1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | import 'dart:async'; |
6 | |
7 | import 'package:async/async.dart' ; |
8 | |
9 | import 'base/logger.dart'; |
10 | import 'device.dart'; |
11 | import 'device_port_forwarder.dart'; |
12 | import 'mdns_discovery.dart'; |
13 | import 'protocol_discovery.dart'; |
14 | |
15 | /// Discovers the VM service uri on a device, and forwards the port to the host. |
16 | /// |
17 | /// This is mainly used during a `flutter attach`. |
18 | abstract class VMServiceDiscoveryForAttach { |
19 | VMServiceDiscoveryForAttach(); |
20 | |
21 | /// The discovered VM service URis. |
22 | /// |
23 | /// Port forwarding is only attempted when this is invoked, for each VM |
24 | /// Service URI in the stream. |
25 | Stream<Uri> get uris; |
26 | } |
27 | |
28 | /// An implementation of [VMServiceDiscoveryForAttach] that uses log scanning |
29 | /// for the discovery. |
30 | class LogScanningVMServiceDiscoveryForAttach extends VMServiceDiscoveryForAttach { |
31 | LogScanningVMServiceDiscoveryForAttach( |
32 | Future<DeviceLogReader> logReader, { |
33 | DevicePortForwarder? portForwarder, |
34 | int? hostPort, |
35 | int? devicePort, |
36 | required bool ipv6, |
37 | required Logger logger, |
38 | }) { |
39 | _protocolDiscovery = (() async => ProtocolDiscovery.vmService( |
40 | await logReader, |
41 | portForwarder: portForwarder, |
42 | ipv6: ipv6, |
43 | devicePort: devicePort, |
44 | hostPort: hostPort, |
45 | logger: logger, |
46 | ))(); |
47 | } |
48 | |
49 | late final Future<ProtocolDiscovery> _protocolDiscovery; |
50 | |
51 | @override |
52 | Stream<Uri> get uris { |
53 | final controller = StreamController<Uri>(); |
54 | _protocolDiscovery.then((ProtocolDiscovery protocolDiscovery) async { |
55 | await controller.addStream(protocolDiscovery.uris); |
56 | await controller.close(); |
57 | }, onError: (Object error) => controller.addError(error)); |
58 | return controller.stream; |
59 | } |
60 | } |
61 | |
62 | /// An implementation of [VMServiceDiscoveryForAttach] that uses mdns for the |
63 | /// discovery. |
64 | class MdnsVMServiceDiscoveryForAttach extends VMServiceDiscoveryForAttach { |
65 | MdnsVMServiceDiscoveryForAttach({ |
66 | required this.device, |
67 | this.appId, |
68 | required this.usesIpv6, |
69 | required this.useDeviceIPAsHost, |
70 | this.deviceVmservicePort, |
71 | this.hostVmservicePort, |
72 | }); |
73 | |
74 | final Device device; |
75 | final String? appId; |
76 | final bool usesIpv6; |
77 | final bool useDeviceIPAsHost; |
78 | final int? deviceVmservicePort; |
79 | final int? hostVmservicePort; |
80 | |
81 | @override |
82 | Stream<Uri> get uris { |
83 | final Future<Uri?> mDNSDiscoveryFuture = MDnsVmServiceDiscovery.instance! |
84 | .getVMServiceUriForAttach( |
85 | appId, |
86 | device, |
87 | usesIpv6: usesIpv6, |
88 | useDeviceIPAsHost: useDeviceIPAsHost, |
89 | deviceVmservicePort: deviceVmservicePort, |
90 | hostVmservicePort: hostVmservicePort, |
91 | ); |
92 | |
93 | return Stream<Uri?>.fromFuture( |
94 | mDNSDiscoveryFuture, |
95 | ).where((Uri? uri) => uri != null).cast<Uri>().asBroadcastStream(); |
96 | } |
97 | } |
98 | |
99 | /// An implementation of [VMServiceDiscoveryForAttach] that delegates to other |
100 | /// [VMServiceDiscoveryForAttach] instances for discovery. |
101 | class DelegateVMServiceDiscoveryForAttach extends VMServiceDiscoveryForAttach { |
102 | DelegateVMServiceDiscoveryForAttach(this.delegates); |
103 | |
104 | final List<VMServiceDiscoveryForAttach> delegates; |
105 | |
106 | @override |
107 | Stream<Uri> get uris => StreamGroup.merge<Uri>( |
108 | delegates.map((VMServiceDiscoveryForAttach delegate) => delegate.uris), |
109 | ); |
110 | } |
111 | |