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 + */