From 2997f2a9fd2c276d26febd2a3a2371a7dfefc75c Mon Sep 17 00:00:00 2001 From: Robert Sesek Date: Sat, 10 Oct 2015 11:47:42 -0400 Subject: [PATCH] Add a block-based -sendCommand... variant to ProtocolClient. This starts making ProtocolClient responsible for dispatching debugger messages. --- Source/DebuggerBackEnd.m | 23 ++++++++--------- Source/ProtocolClient.h | 12 ++++++++- Source/ProtocolClient.m | 54 ++++++++++++++++++++++++++++++++++------ 3 files changed, 68 insertions(+), 21 deletions(-) diff --git a/Source/DebuggerBackEnd.m b/Source/DebuggerBackEnd.m index df26dd8..942eeb7 100644 --- a/Source/DebuggerBackEnd.m +++ b/Source/DebuggerBackEnd.m @@ -134,10 +134,10 @@ /** * Tells the debugger to step into the current command. */ -- (void)stepIn -{ - NSNumber* tx = [client_ sendCommandWithFormat:@"step_into"]; - [self recordCallback:@selector(debuggerStep:) forTransaction:tx]; +- (void)stepIn { + [client_ sendCommandWithFormat:@"step_into" handler:^(NSXMLDocument* message) { + [self debuggerStep:message]; + }]; } /** @@ -280,21 +280,20 @@ [client_ connectOnPort:port_]; } -- (void)debuggerEngine:(ProtocolClient*)client receivedMessage:(NSXMLDocument*)message -{ - // Check and see if there's an error. +- (void)protocolClient:(ProtocolClient*)client receivedInitialMessage:(NSXMLDocument*)message { + [self handleInitialResponse:message]; +} + +- (void)protocolClient:(ProtocolClient*)client receivedErrorMessage:(NSXMLDocument*)message { NSArray* error = [[message rootElement] elementsForName:@"error"]; if ([error count] > 0) { NSLog(@"Xdebug error: %@", error); NSString* errorMessage = [[[[error objectAtIndex:0] children] objectAtIndex:0] stringValue]; [self errorEncountered:errorMessage]; } +} - if ([[[message rootElement] name] isEqualToString:@"init"]) { - [self handleInitialResponse:message]; - return; - } - +- (void)debuggerEngine:(ProtocolClient*)client receivedMessage:(NSXMLDocument*)message { [self handleResponse:message]; } diff --git a/Source/ProtocolClient.h b/Source/ProtocolClient.h index 698e90e..3f9e91b 100644 --- a/Source/ProtocolClient.h +++ b/Source/ProtocolClient.h @@ -20,6 +20,8 @@ @protocol ProtocolClientDelegate; +typedef void (^ProtocolClientMessageHandler)(NSXMLDocument*); + // ProtocolClient sends string commands to a DBGP // debugger engine and receives XML packets in response. This class ensures // proper sequencing of the messages. @@ -36,6 +38,13 @@ // safe and schedules the request on the |runLoop_|. - (NSNumber*)sendCommandWithFormat:(NSString*)format, ...; +// Sends a command with the given |format| to the debugger. When a response is +// received, |handler| is invoked. If an error occurs or the connection is +// interrupted, the delegate will be notified. +- (void)sendCommandWithFormat:(NSString*)format + handler:(ProtocolClientMessageHandler)handler, + ...; + // Sends a command to the debugger. The command must have a substring |{txn}| // within it, which will be replaced with the transaction ID. Use this if // |-sendCommandWithFormat:|'s insertion of the transaction ID is incorrect. @@ -57,6 +66,7 @@ @protocol ProtocolClientDelegate - (void)debuggerEngineConnected:(ProtocolClient*)client; - (void)debuggerEngineDisconnected:(ProtocolClient*)client; - +- (void)protocolClient:(ProtocolClient*)client receivedInitialMessage:(NSXMLDocument*)message; +- (void)protocolClient:(ProtocolClient*)client receivedErrorMessage:(NSXMLDocument*)message; - (void)debuggerEngine:(ProtocolClient*)client receivedMessage:(NSXMLDocument*)message; @end diff --git a/Source/ProtocolClient.m b/Source/ProtocolClient.m index a8e1610..aa80cb2 100644 --- a/Source/ProtocolClient.m +++ b/Source/ProtocolClient.m @@ -27,8 +27,11 @@ // state of the debugger. id _delegate; // weak + // A map between transaction ID and handler block for that message. + NSMutableDictionary* _dispatchTable; + // The next transaction ID to assign. - NSInteger _nextID; + int _nextID; // Records the last read and written transaction IDs. These are only used in // creating LogEntry objects. @@ -39,11 +42,13 @@ - (id)initWithDelegate:(id)delegate { if ((self = [super init])) { _delegate = delegate; + _dispatchTable = [[NSMutableDictionary alloc] init]; } return self; } - (void)dealloc { + [_dispatchTable release]; [super dealloc]; } @@ -76,6 +81,22 @@ return callbackKey; } +- (void)sendCommandWithFormat:(NSString*)format + handler:(ProtocolClientMessageHandler)handler, ... { + // Collect varargs and format command. + va_list args; + va_start(args, handler); + NSString* command = [[NSString alloc] initWithFormat:format arguments:args]; + va_end(args); + + int transaction = _nextID++; + NSString* taggedCommand = [NSString stringWithFormat:@"%@ -i %d", [command autorelease], transaction]; + + assert(_messageQueue); + [_dispatchTable setObject:[[handler copy] autorelease] forKey:@(transaction)]; + [_messageQueue sendMessage:taggedCommand]; +} + - (NSNumber*)sendCustomCommandWithFormat:(NSString*)format, ... { // Collect varargs and format command. va_list args; @@ -139,12 +160,12 @@ - (void)messageQueueDidDisconnect:(MessageQueue*)queue { [_messageQueue release]; _messageQueue = nil; + [_dispatchTable removeAllObjects]; [_delegate debuggerEngineDisconnected:self]; } // Callback for when a message has been sent. -- (void)messageQueue:(MessageQueue*)queue didSendMessage:(NSString*)message -{ +- (void)messageQueue:(MessageQueue*)queue didSendMessage:(NSString*)message { NSInteger tag = [self transactionIDFromCommand:message]; _lastWrittenID = tag; @@ -156,15 +177,15 @@ } // Callback with the message content when one has been receieved. -- (void)messageQueue:(MessageQueue*)queue didReceiveMessage:(NSString*)message -{ +- (void)messageQueue:(MessageQueue*)queue didReceiveMessage:(NSString*)message { + // Record this message in the transaction log. LoggingController* logger = [[AppDelegate instance] loggingController]; LogEntry* entry = [LogEntry newReceiveEntry:message]; entry.lastReadTransactionID = _lastReadID; entry.lastWrittenTransactionID = _lastWrittenID; [logger recordEntry:entry]; - // Test if we can convert it into an NSXMLDocument. + // Parse the XML and test for errors. NSError* error = nil; NSXMLDocument* xml = [[NSXMLDocument alloc] initWithXMLString:message options:NSXMLDocumentTidyXML @@ -173,11 +194,28 @@ [self messageQueue:queue error:error]; return; } + int transactionID = [self transactionIDFromResponse:xml]; - _lastReadID = [self transactionIDFromResponse:xml]; + _lastReadID = transactionID; entry.lastReadTransactionID = _lastReadID; - [_delegate debuggerEngine:self receivedMessage:xml]; + if ([[[xml rootElement] elementsForName:@"error"] count] > 0) { + // Handle back-end errors. + [_delegate protocolClient:self receivedErrorMessage:xml]; + } else if ([[[xml rootElement] name] isEqualToString:@"init"]) { + // Handle the initial connection message. + [_delegate protocolClient:self receivedInitialMessage:xml]; + } else { + // Dispatch the handler for the message. + ProtocolClientMessageHandler handler = [_dispatchTable objectForKey:@(transactionID)]; + if (handler) { + handler(xml); + [_dispatchTable removeObjectForKey:@(transactionID)]; + } else { + // TODO(rsesek): Remove this path once the backend rewrite is complete. + [_delegate debuggerEngine:self receivedMessage:xml]; + } + } } @end -- 2.22.5