OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library service_common; | 5 library service_common; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:convert'; | 8 import 'dart:convert'; |
9 import 'dart:typed_data'; | 9 import 'dart:typed_data'; |
10 | 10 |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
81 abstract class CommonWebSocketVM extends VM { | 81 abstract class CommonWebSocketVM extends VM { |
82 final Completer _connected = new Completer(); | 82 final Completer _connected = new Completer(); |
83 final Completer _disconnected = new Completer<String>(); | 83 final Completer _disconnected = new Completer<String>(); |
84 final WebSocketVMTarget target; | 84 final WebSocketVMTarget target; |
85 final Map<String, _WebSocketRequest> _delayedRequests = | 85 final Map<String, _WebSocketRequest> _delayedRequests = |
86 new Map<String, _WebSocketRequest>(); | 86 new Map<String, _WebSocketRequest>(); |
87 final Map<String, _WebSocketRequest> _pendingRequests = | 87 final Map<String, _WebSocketRequest> _pendingRequests = |
88 new Map<String, _WebSocketRequest>(); | 88 new Map<String, _WebSocketRequest>(); |
89 int _requestSerial = 0; | 89 int _requestSerial = 0; |
90 bool _hasInitiatedConnect = false; | 90 bool _hasInitiatedConnect = false; |
91 bool _hasFinishedConnect = false; | |
92 Utf8Decoder _utf8Decoder = const Utf8Decoder(); | 91 Utf8Decoder _utf8Decoder = const Utf8Decoder(); |
93 | 92 |
94 String get displayName => '${name}@${target.name}'; | 93 String get displayName => '${name}@${target.name}'; |
95 | 94 |
96 CommonWebSocket _webSocket; | 95 CommonWebSocket _webSocket; |
97 | 96 |
98 CommonWebSocketVM(this.target, this._webSocket) { | 97 CommonWebSocketVM(this.target, this._webSocket) { |
99 assert(target != null); | 98 assert(target != null); |
100 } | 99 } |
101 | 100 |
102 void _notifyConnect() { | 101 void _notifyConnect() { |
103 _hasFinishedConnect = true; | |
104 if (!_connected.isCompleted) { | 102 if (!_connected.isCompleted) { |
105 Logger.root.info('WebSocketVM connection opened: ${target.networkAddress}'
); | 103 Logger.root.info('WebSocketVM connection opened: ${target.networkAddress}'
); |
106 _connected.complete(this); | 104 _connected.complete(this); |
107 } | 105 } |
108 } | 106 } |
109 Future get onConnect => _connected.future; | 107 Future get onConnect => _connected.future; |
| 108 bool get wasOrIsConnected => _connected.isCompleted; |
| 109 bool get isConnected => wasOrIsConnected && !isDisconnected; |
110 void _notifyDisconnect(String reason) { | 110 void _notifyDisconnect(String reason) { |
111 if (!_hasFinishedConnect) { | |
112 return; | |
113 } | |
114 if (!_disconnected.isCompleted) { | 111 if (!_disconnected.isCompleted) { |
115 Logger.root.info('WebSocketVM connection error: ${target.networkAddress}')
; | 112 Logger.root.info('WebSocketVM connection error: ${target.networkAddress}')
; |
116 _disconnected.complete(reason); | 113 _disconnected.complete(reason); |
117 } | 114 } |
118 } | 115 } |
119 Future get onDisconnect => _disconnected.future; | 116 Future get onDisconnect => _disconnected.future; |
120 bool get isDisconnected => _disconnected.isCompleted; | 117 bool get isDisconnected => _disconnected.isCompleted; |
121 | 118 |
122 void disconnect({String reason : 'WebSocket closed'}) { | 119 void disconnect({String reason : 'WebSocket closed'}) { |
123 if (_hasInitiatedConnect) { | 120 if (_hasInitiatedConnect) { |
124 _webSocket.close(); | 121 if (_webSocket != null) { |
| 122 _webSocket.close(); |
| 123 } |
125 } | 124 } |
126 // We don't need to cancel requests and notify here. These | 125 // We don't need to cancel requests and notify here. These |
127 // functions will be called again when the onClose callback | 126 // functions will be called again when the onClose callback |
128 // fires. However, we may have a better 'reason' string now, so | 127 // fires. However, we may have a better 'reason' string now, so |
129 // let's take care of business. | 128 // let's take care of business. |
130 _cancelAllRequests(reason); | 129 _cancelAllRequests(reason); |
131 _notifyDisconnect(reason); | 130 _notifyDisconnect(reason); |
132 } | 131 } |
133 | 132 |
134 Future<Map> invokeRpcRaw(String method, Map params) { | 133 Future<Map> invokeRpcRaw(String method, Map params) { |
135 if (!_hasInitiatedConnect) { | 134 if (!_hasInitiatedConnect) { |
136 _hasInitiatedConnect = true; | 135 _hasInitiatedConnect = true; |
137 _webSocket.connect( | 136 try { |
138 target.networkAddress, _onOpen, _onMessage, _onError, _onClose); | 137 _webSocket.connect( |
| 138 target.networkAddress, _onOpen, _onMessage, _onError, _onClose); |
| 139 } catch (_) { |
| 140 _webSocket = null; |
| 141 var exception = new NetworkRpcException('WebSocket closed'); |
| 142 return new Future.error(exception); |
| 143 } |
139 } | 144 } |
140 if (_disconnected.isCompleted) { | 145 if (_disconnected.isCompleted) { |
141 // This connection was closed already. | 146 // This connection was closed already. |
142 var exception = new NetworkRpcException('WebSocket closed'); | 147 var exception = new NetworkRpcException('WebSocket closed'); |
143 return new Future.error(exception); | 148 return new Future.error(exception); |
144 } | 149 } |
145 String serial = (_requestSerial++).toString(); | 150 String serial = (_requestSerial++).toString(); |
146 var request = new _WebSocketRequest(method, params); | 151 var request = new _WebSocketRequest(method, params); |
147 if (_webSocket.isOpen) { | 152 if ((_webSocket != null) && _webSocket.isOpen) { |
148 // Already connected, send request immediately. | 153 // Already connected, send request immediately. |
149 _sendRequest(serial, request); | 154 _sendRequest(serial, request); |
150 } else { | 155 } else { |
151 // Not connected yet, add to delayed requests. | 156 // Not connected yet, add to delayed requests. |
152 _delayedRequests[serial] = request; | 157 _delayedRequests[serial] = request; |
153 } | 158 } |
154 return request.completer.future; | 159 return request.completer.future; |
155 } | 160 } |
156 | 161 |
157 void _onClose() { | 162 void _onClose() { |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
258 void _onMessage(dynamic data) { | 263 void _onMessage(dynamic data) { |
259 if (data is! String) { | 264 if (data is! String) { |
260 _onBinaryMessage(data); | 265 _onBinaryMessage(data); |
261 } else { | 266 } else { |
262 _onStringMessage(data); | 267 _onStringMessage(data); |
263 } | 268 } |
264 } | 269 } |
265 | 270 |
266 void _cancelRequests(Map<String,_WebSocketRequest> requests, | 271 void _cancelRequests(Map<String,_WebSocketRequest> requests, |
267 String message) { | 272 String message) { |
268 requests.forEach((_, _WebSocketRequest request) { | 273 requests.forEach((String serial, _WebSocketRequest request) { |
269 var exception = new NetworkRpcException(message); | 274 var exception = new NetworkRpcException(message + |
| 275 '(id: $serial method: ${request.method} params: ${request.params})'); |
270 request.completer.completeError(exception); | 276 request.completer.completeError(exception); |
271 }); | 277 }); |
272 requests.clear(); | 278 requests.clear(); |
273 } | 279 } |
274 | 280 |
275 /// Cancel all pending and delayed requests by completing them with an error. | 281 /// Cancel all pending and delayed requests by completing them with an error. |
276 void _cancelAllRequests(String reason) { | 282 void _cancelAllRequests(String reason) { |
277 String message = 'Canceling request: $reason'; | 283 String message = 'Canceling request: $reason'; |
278 if (_pendingRequests.length > 0) { | 284 if (_pendingRequests.length > 0) { |
279 Logger.root.info('Canceling all pending requests.'); | 285 Logger.root.info('Canceling all pending requests.'); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
322 } | 328 } |
323 if (request.method != 'getTagProfile' && | 329 if (request.method != 'getTagProfile' && |
324 request.method != 'getIsolateMetric' && | 330 request.method != 'getIsolateMetric' && |
325 request.method != 'getVMMetric') { | 331 request.method != 'getVMMetric') { |
326 Logger.root.info( | 332 Logger.root.info( |
327 'GET [${serial}] ${request.method}(${request.params}) from ${target.ne
tworkAddress}'); | 333 'GET [${serial}] ${request.method}(${request.params}) from ${target.ne
tworkAddress}'); |
328 } | 334 } |
329 // Send message. | 335 // Send message. |
330 _webSocket.send(message); | 336 _webSocket.send(message); |
331 } | 337 } |
| 338 |
| 339 String toString() => displayName; |
332 } | 340 } |
OLD | NEW |