From 6ab0afffd3d3516f088588a7816576ff054f4ca2 Mon Sep 17 00:00:00 2001 From: Robert Sesek Date: Sat, 5 Jan 2008 15:55:52 -0800 Subject: [PATCH] Removing the notification-delegate system that SocketWrapper used because it wasn't necessary because the only action that can block the UI is -[connect] Changes: -[SocketWrapper receive] now returns the data directly, cleaning up the DebuggerConnection class a lot -[SocketWrapper send] returns BOOL depending on the success of the send --- Source/DebuggerConnection.h | 2 - Source/DebuggerConnection.m | 140 ++++++++++++------------------------ Source/SocketWrapper.h | 11 +-- Source/SocketWrapper.m | 96 +++---------------------- 4 files changed, 60 insertions(+), 189 deletions(-) diff --git a/Source/DebuggerConnection.h b/Source/DebuggerConnection.h index 7a20be6..097c6cf 100644 --- a/Source/DebuggerConnection.h +++ b/Source/DebuggerConnection.h @@ -27,8 +27,6 @@ DebuggerWindowController *windowController; SocketWrapper *socket; - - id depthFetchNode; } @property(readonly) SocketWrapper *socket; diff --git a/Source/DebuggerConnection.m b/Source/DebuggerConnection.m index 44ba1e1..6fe2254 100644 --- a/Source/DebuggerConnection.m +++ b/Source/DebuggerConnection.m @@ -20,6 +20,7 @@ @interface DebuggerConnection (Private) - (NSString *)createCommand:(NSString *)cmd; +- (NSXMLDocument *)processData:(NSData *)data; @end @@ -85,43 +86,16 @@ return connected; } -/** - * SocketWrapper delegate method that is called whenever new data is received - */ -- (void)dataReceived:(NSData *)response deliverTo:(SEL)selector -{ - NSXMLDocument *doc = [[NSXMLDocument alloc] initWithData:response options:NSXMLDocumentTidyXML error:nil]; - - // check and see if there's an error - NSArray *error = [[doc rootElement] elementsForName:@"error"]; - if ([error count] > 0) - { - [windowController setError:[[[[error objectAtIndex:0] children] objectAtIndex:0] stringValue]]; - return; - } - - // if the caller of [_socket receive:] specified a deliverTo, just forward the message to them - if (selector != nil) - { - [self performSelector:selector withObject:doc]; - } -} - -/** - * SocketWrapper delegate method that is called after data is sent. This really - * isn't useful for much. - */ -- (void)dataSent:(NSString *)data -{} - /** * Called by SocketWrapper after the connection is successful. This immediately calls - * -[SocketWrapper receive] to clear the way for communication + * -[SocketWrapper receive] to clear the way for communication, though the information + * could be useful server information that we don't use right now. */ -- (void)socketDidAccept +- (void)socketDidAccept:(id)obj { connected = YES; - [socket receive:@selector(handshake:)]; + [socket receive]; + [self refreshStatus]; } /** @@ -133,20 +107,22 @@ } /** - * The initial packet handshake. This allows us to set things like the title of the window - * and glean information about hte server we are debugging + * Tells the debugger to continue running the script */ -- (void)handshake:(NSXMLDocument *)doc +- (void)run { + [socket send:[self createCommand:@"run"]]; [self refreshStatus]; } /** - * Handler used by dataReceived:deliverTo: for anytime the status command is issued. It sets - * the window controller's status text + * Method that runs tells the debugger to give us its status and will update the status text on the window */ -- (void)updateStatus:(NSXMLDocument *)doc +- (void)refreshStatus { + [socket send:[self createCommand:@"status"]]; + + NSXMLDocument *doc = [self processData:[socket receive]]; NSString *status = [[[doc rootElement] attributeForName:@"status"] stringValue]; [windowController setStatus:[status capitalizedString]]; @@ -156,32 +132,13 @@ } } -/** - * Tells the debugger to continue running the script - */ -- (void)run -{ - [socket send:[self createCommand:@"run"]]; - [self refreshStatus]; -} - -/** - * Method that runs tells the debugger to give us its status. This will call _updateStatus - * and will update the status text on the window - */ -- (void)refreshStatus -{ - [socket send:[self createCommand:@"status"]]; - [socket receive:@selector(updateStatus:)]; -} - /** * Tells the debugger to step into the current command. */ - (void)stepIn { [socket send:[self createCommand:@"step_into"]]; - [socket receive:nil]; + [socket receive]; [self refreshStatus]; } @@ -191,7 +148,7 @@ - (void)stepOut { [socket send:[self createCommand:@"step_out"]]; - [socket receive:nil]; + [socket receive]; [self refreshStatus]; } @@ -201,7 +158,7 @@ - (void)stepOver { [socket send:[self createCommand:@"step_over"]]; - [socket receive:nil]; + [socket receive]; [self refreshStatus]; } @@ -211,19 +168,9 @@ */ - (void)updateStackTraceAndRegisters { + // do the stack [socket send:[self createCommand:@"stack_get"]]; - [socket receive:@selector(stackReceived:)]; - - [socket send:[self createCommand:@"context_get"]]; - [socket receive:@selector(registerReceived:)]; -} - -/** - * Called by the dataReceived delivery delegate. This updates the window controller's data - * for the stack trace - */ -- (void)stackReceived:(NSXMLDocument *)doc -{ + NSXMLDocument *doc = [self processData:[socket receive]]; NSArray *children = [[doc rootElement] children]; NSMutableArray *stack = [NSMutableArray array]; NSMutableDictionary *dict = [NSMutableDictionary dictionary]; @@ -238,46 +185,35 @@ dict = [NSMutableDictionary dictionary]; } [windowController setStack:stack]; -} - -/** - * Called when we have a new register to display - */ -- (void)registerReceived:(NSXMLDocument *)doc -{ - [windowController setRegister:doc]; + + // do the registers + [socket send:[self createCommand:@"context_get"]]; + [windowController setRegister:[self processData:[socket receive]]]; } /** * Tells the debugger engine to get a specifc property. This also takes in the NSXMLElement - * that requested it so that the child can be attached in the delivery. + * that requested it so that the child can be attached. */ - (void)getProperty:(NSString *)property forNode:(NSTreeNode *)node { [socket send:[self createCommand:[NSString stringWithFormat:@"property_get -n \"%@\"", property]]]; - depthFetchNode = node; - [socket receive:@selector(propertyReceived:)]; -} - -/** - * Called when a property is received. This then adds the result as children to the passed object - */ -- (void)propertyReceived:(NSXMLDocument *)doc -{ + + NSXMLDocument *doc = [self processData:[socket receive]]; + /* - + */ // we now have to detach all the children so we can insert them into another document NSXMLElement *parent = (NSXMLElement *)[[doc rootElement] childAtIndex:0]; NSArray *children = [parent children]; [parent setChildren:nil]; - [windowController addChildren:children toNode:depthFetchNode]; - depthFetchNode = nil; + [windowController addChildren:children toNode:node]; } /** @@ -288,4 +224,22 @@ return [NSString stringWithFormat:@"%@ -i %@", cmd, session]; } +/** + * Helper function to parse the NSData into an NSXMLDocument + */ +- (NSXMLDocument *)processData:(NSData *)data +{ + NSXMLDocument *doc = [[NSXMLDocument alloc] initWithData:data options:NSXMLDocumentTidyXML error:nil]; + + // check and see if there's an error + NSArray *error = [[doc rootElement] elementsForName:@"error"]; + if ([error count] > 0) + { + [windowController setError:[[[[error objectAtIndex:0] children] objectAtIndex:0] stringValue]]; + return nil; + } + + return doc; +} + @end diff --git a/Source/SocketWrapper.h b/Source/SocketWrapper.h index 4a21863..f86b4c5 100644 --- a/Source/SocketWrapper.h +++ b/Source/SocketWrapper.h @@ -35,8 +35,8 @@ - (void)connect; - (void)close; -- (void)receive:(SEL)selector; -- (void)send:(NSString *)data; +- (NSData *)receive; +- (BOOL)send:(NSString *)data; - (NSString *)remoteHost; @@ -48,11 +48,6 @@ - (void)errorEncountered:(NSString *)error; // connection components -- (void)socketDidBind; -- (void)socketDidAccept; - -// data handlers -- (void)dataReceived:(NSData *)response deliverTo:(SEL)selector; -- (void)dataSent:(NSString *)sent; +- (void)socketDidAccept:(id)obj; @end diff --git a/Source/SocketWrapper.m b/Source/SocketWrapper.m index 070045e..05c5cac 100644 --- a/Source/SocketWrapper.m +++ b/Source/SocketWrapper.m @@ -21,20 +21,10 @@ #include #include -NSString *sockNotificationDebuggerConnection = @"DebuggerConnection"; -NSString *sockNotificationReceiver = @"SEL-del-SocketWrapper_dataReceived"; -NSString *NsockDidAccept = @"SocketWrapper_DidAccept"; -NSString *NsockDataReceived = @"SocketWrapper_DataReceived"; -NSString *NsockDataSent = @"SocketWrapper_DataSent"; - @interface SocketWrapper (Private) - (void)error:(NSString *)msg; -- (void)connect:(id)obj; -- (void)postNotification:(NSString *)name withObject:(id)obj; -- (void)postNotification:(NSString *)name withObject:(id)obj withDict:(NSMutableDictionary *)dict; - @end @implementation SocketWrapper @@ -48,11 +38,6 @@ NSString *NsockDataSent = @"SocketWrapper_DataSent"; { connection = cnx; port = [connection port]; - - // the delegate notifications work funky because of threads. we register ourselves as the - // observer and then pass up the messages that are actually from this object (as we can't only observe self due to threads) - // to our delegate, and not to all delegates - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sendMessageToDelegate:) name:nil object:nil]; } return self; } @@ -62,7 +47,6 @@ NSString *NsockDataSent = @"SocketWrapper_DataSent"; */ - (void)close { - [[NSNotificationCenter defaultCenter] removeObserver:self]; close(sock); } @@ -100,36 +84,6 @@ NSString *NsockDataSent = @"SocketWrapper_DataSent"; return [NSString stringWithUTF8String:name]; } -/** - * This is the notification listener for all types of notifications. If the notifications are from a SocketWrapper - * class, it checks that the value of _delegate in the NSNotification's userInfo matches that of this object. If it does, - * then the notification was sent from the same object in another thread and it passes the message along to the object's - * delegate. Complicated enough? - */ -- (void)sendMessageToDelegate:(NSNotification *)notif -{ - // this isn't us, so there's no point in continuing - if ([[notif userInfo] objectForKey:sockNotificationDebuggerConnection] != delegate) - { - return; - } - - NSString *name = [notif name]; - - if (name == NsockDidAccept) - { - [delegate socketDidAccept]; - } - else if (name == NsockDataReceived) - { - [delegate dataReceived:[notif object] deliverTo:NSSelectorFromString([[notif userInfo] objectForKey:sockNotificationReceiver])]; - } - else if (name == NsockDataSent) - { - [delegate dataSent:[notif object]]; - } -} - /** * Connects to a socket on the port specified during init. This will dispatch another thread to do the * actual waiting. Delegate notifications are posted along the way to let the client know what is going on. @@ -193,18 +147,16 @@ NSString *NsockDataSent = @"SocketWrapper_DataSent"; // we're done listening now that we have a connection close(socketOpen); - [self postNotification:NsockDidAccept withObject:nil]; + [connection performSelectorOnMainThread:@selector(socketDidAccept:) withObject:nil waitUntilDone:NO]; } /** * Reads from the socket and returns the result as a NSString (because it's always going to be XML). Be aware * that the underlying socket recv() call will *wait* for the server to send a message, so be sure that this * is used either in a threaded environment so the interface does not hang, or when you *know* the server - * will return something (which we almost always do). - * - * The paramater is an optional selector which the delegate method dataReceived:deliverTo: should forward to + * will return something (which we almost always do). Returns the data that was received from the socket. */ -- (void)receive:(SEL)selector +- (NSData *)receive { // create a buffer char buffer[1024]; @@ -248,64 +200,36 @@ NSString *NsockDataSent = @"SocketWrapper_DataSent"; if (latest < 1) { [self error:@"Socket closed or could not be read"]; - return; + return nil; } [data appendBytes:buffer length:latest]; recvd += latest; } } - //NSLog(@"data = %@", [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]); - - if (selector != nil) - { - [self postNotification:NsockDataReceived - withObject:data - withDict:[NSMutableDictionary dictionaryWithObject:NSStringFromSelector(selector) forKey:sockNotificationReceiver]]; - } - else - { - [self postNotification:NsockDataReceived withObject:data]; - } + return data; } /** - * Sends a given NSString over the socket + * Sends a given NSString over the socket. Returns YES on complete submission. */ -- (void)send:(NSString *)data +- (BOOL)send:(NSString *)data { data = [NSString stringWithFormat:@"%@\0", data]; int sent = send(sock, [data UTF8String], [data length], 0); if (sent < 0) { [self error:@"Failed to write data to socket"]; - return; + return NO; } if (sent < [data length]) { // TODO - do we really need to worry about partial sends with the lenght of our commands? NSLog(@"FAIL: only partial packet was sent; sent %d bytes", sent); + return NO; } - [self postNotification:NsockDataSent withObject:[data substringToIndex:sent]]; -} - -/** - * Helper method to simply post a notification to the default notification center with a given name and object - */ -- (void)postNotification:(NSString *)name withObject:(id)obj -{ - [self postNotification:name withObject:obj withDict:[NSMutableDictionary dictionary]]; -} - -/** - * Another helper method to aid in the posting of notifications. This one should be used if you have additional - * things for the userInfo. This automatically adds the sockNotificationDebuggerConnection key. - */ -- (void)postNotification:(NSString *)name withObject:(id)obj withDict:(NSMutableDictionary *)dict -{ - [dict setValue:delegate forKey:sockNotificationDebuggerConnection]; - [[NSNotificationCenter defaultCenter] postNotificationName:name object:obj userInfo:dict]; + return YES; } /** -- 2.22.5