| Index: runtime/bin/vmservice/client/lib/service_common.dart
|
| ===================================================================
|
| --- runtime/bin/vmservice/client/lib/service_common.dart (revision 38598)
|
| +++ runtime/bin/vmservice/client/lib/service_common.dart (working copy)
|
| @@ -2,11 +2,10 @@
|
| // for details. All rights reserved. Use of this source code is governed by a
|
| // BSD-style license that can be found in the LICENSE file.
|
|
|
| -library service_html;
|
| +library service_common;
|
|
|
| import 'dart:async';
|
| import 'dart:convert';
|
| -import 'dart:html';
|
|
|
| import 'package:logging/logging.dart';
|
| import 'package:observatory/service.dart';
|
| @@ -60,10 +59,23 @@
|
| : completer = new Completer<String>();
|
| }
|
|
|
| -/// The [WebSocketVM] communicates with a Dart VM over WebSocket. The Dart VM
|
| -/// can be embedded in Chromium or standalone. In the case of Chromium, we
|
| -/// make the service requests via the Chrome Remote Debugging Protocol.
|
| -class WebSocketVM extends VM {
|
| +/// Minimal common interface for 'WebSocket' in [dart:io] and [dart:html].
|
| +abstract class CommonWebSocket {
|
| + void connect(String address,
|
| + void onOpen(),
|
| + void onMessage(dynamic data),
|
| + void onError(),
|
| + void onClose());
|
| + bool get isOpen;
|
| + void send(dynamic data);
|
| + void close();
|
| +}
|
| +
|
| +/// A [CommonWebSocketVM] communicates with a Dart VM over a CommonWebSocket.
|
| +/// The Dart VM can be embedded in Chromium or standalone. In the case of
|
| +/// Chromium, we make the service requests via the Chrome Remote Debugging
|
| +/// Protocol.
|
| +abstract class CommonWebSocketVM extends VM {
|
| final Completer _connected = new Completer();
|
| final Completer _disconnected = new Completer();
|
| final WebSocketVMTarget target;
|
| @@ -72,9 +84,11 @@
|
| final Map<String, _WebSocketRequest> _pendingRequests =
|
| new Map<String, _WebSocketRequest>();
|
| int _requestSerial = 0;
|
| - WebSocket _webSocket;
|
| + bool _hasInitiatedConnect = false;
|
|
|
| - WebSocketVM(this.target) {
|
| + CommonWebSocket _webSocket;
|
| +
|
| + CommonWebSocketVM(this.target, this._webSocket) {
|
| assert(target != null);
|
| }
|
|
|
| @@ -94,7 +108,7 @@
|
| Future get onDisconnect => _disconnected.future;
|
|
|
| void disconnect() {
|
| - if (_webSocket != null) {
|
| + if (_hasInitiatedConnect) {
|
| _webSocket.close();
|
| }
|
| _cancelAllRequests();
|
| @@ -102,24 +116,21 @@
|
| }
|
|
|
| Future<String> getString(String id) {
|
| - if (_webSocket == null) {
|
| - // Create a WebSocket.
|
| - _webSocket = new WebSocket(target.networkAddress);
|
| - _webSocket.onClose.listen(_onClose);
|
| - _webSocket.onError.listen(_onError);
|
| - _webSocket.onOpen.listen(_onOpen);
|
| - _webSocket.onMessage.listen(_onMessage);
|
| + if (!_hasInitiatedConnect) {
|
| + _hasInitiatedConnect = true;
|
| + _webSocket.connect(
|
| + target.networkAddress, _onOpen, _onMessage, _onError, _onClose);
|
| }
|
| return _makeRequest(id);
|
| }
|
|
|
| /// Add a request for [id] to pending requests.
|
| Future<String> _makeRequest(String id) {
|
| - assert(_webSocket != null);
|
| + assert(_hasInitiatedConnect);
|
| // Create request.
|
| String serial = (_requestSerial++).toString();
|
| var request = new _WebSocketRequest(id);
|
| - if (_webSocket.readyState == WebSocket.OPEN) {
|
| + if (_webSocket.isOpen) {
|
| // Already connected, send request immediately.
|
| _sendRequest(serial, request);
|
| } else {
|
| @@ -129,27 +140,28 @@
|
| return request.completer.future;
|
| }
|
|
|
| - void _onClose(CloseEvent event) {
|
| + void _onClose() {
|
| _cancelAllRequests();
|
| _notifyDisconnect();
|
| }
|
|
|
| // WebSocket error event handler.
|
| - void _onError(Event) {
|
| + void _onError() {
|
| _cancelAllRequests();
|
| _notifyDisconnect();
|
| }
|
|
|
| // WebSocket open event handler.
|
| - void _onOpen(Event) {
|
| + void _onOpen() {
|
| target.lastConnectionTime = new DateTime.now().millisecondsSinceEpoch;
|
| _sendAllDelayedRequests();
|
| _notifyConnect();
|
| }
|
|
|
| // WebSocket message event handler.
|
| - void _onMessage(MessageEvent event) {
|
| - var map = JSON.decode(event.data);
|
| + void _onMessage(dynamic data) {
|
| + assert(data is String); // We don't handle binary data, yet.
|
| + var map = JSON.decode(data);
|
| if (map == null) {
|
| Logger.root.severe('WebSocketVM got empty message');
|
| return;
|
| @@ -214,7 +226,7 @@
|
|
|
| /// Send all delayed requests.
|
| void _sendAllDelayedRequests() {
|
| - assert(_webSocket != null);
|
| + assert(_webSocket.isOpen);
|
| if (_delayedRequests.length == 0) {
|
| return;
|
| }
|
| @@ -227,7 +239,7 @@
|
|
|
| /// Send the request over WebSocket.
|
| void _sendRequest(String serial, _WebSocketRequest request) {
|
| - assert (_webSocket.readyState == WebSocket.OPEN);
|
| + assert (_webSocket.isOpen);
|
| if (!request.id.endsWith('/profile/tag')) {
|
| Logger.root.info('GET ${request.id} from ${target.networkAddress}');
|
| }
|
| @@ -252,46 +264,3 @@
|
| _webSocket.send(message);
|
| }
|
| }
|
| -
|
| -// A VM that communicates with the service via posting messages from DevTools.
|
| -class PostMessageVM extends VM {
|
| - final Completer _connected = new Completer();
|
| - final Completer _disconnected = new Completer();
|
| - void disconnect() { /* nope */ }
|
| - Future get onConnect => _connected.future;
|
| - Future get onDisconnect => _disconnected.future;
|
| - final Map<String, Completer> _pendingRequests =
|
| - new Map<String, Completer>();
|
| - int _requestSerial = 0;
|
| -
|
| - PostMessageVM() : super() {
|
| - window.onMessage.listen(_messageHandler);
|
| - _connected.complete(this);
|
| - }
|
| -
|
| - void _messageHandler(msg) {
|
| - var id = msg.data['id'];
|
| - var name = msg.data['name'];
|
| - var data = msg.data['data'];
|
| - if (name != 'observatoryData') {
|
| - return;
|
| - }
|
| - var completer = _pendingRequests[id];
|
| - assert(completer != null);
|
| - _pendingRequests.remove(id);
|
| - completer.complete(data);
|
| - }
|
| -
|
| - Future<String> getString(String path) {
|
| - var idString = '$_requestSerial';
|
| - Map message = {};
|
| - message['id'] = idString;
|
| - message['method'] = 'observatoryQuery';
|
| - message['query'] = '$path';
|
| - _requestSerial++;
|
| - var completer = new Completer();
|
| - _pendingRequests[idString] = completer;
|
| - window.parent.postMessage(JSON.encode(message), '*');
|
| - return completer.future;
|
| - }
|
| -}
|
|
|