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

Side by Side Diff: runtime/bin/vmservice/client/lib/service_html.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_html;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:convert'; 8 import 'dart:convert';
9 import 'dart:html'; 9 import 'dart:html';
10 10
11 import 'package:logging/logging.dart'; 11 import 'package:observatory/service_common.dart';
12 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_common.dart';
16 15
17 /// Description of a VM target. 16 class _HtmlWebSocket implements CommonWebSocket {
18 class WebSocketVMTarget { 17 WebSocket _webSocket;
19 // Last time this VM has been connected to.
20 int lastConnectionTime = 0;
21 bool get hasEverConnected => lastConnectionTime > 0;
22 18
23 // Chrome VM or standalone; 19 void connect(String address,
24 bool chrome = false; 20 void onOpen(),
25 bool get standalone => !chrome; 21 void onMessage(dynamic data),
26 22 void onError(),
27 // User defined name. 23 void onClose()) {
28 String name; 24 _webSocket = new WebSocket(address);
29 // Network address of VM. 25 _webSocket.onClose.listen((CloseEvent) => onClose());
30 String networkAddress; 26 _webSocket.onError.listen((Event) => onError());
31 27 _webSocket.onOpen.listen((Event) => onOpen());
32 WebSocketVMTarget(this.networkAddress) { 28 _webSocket.onMessage.listen((MessageEvent event) => onMessage(event.data));
33 name = networkAddress;
34 } 29 }
35 30
36 WebSocketVMTarget.fromMap(Map json) { 31 bool get isOpen => _webSocket.readyState == WebSocket.OPEN;
37 lastConnectionTime = json['lastConnectionTime']; 32
38 chrome = json['chrome']; 33 void send(dynamic data) {
39 name = json['name']; 34 _webSocket.send(data);
40 networkAddress = json['networkAddress'];
41 if (name == null) {
42 name = networkAddress;
43 }
44 } 35 }
45 36
46 Map toJson() { 37 void close() {
47 return { 38 _webSocket.close();
48 'lastConnectionTime': lastConnectionTime,
49 'chrome': chrome,
50 'name': name,
51 'networkAddress': networkAddress,
52 };
53 } 39 }
54 } 40 }
55 41
56 class _WebSocketRequest {
57 final String id;
58 final Completer<String> completer;
59 _WebSocketRequest(this.id)
60 : completer = new Completer<String>();
61 }
62
63 /// The [WebSocketVM] communicates with a Dart VM over WebSocket. The Dart VM 42 /// The [WebSocketVM] communicates with a Dart VM over WebSocket. The Dart VM
64 /// can be embedded in Chromium or standalone. In the case of Chromium, we 43 /// can be embedded in Chromium or standalone. In the case of Chromium, we
65 /// make the service requests via the Chrome Remote Debugging Protocol. 44 /// make the service requests via the Chrome Remote Debugging Protocol.
66 class WebSocketVM extends VM { 45 class WebSocketVM extends CommonWebSocketVM {
67 final Completer _connected = new Completer(); 46 WebSocketVM(WebSocketVMTarget target) : super(target, new _HtmlWebSocket());
68 final Completer _disconnected = new Completer();
69 final WebSocketVMTarget target;
70 final Map<String, _WebSocketRequest> _delayedRequests =
71 new Map<String, _WebSocketRequest>();
72 final Map<String, _WebSocketRequest> _pendingRequests =
73 new Map<String, _WebSocketRequest>();
74 int _requestSerial = 0;
75 WebSocket _webSocket;
76
77 WebSocketVM(this.target) {
78 assert(target != null);
79 }
80
81 void _notifyConnect() {
82 if (!_connected.isCompleted) {
83 Logger.root.info('WebSocketVM connection opened: ${target.networkAddress}' );
84 _connected.complete(this);
85 }
86 }
87 Future get onConnect => _connected.future;
88 void _notifyDisconnect() {
89 if (!_disconnected.isCompleted) {
90 Logger.root.info('WebSocketVM connection error: ${target.networkAddress}') ;
91 _disconnected.complete(this);
92 }
93 }
94 Future get onDisconnect => _disconnected.future;
95
96 void disconnect() {
97 if (_webSocket != null) {
98 _webSocket.close();
99 }
100 _cancelAllRequests();
101 _notifyDisconnect();
102 }
103
104 Future<String> getString(String id) {
105 if (_webSocket == null) {
106 // Create a WebSocket.
107 _webSocket = new WebSocket(target.networkAddress);
108 _webSocket.onClose.listen(_onClose);
109 _webSocket.onError.listen(_onError);
110 _webSocket.onOpen.listen(_onOpen);
111 _webSocket.onMessage.listen(_onMessage);
112 }
113 return _makeRequest(id);
114 }
115
116 /// Add a request for [id] to pending requests.
117 Future<String> _makeRequest(String id) {
118 assert(_webSocket != null);
119 // Create request.
120 String serial = (_requestSerial++).toString();
121 var request = new _WebSocketRequest(id);
122 if (_webSocket.readyState == WebSocket.OPEN) {
123 // Already connected, send request immediately.
124 _sendRequest(serial, request);
125 } else {
126 // Not connected yet, add to delayed requests.
127 _delayedRequests[serial] = request;
128 }
129 return request.completer.future;
130 }
131
132 void _onClose(CloseEvent event) {
133 _cancelAllRequests();
134 _notifyDisconnect();
135 }
136
137 // WebSocket error event handler.
138 void _onError(Event) {
139 _cancelAllRequests();
140 _notifyDisconnect();
141 }
142
143 // WebSocket open event handler.
144 void _onOpen(Event) {
145 target.lastConnectionTime = new DateTime.now().millisecondsSinceEpoch;
146 _sendAllDelayedRequests();
147 _notifyConnect();
148 }
149
150 // WebSocket message event handler.
151 void _onMessage(MessageEvent event) {
152 var map = JSON.decode(event.data);
153 if (map == null) {
154 Logger.root.severe('WebSocketVM got empty message');
155 return;
156 }
157 // Extract serial and response.
158 var serial;
159 var response;
160 if (target.chrome) {
161 if (map['method'] != 'Dart.observatoryData') {
162 // ignore devtools protocol spam.
163 return;
164 }
165 serial = map['params']['id'].toString();
166 response = map['params']['data'];
167 } else {
168 serial = map['seq'];
169 response = map['response'];
170 }
171 if (serial == null) {
172 // Messages without sequence numbers are asynchronous events
173 // from the vm.
174 postEventMessage(response);
175 return;
176 }
177 // Complete request.
178 var request = _pendingRequests.remove(serial);
179 if (request == null) {
180 Logger.root.severe('Received unexpected message: ${map}');
181 return;
182 }
183 request.completer.complete(response);
184 }
185
186 String _generateNetworkError(String userMessage) {
187 return JSON.encode({
188 'type': 'ServiceException',
189 'id': '',
190 'kind': 'NetworkException',
191 'message': userMessage
192 });
193 }
194
195 void _cancelRequests(Map<String, _WebSocketRequest> requests) {
196 requests.forEach((String serial, _WebSocketRequest request) {
197 request.completer.complete(
198 _generateNetworkError('WebSocket disconnected'));
199 });
200 requests.clear();
201 }
202
203 /// Cancel all pending and delayed requests by completing them with an error.
204 void _cancelAllRequests() {
205 if (_pendingRequests.length > 0) {
206 Logger.root.info('Cancelling all pending requests.');
207 _cancelRequests(_pendingRequests);
208 }
209 if (_delayedRequests.length > 0) {
210 Logger.root.info('Cancelling all delayed requests.');
211 _cancelRequests(_delayedRequests);
212 }
213 }
214
215 /// Send all delayed requests.
216 void _sendAllDelayedRequests() {
217 assert(_webSocket != null);
218 if (_delayedRequests.length == 0) {
219 return;
220 }
221 Logger.root.info('Sending all delayed requests.');
222 // Send all delayed requests.
223 _delayedRequests.forEach(_sendRequest);
224 // Clear all delayed requests.
225 _delayedRequests.clear();
226 }
227
228 /// Send the request over WebSocket.
229 void _sendRequest(String serial, _WebSocketRequest request) {
230 assert (_webSocket.readyState == WebSocket.OPEN);
231 if (!request.id.endsWith('/profile/tag')) {
232 Logger.root.info('GET ${request.id} from ${target.networkAddress}');
233 }
234 // Mark request as pending.
235 assert(_pendingRequests.containsKey(serial) == false);
236 _pendingRequests[serial] = request;
237 var message;
238 // Encode message.
239 if (target.chrome) {
240 message = JSON.encode({
241 'id': int.parse(serial),
242 'method': 'Dart.observatoryQuery',
243 'params': {
244 'id': serial,
245 'query': request.id
246 }
247 });
248 } else {
249 message = JSON.encode({'seq': serial, 'request': request.id});
250 }
251 // Send message.
252 _webSocket.send(message);
253 }
254 } 47 }
255 48
256 // A VM that communicates with the service via posting messages from DevTools. 49 // A VM that communicates with the service via posting messages from DevTools.
257 class PostMessageVM extends VM { 50 class PostMessageVM extends VM {
258 final Completer _connected = new Completer(); 51 final Completer _connected = new Completer();
259 final Completer _disconnected = new Completer(); 52 final Completer _disconnected = new Completer();
260 void disconnect() { /* nope */ } 53 void disconnect() { /* nope */ }
261 Future get onConnect => _connected.future; 54 Future get onConnect => _connected.future;
262 Future get onDisconnect => _disconnected.future; 55 Future get onDisconnect => _disconnected.future;
263 final Map<String, Completer> _pendingRequests = 56 final Map<String, Completer> _pendingRequests =
(...skipping 24 matching lines...) Expand all
288 message['id'] = idString; 81 message['id'] = idString;
289 message['method'] = 'observatoryQuery'; 82 message['method'] = 'observatoryQuery';
290 message['query'] = '$path'; 83 message['query'] = '$path';
291 _requestSerial++; 84 _requestSerial++;
292 var completer = new Completer(); 85 var completer = new Completer();
293 _pendingRequests[idString] = completer; 86 _pendingRequests[idString] = completer;
294 window.parent.postMessage(JSON.encode(message), '*'); 87 window.parent.postMessage(JSON.encode(message), '*');
295 return completer.future; 88 return completer.future;
296 } 89 }
297 } 90 }
OLDNEW
« no previous file with comments | « runtime/bin/vmservice/client/lib/service_common.dart ('k') | runtime/bin/vmservice/client/lib/service_io.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698