protocol_discovery.dart 3.39 KB
Newer Older
1 2 3 4 5 6
// 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';

7 8
import 'base/common.dart';
import 'base/os.dart';
9
import 'device.dart';
10
import 'globals.dart';
11

12 13
/// Discover service protocol on a device
/// and forward the service protocol device port to the host.
14
class ProtocolDiscovery {
Devon Carew's avatar
Devon Carew committed
15
  /// [logReader] - a [DeviceLogReader] to look for service messages in.
16 17
  ProtocolDiscovery(DeviceLogReader logReader, String serviceName,
      {this.portForwarder, this.hostPort, this.defaultHostPort})
Devon Carew's avatar
Devon Carew committed
18
      : _logReader = logReader, _serviceName = serviceName {
19
    assert(_logReader != null);
Devon Carew's avatar
Devon Carew committed
20
    _subscription = _logReader.logLines.listen(_onLine);
21
    assert(portForwarder == null || defaultHostPort != null);
22 23
  }

24 25 26 27 28 29 30 31 32 33 34 35 36 37
  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);

Devon Carew's avatar
Devon Carew committed
38 39 40
  static const String kObservatoryService = 'Observatory';
  static const String kDiagnosticService = 'Diagnostic server';

41
  final DeviceLogReader _logReader;
42
  final String _serviceName;
43 44 45
  final DevicePortForwarder portForwarder;
  int hostPort;
  final int defaultHostPort;
Devon Carew's avatar
Devon Carew committed
46

47
  Completer<Uri> _completer = new Completer<Uri>();
Devon Carew's avatar
Devon Carew committed
48
  StreamSubscription<String> _subscription;
49

50
  /// The [Future] returned by this function will complete when the next service
51
  /// Uri is found.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
  Future<Uri> nextUri() async {
    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) {
      int devicePort = deviceUri.port;
      hostPort ??= await findPreferredPort(defaultHostPort);
      hostPort = await portForwarder
          .forward(devicePort, hostPort: hostPort)
          .timeout(const Duration(seconds: 60), onTimeout: () {
            throwToolExit('Timeout while atempting to foward device port $devicePort');
          });
      printTrace('Forwarded host port $hostPort to device port $devicePort');
      hostUri = deviceUri.replace(port: hostPort);
    } else {
      hostUri = deviceUri;
    }
    printStatus('$_serviceName listening on $hostUri');
    return hostUri;
  }
76

Devon Carew's avatar
Devon Carew committed
77 78 79 80
  void cancel() {
    _subscription.cancel();
  }

81
  void _onLine(String line) {
82 83 84 85
    Uri uri;
    String prefix = '$_serviceName listening on ';
    int index = line.indexOf(prefix + 'http://');
    if (index >= 0) {
86
      try {
87
        uri = Uri.parse(line.substring(index + prefix.length));
88 89 90 91
      } catch (_) {
        // Ignore errors.
      }
    }
92 93
    if (uri != null)
      _located(uri);
94 95
  }

96
  void _located(Uri uri) {
97 98
    assert(_completer != null);
    assert(!_completer.isCompleted);
Devon Carew's avatar
Devon Carew committed
99

100 101
    _completer.complete(uri);
    _completer = new Completer<Uri>();
102 103
  }
}