More work on Bonjour classes. They now support registering services.
5 // Created by Jens Alfke on 5/22/08.
6 // Copyright 2008 Jens Alfke. All rights reserved.
9 #import "BLIPRequest.h"
10 #import "BLIP_Internal.h"
11 #import "BLIPWriter.h"
12 #import "BLIPReader.h"
17 #import "ExceptionUtils.h"
20 @implementation BLIPRequest
23 - (id) _initWithConnection: (BLIPConnection*)connection
25 properties: (NSDictionary*)properties
27 self = [self _initWithConnection: connection
37 [self.mutableProperties setAllProperties: properties];
42 + (BLIPRequest*) requestWithBody: (NSData*)body
44 return [[[self alloc] _initWithConnection: nil body: body properties: nil] autorelease];
47 + (BLIPRequest*) requestWithBody: (NSData*)body
48 properties: (NSDictionary*)properties
50 return [[[self alloc] _initWithConnection: nil body: body properties: properties] autorelease];
61 - (BOOL) noReply {return (_flags & kBLIP_NoReply) != 0;}
62 - (void) setNoReply: (BOOL)noReply {[self _setFlag: kBLIP_NoReply value: noReply];}
63 - (BLIPConnection*) connection {return _connection;}
65 - (void) setConnection: (BLIPConnection*)conn
67 Assert(_isMine && !_sent,@"Connection can only be set before sending");
68 setObj(&_connection,conn);
72 - (BLIPResponse*) send
74 Assert(_connection,@"%@ has no connection to send over",self);
75 Assert(!_sent,@"%@ was already sent",self);
77 BLIPResponse *response = self.response;
78 if( [(BLIPWriter*)_connection.writer sendRequest: self response: response] )
86 - (BLIPResponse*) response
88 if( ! _response && ! self.noReply )
89 _response = [[BLIPResponse alloc] _initWithRequest: self];
93 - (void) deferResponse
95 // This will allocate _response, causing -repliedTo to become YES, so BLIPConnection won't
96 // send an automatic empty response after the current request handler returns.
97 LogTo(BLIP,@"Deferring response to %@",self);
103 return _response != nil;
106 - (void) respondWithData: (NSData*)data contentType: (NSString*)contentType
108 BLIPResponse *response = self.response;
109 response.body = data;
110 response.contentType = contentType;
114 - (void) respondWithString: (NSString*)string
116 [self respondWithData: [string dataUsingEncoding: NSUTF8StringEncoding]
117 contentType: @"text/plain; charset=UTF-8"];
120 - (void) respondWithError: (NSError*)error
122 self.response.error = error;
123 [self.response send];
126 - (void) respondWithErrorCode: (int)errorCode message: (NSString*)errorMessage
128 [self respondWithError: BLIPMakeError(errorCode, @"%@",errorMessage)];
131 - (void) respondWithException: (NSException*)exception
133 [self respondWithError: BLIPMakeError(kBLIPError_HandlerFailed, @"%@", exception.reason)];
143 @implementation BLIPResponse
145 - (id) _initWithRequest: (BLIPRequest*)request
148 self = [super _initWithConnection: request.connection
149 isMine: !request.isMine
150 flags: kBLIP_RPY | kBLIP_MoreComing
151 number: request.number
157 _flags |= kBLIP_Urgent;
159 _flags |= kBLIP_MoreComing;
168 [_onComplete release];
175 if( ! (_flags & kBLIP_ERR) )
178 NSMutableDictionary *userInfo = [[[self.properties allProperties] mutableCopy] autorelease];
179 NSString *domain = [userInfo objectForKey: @"Error-Domain"];
180 int code = [[userInfo objectForKey: @"Error-Code"] intValue];
181 if( domain==nil || code==0 ) {
182 domain = BLIPErrorDomain;
184 code = kBLIPError_Unspecified;
186 [userInfo removeObjectForKey: @"Error-Domain"];
187 [userInfo removeObjectForKey: @"Error-Code"];
188 return [NSError errorWithDomain: domain code: code userInfo: userInfo];
191 - (void) _setError: (NSError*)error
193 _flags &= ~kBLIP_TypeMask;
195 // Setting this stuff is a PITA because this object might be technically immutable,
196 // in which case the standard setters would barf if I called them.
199 setObj(&_mutableBody,nil);
201 BLIPMutableProperties *errorProps = [self.properties mutableCopy];
203 errorProps = [[BLIPMutableProperties alloc] init];
204 NSDictionary *userInfo = error.userInfo;
205 for( NSString *key in userInfo ) {
206 id value = $castIf(NSString,[userInfo objectForKey: key]);
208 [errorProps setValue: value ofProperty: key];
210 [errorProps setValue: error.domain ofProperty: @"Error-Domain"];
211 [errorProps setValue: $sprintf(@"%i",error.code) ofProperty: @"Error-Code"];
212 setObj(&_properties,errorProps);
213 [errorProps release];
217 [self.mutableProperties setAllProperties: nil];
221 - (void) setError: (NSError*)error
223 Assert(_isMine && _isMutable);
224 [self _setError: error];
230 Assert(_connection,@"%@ has no connection to send over",self);
231 Assert(!_sent,@"%@ was already sent",self);
232 BLIPWriter *writer = (BLIPWriter*)_connection.writer;
233 Assert(writer,@"%@'s connection has no writer (already closed?)",self);
235 BOOL sent = self.sent = [writer sendMessage: self];
241 @synthesize onComplete=_onComplete;
244 - (void) setComplete: (BOOL)complete
246 [super setComplete: complete];
247 if( complete && _onComplete ) {
249 [_onComplete invokeWithSender: self];
250 }catchAndReport(@"BLIPResponse onComplete target");
255 - (void) _connectionClosed
257 [super _connectionClosed];
258 if( !_isMine && !_complete ) {
259 // Change incoming response to an error:
261 [_properties autorelease];
262 _properties = [_properties mutableCopy];
263 [self _setError: BLIPMakeError(kBLIPError_Disconnected,
264 @"Connection closed before response was received")];
266 self.complete = YES; // Calls onComplete target
275 Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
277 Redistribution and use in source and binary forms, with or without modification, are permitted
278 provided that the following conditions are met:
280 * Redistributions of source code must retain the above copyright notice, this list of conditions
281 and the following disclaimer.
282 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
283 and the following disclaimer in the documentation and/or other materials provided with the
286 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
287 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
288 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
289 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
290 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
291 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
292 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
293 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.