protocol_discovery.dart 2.97 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
import 'base/common.dart';
8
import 'base/io.dart';
9
import 'base/port_scanner.dart';
10
import 'device.dart';
11
import 'globals.dart';
12

13
/// Discovers a specific service protocol on a device, and forwards the service
14
/// protocol device port to the host.
15
class ProtocolDiscovery {
16
  ProtocolDiscovery._(
17 18
    this.logReader,
    this.serviceName, {
19 20 21
    this.portForwarder,
    this.hostPort,
    this.defaultHostPort,
22
    this.ipv6,
23 24 25
  }) : assert(logReader != null),
       assert(portForwarder == null || defaultHostPort != null),
       _prefix = '$serviceName listening on ' {
26 27 28 29 30 31 32
    _deviceLogSubscription = logReader.logLines.listen(_handleLine);
  }

  factory ProtocolDiscovery.observatory(
    DeviceLogReader logReader, {
    DevicePortForwarder portForwarder,
    int hostPort,
33
    bool ipv6: false,
34 35 36 37 38 39 40
  }) {
    const String kObservatoryService = 'Observatory';
    return new ProtocolDiscovery._(
      logReader, kObservatoryService,
      portForwarder: portForwarder,
      hostPort: hostPort,
      defaultHostPort: kDefaultObservatoryPort,
41
      ipv6: ipv6,
42
    );
43 44
  }

45 46
  final DeviceLogReader logReader;
  final String serviceName;
47
  final DevicePortForwarder portForwarder;
48
  final int hostPort;
49
  final int defaultHostPort;
50
  final bool ipv6;
51 52

  final String _prefix;
53
  final Completer<Uri> _completer = new Completer<Uri>();
Devon Carew's avatar
Devon Carew committed
54

55
  StreamSubscription<String> _deviceLogSubscription;
56

57
  /// The discovered service URI.
58
  Future<Uri> get uri => _completer.future;
59

60 61 62 63 64
  Future<Null> cancel() => _stopScrapingLogs();

  Future<Null> _stopScrapingLogs() async {
    await _deviceLogSubscription?.cancel();
    _deviceLogSubscription = null;
Devon Carew's avatar
Devon Carew committed
65 66
  }

67
  void _handleLine(String line) {
68
    Uri uri;
69
    final int index = line.indexOf(_prefix + 'http://');
70
    if (index >= 0) {
71
      try {
72
        uri = Uri.parse(line.substring(index + _prefix.length));
73 74 75
      } catch (error) {
        _stopScrapingLogs();
        _completer.completeError(error);
76 77
      }
    }
78 79 80 81 82 83

    if (uri != null) {
      assert(!_completer.isCompleted);
      _stopScrapingLogs();
      _completer.complete(_forwardPort(uri));
    }
84 85
  }

86
  Future<Uri> _forwardPort(Uri deviceUri) async {
87
    printTrace('$serviceName URL on device: $deviceUri');
88 89 90 91 92
    Uri hostUri = deviceUri;

    if (portForwarder != null) {
      final int devicePort = deviceUri.port;
      int hostPort = this.hostPort ?? await portScanner.findPreferredPort(defaultHostPort);
93
      hostPort = await portForwarder.forward(devicePort, hostPort: hostPort);
94
      printTrace('Forwarded host port $hostPort to device port $devicePort for $serviceName');
95 96
      hostUri = deviceUri.replace(port: hostPort);
    }
Devon Carew's avatar
Devon Carew committed
97

98 99
    assert(new InternetAddress(hostUri.host).isLoopback);
    if (ipv6) {
100
      hostUri = hostUri.replace(host: InternetAddress.LOOPBACK_IP_V6.host); // ignore: deprecated_member_use
101 102
    }

103
    return hostUri;
104 105
  }
}