| Index: runtime/bin/vmservice/client/bin/server.dart
|
| diff --git a/runtime/bin/vmservice/client/bin/server.dart b/runtime/bin/vmservice/client/bin/server.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..4df5a85e31ecebcba24861d53a3b1fe1af09f2fd
|
| --- /dev/null
|
| +++ b/runtime/bin/vmservice/client/bin/server.dart
|
| @@ -0,0 +1,159 @@
|
| +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
| +// 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 observatory_server;
|
| +
|
| +import 'dart:async';
|
| +import 'dart:convert';
|
| +import 'dart:io';
|
| +
|
| +import 'package:args/args.dart';
|
| +import 'package:logging/logging.dart';
|
| +
|
| +final Logger logger = new Logger('ObsServe');
|
| +
|
| +class ObservatoryServer {
|
| + static const _CHROME_PREFIX = '/crdptargets/';
|
| +
|
| + // Is logging enabled?
|
| + bool log;
|
| +
|
| + // Host to listen on.
|
| + String host;
|
| + // Port to listen on.
|
| + int port;
|
| +
|
| + // Host that pub is listening on.
|
| + String pubHost;
|
| + // Port that pub is listening on.
|
| + int pubPort;
|
| +
|
| + HttpServer _server;
|
| + final HttpClient _client = new HttpClient();
|
| +
|
| + ObservatoryServer(List<String> args) {
|
| + var parser = new ArgParser();
|
| + parser.addFlag('log', help: 'Log activity.', defaultsTo: true);
|
| + parser.addOption('port', help: 'Specify port listen on',
|
| + defaultsTo: '9090');
|
| + parser.addOption('host',
|
| + help: 'Specify host to listen on',
|
| + defaultsTo: '127.0.0.1');
|
| + parser.addOption('pub-port', help: 'Specify port that pub is listening on',
|
| + defaultsTo: '9191');
|
| + parser.addOption('pub-host', help: 'Specify host that pub is listening on',
|
| + defaultsTo: '127.0.0.1');
|
| + var results = parser.parse(args);
|
| + host = results['host'];
|
| + port = int.parse(results['port']);
|
| + log = results['log'];
|
| + pubHost = results['pub-host'];
|
| + pubPort = int.parse(results['pub-port']);
|
| + }
|
| +
|
| + List<Map> _makeTargetList(List<Map> tabs) {
|
| + var r = <Map>[];
|
| + tabs.forEach((tab) {
|
| + var uri = Uri.parse(tab['url']);
|
| + if (uri.host == 'devtools') {
|
| + // Ignore.
|
| + return;
|
| + }
|
| + var target = {
|
| + 'lastConnectionTime': 0,
|
| + 'chrome': true,
|
| + 'name': tab['title'],
|
| + 'networkAddress': tab['webSocketDebuggerUrl'],
|
| + };
|
| + r.add(target);
|
| + });
|
| + return r;
|
| + }
|
| +
|
| + void _getChromeTabs(HttpRequest request) {
|
| + var path = request.uri.path;
|
| + var method = request.method;
|
| + if (method != 'GET') {
|
| + return;
|
| + }
|
| + assert(path.startsWith(_CHROME_PREFIX));
|
| + var networkAddress = path.substring(_CHROME_PREFIX.length);
|
| + if ((networkAddress == '') || (networkAddress == null)) {
|
| + request.response.write('[]');
|
| + request.response.close();
|
| + return;
|
| + }
|
| + networkAddress = Uri.decodeComponent(networkAddress);
|
| + var chunks = networkAddress.split(':');
|
| + var chromeAddress = chunks[0];
|
| + var chromePort =
|
| + (chunks[1] == null) || (chunks[1] == '') ? 9222 : int.parse(chunks[1]);
|
| + logger.info('tabs from $chromeAddress:$chromePort');
|
| + _client.open(method, chromeAddress, chromePort, 'json')
|
| + .then((HttpClientRequest pubRequest) {
|
| + // Calling .close() on an HttpClientRequest sends the request to the
|
| + // server. The future completes to an HttpClientResponse when the
|
| + // server has responded.
|
| + return pubRequest.close();
|
| + }).then((HttpClientResponse response) {
|
| + var respond = (contents) {
|
| + var tabs = JSON.decode(contents);
|
| + var targets = _makeTargetList(tabs);
|
| + request.response.write(JSON.encode(targets));
|
| + request.response.close().catchError((e) {
|
| + logger.severe('tabs from $chromeAddress:$chromePort failed');
|
| + logger.severe(e.toString());
|
| + });
|
| + };
|
| + response.transform(UTF8.decoder).listen(respond);
|
| + }).catchError((e) {
|
| + logger.severe('tabs from $chromeAddress:$chromePort failed');
|
| + logger.severe(e.toString());
|
| + });
|
| + }
|
| +
|
| + /// Forward [request] to pub.
|
| + void _forwardToPub(HttpRequest request) {
|
| + var path = request.uri.path;
|
| + var method = request.method;
|
| + logger.info('pub $method $path');
|
| + _client.open(method, pubHost, pubPort, path)
|
| + .then((HttpClientRequest pubRequest) {
|
| + return pubRequest.close();
|
| + }).then((HttpClientResponse response) {
|
| + return request.response.addStream(response);
|
| + }).then((_) => request.response.close())
|
| + .catchError((e) {
|
| + logger.severe('pub $method $path failed.');
|
| + logger.severe(e.toString());
|
| + });
|
| + }
|
| +
|
| + void _onHttpRequest(HttpRequest request) {
|
| + // Allow cross origin requests.
|
| + request.response.headers.add('Access-Control-Allow-Origin', '*');
|
| + if (request.uri.path.startsWith(_CHROME_PREFIX)) {
|
| + _getChromeTabs(request);
|
| + } else {
|
| + _forwardToPub(request);
|
| + }
|
| + }
|
| +
|
| + /// Future completes to [this] on successful startup.
|
| + Future start() {
|
| + return HttpServer.bind(host, port).then((s) {
|
| + _server = s;
|
| + _server.listen(_onHttpRequest);
|
| + print('ObsServe is running on ${_server.address}:${_server.port}');
|
| + });
|
| + }
|
| +}
|
| +
|
| +main(List<String> args) {
|
| + hierarchicalLoggingEnabled = true;
|
| + logger.level = Level.ALL;
|
| + logger.onRecord.listen(print);
|
| + new ObservatoryServer(args)..start();
|
| +}
|
| +
|
|
|