Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(89)

Side by Side Diff: runtime/bin/vmservice/client/lib/service_common.dart

Issue 428613002: Enable using the service library from dart:io applications. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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_html; 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:html';
10 9
11 import 'package:logging/logging.dart'; 10 import 'package:logging/logging.dart';
12 import 'package:observatory/service.dart'; 11 import 'package:observatory/service.dart';
13 12
14 // Export the service library. 13 // Export the service library.
15 export 'package:observatory/service.dart'; 14 export 'package:observatory/service.dart';
16 15
17 /// Description of a VM target. 16 /// Description of a VM target.
18 class WebSocketVMTarget { 17 class WebSocketVMTarget {
19 // Last time this VM has been connected to. 18 // Last time this VM has been connected to.
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 } 52 }
54 } 53 }
55 54
56 class _WebSocketRequest { 55 class _WebSocketRequest {
57 final String id; 56 final String id;
58 final Completer<String> completer; 57 final Completer<String> completer;
59 _WebSocketRequest(this.id) 58 _WebSocketRequest(this.id)
60 : completer = new Completer<String>(); 59 : completer = new Completer<String>();
61 } 60 }
62 61
63 /// The [WebSocketVM] communicates with a Dart VM over WebSocket. The Dart VM 62 /// Minimal common interface for 'WebSocket' in [dart:io] and [dart:html].
64 /// can be embedded in Chromium or standalone. In the case of Chromium, we 63 abstract class CommonWebSocket {
65 /// make the service requests via the Chrome Remote Debugging Protocol. 64 void connect(String address,
66 class WebSocketVM extends VM { 65 void onOpen(),
66 void onMessage(dynamic data),
67 void onError(),
68 void onClose());
69 bool get isOpen;
70 void send(dynamic data);
71 void close();
72 }
73
74 /// A [CommonWebSocketVM] communicates with a Dart VM over a CommonWebSocket.
75 /// The Dart VM can be embedded in Chromium or standalone. In the case of
76 /// Chromium, we make the service requests via the Chrome Remote Debugging
77 /// Protocol.
78 abstract class CommonWebSocketVM extends VM {
67 final Completer _connected = new Completer(); 79 final Completer _connected = new Completer();
68 final Completer _disconnected = new Completer(); 80 final Completer _disconnected = new Completer();
69 final WebSocketVMTarget target; 81 final WebSocketVMTarget target;
70 final Map<String, _WebSocketRequest> _delayedRequests = 82 final Map<String, _WebSocketRequest> _delayedRequests =
71 new Map<String, _WebSocketRequest>(); 83 new Map<String, _WebSocketRequest>();
72 final Map<String, _WebSocketRequest> _pendingRequests = 84 final Map<String, _WebSocketRequest> _pendingRequests =
73 new Map<String, _WebSocketRequest>(); 85 new Map<String, _WebSocketRequest>();
74 int _requestSerial = 0; 86 int _requestSerial = 0;
75 WebSocket _webSocket; 87 bool _hasInitiatedConnect = false;
76 88
77 WebSocketVM(this.target) { 89 CommonWebSocket _webSocket;
90
91 CommonWebSocketVM(this.target, this._webSocket) {
78 assert(target != null); 92 assert(target != null);
79 } 93 }
80 94
81 void _notifyConnect() { 95 void _notifyConnect() {
82 if (!_connected.isCompleted) { 96 if (!_connected.isCompleted) {
83 Logger.root.info('WebSocketVM connection opened: ${target.networkAddress}' ); 97 Logger.root.info('WebSocketVM connection opened: ${target.networkAddress}' );
84 _connected.complete(this); 98 _connected.complete(this);
85 } 99 }
86 } 100 }
87 Future get onConnect => _connected.future; 101 Future get onConnect => _connected.future;
88 void _notifyDisconnect() { 102 void _notifyDisconnect() {
89 if (!_disconnected.isCompleted) { 103 if (!_disconnected.isCompleted) {
90 Logger.root.info('WebSocketVM connection error: ${target.networkAddress}') ; 104 Logger.root.info('WebSocketVM connection error: ${target.networkAddress}') ;
91 _disconnected.complete(this); 105 _disconnected.complete(this);
92 } 106 }
93 } 107 }
94 Future get onDisconnect => _disconnected.future; 108 Future get onDisconnect => _disconnected.future;
95 109
96 void disconnect() { 110 void disconnect() {
97 if (_webSocket != null) { 111 if (_hasInitiatedConnect) {
98 _webSocket.close(); 112 _webSocket.close();
99 } 113 }
100 _cancelAllRequests(); 114 _cancelAllRequests();
101 _notifyDisconnect(); 115 _notifyDisconnect();
102 } 116 }
103 117
104 Future<String> getString(String id) { 118 Future<String> getString(String id) {
105 if (_webSocket == null) { 119 if (!_hasInitiatedConnect) {
106 // Create a WebSocket. 120 _hasInitiatedConnect = true;
107 _webSocket = new WebSocket(target.networkAddress); 121 _webSocket.connect(
108 _webSocket.onClose.listen(_onClose); 122 target.networkAddress, _onOpen, _onMessage, _onError, _onClose);
109 _webSocket.onError.listen(_onError);
110 _webSocket.onOpen.listen(_onOpen);
111 _webSocket.onMessage.listen(_onMessage);
112 } 123 }
113 return _makeRequest(id); 124 return _makeRequest(id);
114 } 125 }
115 126
116 /// Add a request for [id] to pending requests. 127 /// Add a request for [id] to pending requests.
117 Future<String> _makeRequest(String id) { 128 Future<String> _makeRequest(String id) {
118 assert(_webSocket != null); 129 assert(_hasInitiatedConnect);
119 // Create request. 130 // Create request.
120 String serial = (_requestSerial++).toString(); 131 String serial = (_requestSerial++).toString();
121 var request = new _WebSocketRequest(id); 132 var request = new _WebSocketRequest(id);
122 if (_webSocket.readyState == WebSocket.OPEN) { 133 if (_webSocket.isOpen) {
123 // Already connected, send request immediately. 134 // Already connected, send request immediately.
124 _sendRequest(serial, request); 135 _sendRequest(serial, request);
125 } else { 136 } else {
126 // Not connected yet, add to delayed requests. 137 // Not connected yet, add to delayed requests.
127 _delayedRequests[serial] = request; 138 _delayedRequests[serial] = request;
128 } 139 }
129 return request.completer.future; 140 return request.completer.future;
130 } 141 }
131 142
132 void _onClose(CloseEvent event) { 143 void _onClose() {
133 _cancelAllRequests(); 144 _cancelAllRequests();
134 _notifyDisconnect(); 145 _notifyDisconnect();
135 } 146 }
136 147
137 // WebSocket error event handler. 148 // WebSocket error event handler.
138 void _onError(Event) { 149 void _onError() {
139 _cancelAllRequests(); 150 _cancelAllRequests();
140 _notifyDisconnect(); 151 _notifyDisconnect();
141 } 152 }
142 153
143 // WebSocket open event handler. 154 // WebSocket open event handler.
144 void _onOpen(Event) { 155 void _onOpen() {
145 target.lastConnectionTime = new DateTime.now().millisecondsSinceEpoch; 156 target.lastConnectionTime = new DateTime.now().millisecondsSinceEpoch;
146 _sendAllDelayedRequests(); 157 _sendAllDelayedRequests();
147 _notifyConnect(); 158 _notifyConnect();
148 } 159 }
149 160
150 // WebSocket message event handler. 161 // WebSocket message event handler.
151 void _onMessage(MessageEvent event) { 162 void _onMessage(dynamic data) {
152 var map = JSON.decode(event.data); 163 assert(data is String); // We don't handle binary data, yet.
164 var map = JSON.decode(data);
153 if (map == null) { 165 if (map == null) {
154 Logger.root.severe('WebSocketVM got empty message'); 166 Logger.root.severe('WebSocketVM got empty message');
155 return; 167 return;
156 } 168 }
157 // Extract serial and response. 169 // Extract serial and response.
158 var serial; 170 var serial;
159 var response; 171 var response;
160 if (target.chrome) { 172 if (target.chrome) {
161 if (map['method'] != 'Dart.observatoryData') { 173 if (map['method'] != 'Dart.observatoryData') {
162 // ignore devtools protocol spam. 174 // ignore devtools protocol spam.
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 _cancelRequests(_pendingRequests); 219 _cancelRequests(_pendingRequests);
208 } 220 }
209 if (_delayedRequests.length > 0) { 221 if (_delayedRequests.length > 0) {
210 Logger.root.info('Cancelling all delayed requests.'); 222 Logger.root.info('Cancelling all delayed requests.');
211 _cancelRequests(_delayedRequests); 223 _cancelRequests(_delayedRequests);
212 } 224 }
213 } 225 }
214 226
215 /// Send all delayed requests. 227 /// Send all delayed requests.
216 void _sendAllDelayedRequests() { 228 void _sendAllDelayedRequests() {
217 assert(_webSocket != null); 229 assert(_webSocket.isOpen);
218 if (_delayedRequests.length == 0) { 230 if (_delayedRequests.length == 0) {
219 return; 231 return;
220 } 232 }
221 Logger.root.info('Sending all delayed requests.'); 233 Logger.root.info('Sending all delayed requests.');
222 // Send all delayed requests. 234 // Send all delayed requests.
223 _delayedRequests.forEach(_sendRequest); 235 _delayedRequests.forEach(_sendRequest);
224 // Clear all delayed requests. 236 // Clear all delayed requests.
225 _delayedRequests.clear(); 237 _delayedRequests.clear();
226 } 238 }
227 239
228 /// Send the request over WebSocket. 240 /// Send the request over WebSocket.
229 void _sendRequest(String serial, _WebSocketRequest request) { 241 void _sendRequest(String serial, _WebSocketRequest request) {
230 assert (_webSocket.readyState == WebSocket.OPEN); 242 assert (_webSocket.isOpen);
231 if (!request.id.endsWith('/profile/tag')) { 243 if (!request.id.endsWith('/profile/tag')) {
232 Logger.root.info('GET ${request.id} from ${target.networkAddress}'); 244 Logger.root.info('GET ${request.id} from ${target.networkAddress}');
233 } 245 }
234 // Mark request as pending. 246 // Mark request as pending.
235 assert(_pendingRequests.containsKey(serial) == false); 247 assert(_pendingRequests.containsKey(serial) == false);
236 _pendingRequests[serial] = request; 248 _pendingRequests[serial] = request;
237 var message; 249 var message;
238 // Encode message. 250 // Encode message.
239 if (target.chrome) { 251 if (target.chrome) {
240 message = JSON.encode({ 252 message = JSON.encode({
241 'id': int.parse(serial), 253 'id': int.parse(serial),
242 'method': 'Dart.observatoryQuery', 254 'method': 'Dart.observatoryQuery',
243 'params': { 255 'params': {
244 'id': serial, 256 'id': serial,
245 'query': request.id 257 'query': request.id
246 } 258 }
247 }); 259 });
248 } else { 260 } else {
249 message = JSON.encode({'seq': serial, 'request': request.id}); 261 message = JSON.encode({'seq': serial, 'request': request.id});
250 } 262 }
251 // Send message. 263 // Send message.
252 _webSocket.send(message); 264 _webSocket.send(message);
253 } 265 }
254 } 266 }
255
256 // A VM that communicates with the service via posting messages from DevTools.
257 class PostMessageVM extends VM {
258 final Completer _connected = new Completer();
259 final Completer _disconnected = new Completer();
260 void disconnect() { /* nope */ }
261 Future get onConnect => _connected.future;
262 Future get onDisconnect => _disconnected.future;
263 final Map<String, Completer> _pendingRequests =
264 new Map<String, Completer>();
265 int _requestSerial = 0;
266
267 PostMessageVM() : super() {
268 window.onMessage.listen(_messageHandler);
269 _connected.complete(this);
270 }
271
272 void _messageHandler(msg) {
273 var id = msg.data['id'];
274 var name = msg.data['name'];
275 var data = msg.data['data'];
276 if (name != 'observatoryData') {
277 return;
278 }
279 var completer = _pendingRequests[id];
280 assert(completer != null);
281 _pendingRequests.remove(id);
282 completer.complete(data);
283 }
284
285 Future<String> getString(String path) {
286 var idString = '$_requestSerial';
287 Map message = {};
288 message['id'] = idString;
289 message['method'] = 'observatoryQuery';
290 message['query'] = '$path';
291 _requestSerial++;
292 var completer = new Completer();
293 _pendingRequests[idString] = completer;
294 window.parent.postMessage(JSON.encode(message), '*');
295 return completer.future;
296 }
297 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698