BLIP/BLIPRequest.m
changeset 0 9d67172bb323
child 1 8267d5c429c4
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/BLIP/BLIPRequest.m	Fri May 23 17:37:36 2008 -0700
     1.3 @@ -0,0 +1,268 @@
     1.4 +//
     1.5 +//  BLIPRequest.m
     1.6 +//  MYNetwork
     1.7 +//
     1.8 +//  Created by Jens Alfke on 5/22/08.
     1.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
    1.10 +//
    1.11 +
    1.12 +#import "BLIPRequest.h"
    1.13 +#import "BLIP_Internal.h"
    1.14 +#import "BLIPWriter.h"
    1.15 +#import "BLIPReader.h"
    1.16 +#import "Target.h"
    1.17 +#import "ExceptionUtils.h"
    1.18 +
    1.19 +
    1.20 +@implementation BLIPRequest
    1.21 +
    1.22 +
    1.23 +- (id) _initWithConnection: (BLIPConnection*)connection
    1.24 +                      body: (NSData*)body 
    1.25 +                properties: (NSDictionary*)properties
    1.26 +{
    1.27 +    self = [self _initWithConnection: connection
    1.28 +                              isMine: YES
    1.29 +                               flags: kBLIP_MSG
    1.30 +                              number: 0
    1.31 +                                body: body];
    1.32 +    if( self ) {
    1.33 +        _isMutable = YES;
    1.34 +        if( body )
    1.35 +            self.body = body;
    1.36 +        if( properties )
    1.37 +            [self.mutableProperties setAllProperties: properties];
    1.38 +    }
    1.39 +    return self;
    1.40 +}
    1.41 +
    1.42 ++ (BLIPRequest*) requestWithBody: (NSData*)body
    1.43 +{
    1.44 +    return [[[self alloc] _initWithConnection: nil body: body properties: nil] autorelease];
    1.45 +}
    1.46 +
    1.47 ++ (BLIPRequest*) requestWithBody: (NSData*)body
    1.48 +                      properties: (NSDictionary*)properties
    1.49 +{
    1.50 +    return [[[self alloc] _initWithConnection: nil body: body properties: properties] autorelease];
    1.51 +}
    1.52 +
    1.53 +
    1.54 +- (void) dealloc
    1.55 +{
    1.56 +    [_response release];
    1.57 +    [super dealloc];
    1.58 +}
    1.59 +
    1.60 +
    1.61 +- (BOOL) noReply                            {return (_flags & kBLIP_NoReply) != 0;}
    1.62 +- (void) setNoReply: (BOOL)noReply          {[self _setFlag: kBLIP_NoReply value: noReply];}
    1.63 +- (BLIPConnection*) connection              {return _connection;}
    1.64 +
    1.65 +- (void) setConnection: (BLIPConnection*)conn
    1.66 +{
    1.67 +    Assert(_isMine && !_sent,@"Connection can only be set before sending");
    1.68 +    setObj(&_connection,conn);
    1.69 +}
    1.70 +
    1.71 +
    1.72 +- (BLIPResponse*) send
    1.73 +{
    1.74 +    Assert(_connection,@"%@ has no connection to send over",self);
    1.75 +    Assert(!_sent,@"%@ was already sent",self);
    1.76 +    [self _encode];
    1.77 +    BLIPResponse *response = self.response;
    1.78 +    if( [(BLIPWriter*)_connection.writer sendRequest: self response: response] )
    1.79 +        self.sent = YES;
    1.80 +    else
    1.81 +        response = nil;
    1.82 +    return response;
    1.83 +}
    1.84 +
    1.85 +
    1.86 +- (BLIPResponse*) response
    1.87 +{
    1.88 +    if( ! _response && ! self.noReply )
    1.89 +        _response = [[BLIPResponse alloc] _initWithRequest: self];
    1.90 +    return _response;
    1.91 +}
    1.92 +
    1.93 +- (void) deferResponse
    1.94 +{
    1.95 +    // This will allocate _response, causing -repliedTo to become YES, so BLIPConnection won't
    1.96 +    // send an automatic empty response after the current request handler returns.
    1.97 +    LogTo(BLIP,@"Deferring response to %@",self);
    1.98 +    [self response];
    1.99 +}
   1.100 +
   1.101 +- (BOOL) repliedTo
   1.102 +{
   1.103 +    return _response != nil;
   1.104 +}
   1.105 +
   1.106 +- (void) respondWithData: (NSData*)data                   {self.response.body = data; [self.response send];}
   1.107 +- (void) respondWithString: (NSString*)string             {[self respondWithData: [string dataUsingEncoding: NSUTF8StringEncoding]];}
   1.108 +- (void) respondWithError: (NSError*)error                {self.response.error = error; [self.response send];}
   1.109 +
   1.110 +- (void) respondWithErrorCode: (int)errorCode message: (NSString*)errorMessage
   1.111 +{
   1.112 +    [self respondWithError: BLIPMakeError(errorCode, @"%@",errorMessage)];
   1.113 +}
   1.114 +
   1.115 +- (void) respondWithException: (NSException*)exception
   1.116 +{
   1.117 +    [self respondWithError: BLIPMakeError(kBLIPError_HandlerFailed, @"%@", exception.reason)];
   1.118 +}
   1.119 +
   1.120 +
   1.121 +@end
   1.122 +
   1.123 +
   1.124 +
   1.125 +
   1.126 +#pragma mark -
   1.127 +@implementation BLIPResponse
   1.128 +
   1.129 +- (id) _initWithRequest: (BLIPRequest*)request
   1.130 +{
   1.131 +    Assert(request);
   1.132 +    self = [super _initWithConnection: request.connection
   1.133 +                               isMine: !request.isMine
   1.134 +                                flags: kBLIP_RPY | kBLIP_MoreComing
   1.135 +                               number: request.number
   1.136 +                                 body: nil];
   1.137 +    if (self != nil) {
   1.138 +        if( _isMine ) {
   1.139 +            _isMutable = YES;
   1.140 +            if( request.urgent )
   1.141 +                _flags |= kBLIP_Urgent;
   1.142 +        } else {
   1.143 +            _flags |= kBLIP_MoreComing;
   1.144 +        }
   1.145 +    }
   1.146 +    return self;
   1.147 +}
   1.148 +
   1.149 +- (void) dealloc
   1.150 +{
   1.151 +    [_error release];
   1.152 +    [_onComplete release];
   1.153 +    [super dealloc];
   1.154 +}
   1.155 +
   1.156 +
   1.157 +- (NSError*) error
   1.158 +{
   1.159 +    if( ! (_flags & kBLIP_ERR) )
   1.160 +        return nil;
   1.161 +    
   1.162 +    NSMutableDictionary *userInfo = [[self.properties allProperties] mutableCopy];
   1.163 +    NSString *domain = [userInfo objectForKey: @"Error-Domain"];
   1.164 +    int code = [[userInfo objectForKey: @"Error-Code"] intValue];
   1.165 +    if( domain==nil || code==0 ) {
   1.166 +        domain = BLIPErrorDomain;
   1.167 +        if( code==0 )
   1.168 +            code = kBLIPError_Unspecified;
   1.169 +    }
   1.170 +    [userInfo removeObjectForKey: @"Error-Domain"];
   1.171 +    [userInfo removeObjectForKey: @"Error-Code"];
   1.172 +    return [NSError errorWithDomain: domain code: code userInfo: userInfo];
   1.173 +}
   1.174 +
   1.175 +- (void) _setError: (NSError*)error
   1.176 +{
   1.177 +    _flags &= ~kBLIP_TypeMask;
   1.178 +    if( error ) {
   1.179 +        // Setting this stuff is a PITA because this object might be technically immutable,
   1.180 +        // in which case the standard setters would barf if I called them.
   1.181 +        _flags |= kBLIP_ERR;
   1.182 +        setObj(&_body,nil);
   1.183 +        setObj(&_mutableBody,nil);
   1.184 +        
   1.185 +        BLIPMutableProperties *errorProps = [self.properties mutableCopy];
   1.186 +        NSDictionary *userInfo = error.userInfo;
   1.187 +        for( NSString *key in userInfo ) {
   1.188 +            id value = $castIf(NSString,[userInfo objectForKey: key]);
   1.189 +            if( value )
   1.190 +                [errorProps setValue: value ofProperty: key];
   1.191 +        }
   1.192 +        [errorProps setValue: error.domain ofProperty: @"Error-Domain"];
   1.193 +        [errorProps setValue: $sprintf(@"%i",error.code) ofProperty: @"Error-Code"];
   1.194 +        setObj(&_properties,errorProps);
   1.195 +        [errorProps release];
   1.196 +        
   1.197 +    } else {
   1.198 +        _flags |= kBLIP_RPY;
   1.199 +        [self.mutableProperties setAllProperties: nil];
   1.200 +    }
   1.201 +}
   1.202 +
   1.203 +- (void) setError: (NSError*)error
   1.204 +{
   1.205 +    Assert(_isMine && _isMutable);
   1.206 +    [self _setError: error];
   1.207 +}
   1.208 +
   1.209 +
   1.210 +- (BOOL) send
   1.211 +{
   1.212 +    Assert(_connection,@"%@ has no connection to send over",self);
   1.213 +    Assert(!_sent,@"%@ was already sent",self);
   1.214 +    [self _encode];
   1.215 +    return (self.sent = [(BLIPWriter*)_connection.writer sendMessage: self]);
   1.216 +}
   1.217 +
   1.218 +
   1.219 +@synthesize onComplete=_onComplete;
   1.220 +
   1.221 +
   1.222 +- (void) setComplete: (BOOL)complete
   1.223 +{
   1.224 +    [super setComplete: complete];
   1.225 +    if( complete && _onComplete ) {
   1.226 +        @try{
   1.227 +            [_onComplete invokeWithSender: self];
   1.228 +        }catchAndReport(@"BLIPResponse onComplete target");
   1.229 +    }
   1.230 +}
   1.231 +
   1.232 +
   1.233 +- (void) _connectionClosed
   1.234 +{
   1.235 +    [super _connectionClosed];
   1.236 +    if( !_isMine ) {
   1.237 +        // Change incoming response to an error:
   1.238 +        _isMutable = YES;
   1.239 +        [_properties autorelease];
   1.240 +        _properties = [_properties mutableCopy];
   1.241 +        [self _setError: BLIPMakeError(kBLIPError_Disconnected,
   1.242 +                                         @"Connection closed before response was received")];
   1.243 +        _isMutable = NO;
   1.244 +    }
   1.245 +}
   1.246 +
   1.247 +
   1.248 +@end
   1.249 +
   1.250 +
   1.251 +/*
   1.252 + Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   1.253 + 
   1.254 + Redistribution and use in source and binary forms, with or without modification, are permitted
   1.255 + provided that the following conditions are met:
   1.256 + 
   1.257 + * Redistributions of source code must retain the above copyright notice, this list of conditions
   1.258 + and the following disclaimer.
   1.259 + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   1.260 + and the following disclaimer in the documentation and/or other materials provided with the
   1.261 + distribution.
   1.262 + 
   1.263 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   1.264 + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   1.265 + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   1.266 + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   1.267 + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   1.268 + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   1.269 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   1.270 + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   1.271 + */