
1. Add `PortScanner` abstraction so that we don't do actual port scanning in tests. 2. Don't change the real `cwd` of the isolate during tests, as it affects all tests, not just the current running test. Fixes #8761
103 lines
3.4 KiB
Dart
103 lines
3.4 KiB
Dart
// Copyright 2016 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'dart:async';
|
|
|
|
import 'base/common.dart';
|
|
import 'base/port_scanner.dart';
|
|
import 'device.dart';
|
|
import 'globals.dart';
|
|
|
|
/// Discover service protocol on a device
|
|
/// and forward the service protocol device port to the host.
|
|
class ProtocolDiscovery {
|
|
/// [logReader] - a [DeviceLogReader] to look for service messages in.
|
|
ProtocolDiscovery(DeviceLogReader logReader, String serviceName,
|
|
{this.portForwarder, this.hostPort, this.defaultHostPort})
|
|
: _logReader = logReader, _serviceName = serviceName {
|
|
assert(_logReader != null);
|
|
_subscription = _logReader.logLines.listen(_onLine);
|
|
assert(portForwarder == null || defaultHostPort != null);
|
|
}
|
|
|
|
factory ProtocolDiscovery.observatory(DeviceLogReader logReader,
|
|
{DevicePortForwarder portForwarder, int hostPort}) =>
|
|
new ProtocolDiscovery(logReader, kObservatoryService,
|
|
portForwarder: portForwarder,
|
|
hostPort: hostPort,
|
|
defaultHostPort: kDefaultObservatoryPort);
|
|
|
|
factory ProtocolDiscovery.diagnosticService(DeviceLogReader logReader,
|
|
{DevicePortForwarder portForwarder, int hostPort}) =>
|
|
new ProtocolDiscovery(logReader, kDiagnosticService,
|
|
portForwarder: portForwarder,
|
|
hostPort: hostPort,
|
|
defaultHostPort: kDefaultDiagnosticPort);
|
|
|
|
static const String kObservatoryService = 'Observatory';
|
|
static const String kDiagnosticService = 'Diagnostic server';
|
|
|
|
final DeviceLogReader _logReader;
|
|
final String _serviceName;
|
|
final DevicePortForwarder portForwarder;
|
|
int hostPort;
|
|
final int defaultHostPort;
|
|
|
|
Completer<Uri> _completer = new Completer<Uri>();
|
|
StreamSubscription<String> _subscription;
|
|
|
|
/// The [Future] returned by this function will complete when the next service
|
|
/// Uri is found.
|
|
Future<Uri> nextUri() async {
|
|
final Uri deviceUri = await _completer.future.timeout(
|
|
const Duration(seconds: 60), onTimeout: () {
|
|
throwToolExit('Timeout while attempting to retrieve Uri for $_serviceName');
|
|
}
|
|
);
|
|
printTrace('$_serviceName Uri on device: $deviceUri');
|
|
Uri hostUri;
|
|
if (portForwarder != null) {
|
|
final int devicePort = deviceUri.port;
|
|
hostPort ??= await portScanner.findPreferredPort(defaultHostPort);
|
|
hostPort = await portForwarder
|
|
.forward(devicePort, hostPort: hostPort)
|
|
.timeout(const Duration(seconds: 60), onTimeout: () {
|
|
throwToolExit('Timeout while atempting to foward device port $devicePort for $_serviceName');
|
|
});
|
|
printTrace('Forwarded host port $hostPort to device port $devicePort for $_serviceName');
|
|
hostUri = deviceUri.replace(port: hostPort);
|
|
} else {
|
|
hostUri = deviceUri;
|
|
}
|
|
return hostUri;
|
|
}
|
|
|
|
void cancel() {
|
|
_subscription.cancel();
|
|
}
|
|
|
|
void _onLine(String line) {
|
|
Uri uri;
|
|
final String prefix = '$_serviceName listening on ';
|
|
final int index = line.indexOf(prefix + 'http://');
|
|
if (index >= 0) {
|
|
try {
|
|
uri = Uri.parse(line.substring(index + prefix.length));
|
|
} catch (_) {
|
|
// Ignore errors.
|
|
}
|
|
}
|
|
if (uri != null)
|
|
_located(uri);
|
|
}
|
|
|
|
void _located(Uri uri) {
|
|
assert(_completer != null);
|
|
assert(!_completer.isCompleted);
|
|
|
|
_completer.complete(uri);
|
|
_completer = new Completer<Uri>();
|
|
}
|
|
}
|