3 * Copyright (c) 2013, Blue Static <http://www.bluestatic.org>
5 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6 * General Public License as published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
10 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public License along with this program; if not,
14 * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
17 #import "ProtocolClient.h"
19 @implementation ProtocolClient
21 - (id)initWithDelegate
:(NSObject
<ProtocolClientDelegate
>*)delegate
{
22 if ((self = [super init
])) {
24 _delegateThread
= [NSThread currentThread
];
25 _lock
= [[NSRecursiveLock alloc
] init
];
36 return [_messageQueue isConnected
];
39 - (void)connectOnPort
:(NSUInteger
)port
{
40 assert(!_messageQueue
);
41 _messageQueue
= [[MessageQueue alloc
] initWithPort
:port delegate
:self];
42 [_messageQueue connect
];
46 [_messageQueue disconnect
];
49 - (NSNumber
*)sendCommandWithFormat
:(NSString
*)format
, ...
{
50 // Collect varargs and format command.
52 va_start(args
, format
);
53 NSString
* command
= [[NSString alloc
] initWithFormat
:format arguments
:args
];
56 NSNumber
* callbackKey
= [NSNumber numberWithInt
:_nextID
++];
57 NSString
* taggedCommand
= [NSString stringWithFormat
:@
"%@ -i %@", [command autorelease
], callbackKey
];
59 assert(_messageQueue
);
60 [_messageQueue sendMessage
:taggedCommand
];
64 - (NSNumber
*)sendCustomCommandWithFormat
:(NSString
*)format
, ...
{
65 // Collect varargs and format command.
67 va_start(args
, format
);
68 NSString
* command
= [[[NSString alloc
] initWithFormat
:format arguments
:args
] autorelease
];
71 NSNumber
* callbackKey
= [NSNumber numberWithInt
:_nextID
++];
72 NSString
* taggedCommand
= [command stringByReplacingOccurrencesOfString
:@
"{txn}"
73 withString
:[callbackKey stringValue
]];
75 [_messageQueue sendMessage
:taggedCommand
];
79 - (NSInteger
)transactionIDFromResponse
:(NSXMLDocument
*)response
{
80 return [[[[response rootElement
] attributeForName
:@
"transaction_id"] stringValue
] intValue
];
83 - (NSInteger
)transactionIDFromCommand
:(NSString
*)command
{
84 NSRange occurrence
= [command rangeOfString
:@
"-i "];
85 if (occurrence.location
== NSNotFound
)
87 NSString
* transaction
= [command substringFromIndex
:occurrence.location
+ occurrence.length
];
88 return [transaction intValue
];
91 // MessageQueueDelegate ////////////////////////////////////////////////////////
93 - (void)messageQueue
:(MessageQueue
*)queue error
:(NSError
*)error
{
94 NSLog(@
"error = %@", error
);
97 - (void)messageQueueDidConnect
:(MessageQueue
*)queue
{
104 [_delegate debuggerEngineConnected
:self];
107 - (void)messageQueueDidDisconnect
:(MessageQueue
*)queue
{
108 [_messageQueue release
];
110 [_delegate debuggerEngineDisconnected
:self];
113 // If the write stream is ready, the delegate controls whether or not the next
114 // pending message should be sent via the result of this method.
115 - (BOOL)shouldSendMessage
{
117 BOOL r
= _lastReadID
>= _lastWrittenID
;
122 // Callback for when a message has been sent.
123 - (void)messageQueue
:(MessageQueue
*)queue didSendMessage
:(NSString
*)message
{
124 NSInteger tag
= [self transactionIDFromCommand
:message
];
126 _lastWrittenID
= tag
;
130 // Callback with the message content when one has been receieved.
131 - (void)messageQueue
:(MessageQueue
*)queue didReceiveMessage
:(NSString
*)message
{
132 // Test if we can convert it into an NSXMLDocument.
133 NSError
* error
= nil;
134 NSXMLDocument
* xml
= [[NSXMLDocument alloc
] initWithXMLString
:message
135 options
:NSXMLDocumentTidyXML
138 [self messageQueue
:queue error
:error
];
142 // Validate the transaction.
143 NSInteger transaction
= [self transactionIDFromResponse
:xml
];
144 if (transaction
< _lastReadID
) {
145 NSLog(@
"Transaction #%d is out of date (lastRead = %d). Dropping packet: %@",
146 transaction
, _lastReadID
, message
);
149 if (transaction
!= _lastWrittenID
) {
150 NSLog(@
"Transaction #%d received out of order. lastRead = %d, lastWritten = %d. Continuing.",
151 transaction
, _lastReadID
, _lastWrittenID
);
154 _lastReadID
= transaction
;
156 [_delegate debuggerEngine
:self receivedMessage
:xml
];