OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 import 'dart:async'; | 5 import 'dart:async'; |
6 import 'dart:convert'; | 6 import 'dart:convert'; |
7 import 'dart:io'; | 7 import 'dart:io'; |
8 | 8 |
9 import 'package:async/async.dart'; | 9 import 'package:async/async.dart'; |
10 import 'package:path/path.dart' as p; | 10 import 'package:path/path.dart' as p; |
(...skipping 10 matching lines...) Expand all Loading... |
21 /// so this exposes a bare-bones API. The browser starts as soon as the class is | 21 /// so this exposes a bare-bones API. The browser starts as soon as the class is |
22 /// constructed, and is killed when [close] is called. | 22 /// constructed, and is killed when [close] is called. |
23 /// | 23 /// |
24 /// Any errors starting or running the process are reported through [onExit]. | 24 /// Any errors starting or running the process are reported through [onExit]. |
25 class Dartium extends Browser { | 25 class Dartium extends Browser { |
26 final name = "Dartium"; | 26 final name = "Dartium"; |
27 | 27 |
28 final Future<Uri> observatoryUrl; | 28 final Future<Uri> observatoryUrl; |
29 | 29 |
30 factory Dartium(url, {String executable, bool debug: false}) { | 30 factory Dartium(url, {String executable, bool debug: false}) { |
31 var completer = new Completer.sync(); | 31 var completer = new Completer<Uri>.sync(); |
32 return new Dartium._(() async { | 32 return new Dartium._(() async { |
33 if (executable == null) executable = _defaultExecutable(); | 33 if (executable == null) executable = _defaultExecutable(); |
34 | 34 |
35 var dir = createTempDir(); | 35 var dir = createTempDir(); |
36 var process = await Process.start(executable, [ | 36 var process = await Process.start(executable, [ |
37 "--user-data-dir=$dir", | 37 "--user-data-dir=$dir", |
38 url.toString(), | 38 url.toString(), |
39 "--disable-extensions", | 39 "--disable-extensions", |
40 "--disable-popup-blocking", | 40 "--disable-popup-blocking", |
41 "--bwsi", | 41 "--bwsi", |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
106 /// Returns the Observatory URL for the Dartium executable with the given | 106 /// Returns the Observatory URL for the Dartium executable with the given |
107 /// [stdout] stream, or `null` if the correct one couldn't be found. | 107 /// [stdout] stream, or `null` if the correct one couldn't be found. |
108 /// | 108 /// |
109 /// Dartium prints out three different Observatory URLs when it starts. Only | 109 /// Dartium prints out three different Observatory URLs when it starts. Only |
110 /// one of them is connected to the VM instance running the host page, and the | 110 /// one of them is connected to the VM instance running the host page, and the |
111 /// ordering isn't guaranteed, so we need to figure out which one is correct. | 111 /// ordering isn't guaranteed, so we need to figure out which one is correct. |
112 /// We do so by connecting to the VM service via WebSockets and looking for | 112 /// We do so by connecting to the VM service via WebSockets and looking for |
113 /// the Observatory instance that actually contains an isolate, and returning | 113 /// the Observatory instance that actually contains an isolate, and returning |
114 /// the corresponding URI. | 114 /// the corresponding URI. |
115 static Future<Uri> _getObservatoryUrl(Stream<List<int>> stdout) async { | 115 static Future<Uri> _getObservatoryUrl(Stream<List<int>> stdout) async { |
116 var urlQueue = new StreamQueue(lineSplitter.bind(stdout).map((line) { | 116 var urlQueue = new StreamQueue<Uri>(lineSplitter.bind(stdout).map((line) { |
117 var match = _observatoryRegExp.firstMatch(line); | 117 var match = _observatoryRegExp.firstMatch(line); |
118 return match == null ? null : Uri.parse(match[1]); | 118 return match == null ? null : Uri.parse(match[1]); |
119 }).where((line) => line != null)); | 119 }).where((line) => line != null)); |
120 | 120 |
121 var operations = [ | 121 var operations = [ |
122 urlQueue.next, | 122 urlQueue.next, |
123 urlQueue.next, | 123 urlQueue.next, |
124 urlQueue.next | 124 urlQueue.next |
125 ].map(_checkObservatoryUrl); | 125 ].map((future) => _checkObservatoryUrl(future)); |
126 | 126 |
127 urlQueue.cancel(); | 127 urlQueue.cancel(); |
128 | 128 |
129 /// Dartium will print three possible observatory URLs. For each one, we | 129 /// Dartium will print three possible observatory URLs. For each one, we |
130 /// check whether it's actually connected to an isolate, indicating that | 130 /// check whether it's actually connected to an isolate, indicating that |
131 /// it's the observatory for the main page. Once we find the one that is, we | 131 /// it's the observatory for the main page. Once we find the one that is, we |
132 /// cancel the other requests and return it. | 132 /// cancel the other requests and return it. |
133 return inCompletionOrder(operations) | 133 return (await inCompletionOrder(operations) |
134 .firstWhere((url) => url != null, defaultValue: () => null); | 134 .firstWhere((url) => url != null, defaultValue: () => null)) as Uri; |
135 } | 135 } |
136 | 136 |
137 /// If the URL returned by [future] corresponds to the correct Observatory | 137 /// If the URL returned by [future] corresponds to the correct Observatory |
138 /// instance, returns it. Otherwise, returns `null`. | 138 /// instance, returns it. Otherwise, returns `null`. |
139 /// | 139 /// |
140 /// If the returned operation is canceled before it fires, the WebSocket | 140 /// If the returned operation is canceled before it fires, the WebSocket |
141 /// connection with the given Observatory will be closed immediately. | 141 /// connection with the given Observatory will be closed immediately. |
142 static CancelableOperation<Uri> _checkObservatoryUrl(Future<Uri> future) { | 142 static CancelableOperation<Uri> _checkObservatoryUrl(Future<Uri> future) { |
143 var webSocket; | 143 var webSocket; |
144 var canceled = false; | 144 var canceled = false; |
145 var completer = new CancelableCompleter(onCancel: () { | 145 var completer = new CancelableCompleter<Uri>(onCancel: () { |
146 canceled = true; | 146 canceled = true; |
147 if (webSocket != null) webSocket.close(); | 147 if (webSocket != null) webSocket.close(); |
148 }); | 148 }); |
149 | 149 |
150 // We've encountered a format we don't understand. Close the web socket and | 150 // We've encountered a format we don't understand. Close the web socket and |
151 // complete to null. | 151 // complete to null. |
152 giveUp() { | 152 giveUp() { |
153 webSocket.close(); | 153 webSocket.close(); |
154 if (!completer.isCompleted) completer.complete(); | 154 if (!completer.isCompleted) completer.complete(); |
155 } | 155 } |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 // incorrect WebSocket that already closed. | 241 // incorrect WebSocket that already closed. |
242 return null; | 242 return null; |
243 } | 243 } |
244 }).catchError((error, stackTrace) { | 244 }).catchError((error, stackTrace) { |
245 if (!completer.isCompleted) completer.completeError(error, stackTrace); | 245 if (!completer.isCompleted) completer.completeError(error, stackTrace); |
246 }); | 246 }); |
247 | 247 |
248 return completer.operation; | 248 return completer.operation; |
249 } | 249 } |
250 } | 250 } |
OLD | NEW |