// Copyright 2014 The Flutter 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 'package:async/async.dart'; import 'base/logger.dart'; import 'device.dart'; import 'device_port_forwarder.dart'; import 'mdns_discovery.dart'; import 'protocol_discovery.dart'; /// Discovers the VM service uri on a device, and forwards the port to the host. /// /// This is mainly used during a `flutter attach`. abstract class VMServiceDiscoveryForAttach { VMServiceDiscoveryForAttach(); /// The discovered VM service URis. /// /// Port forwarding is only attempted when this is invoked, for each VM /// Service URI in the stream. Stream get uris; } /// An implementation of [VMServiceDiscoveryForAttach] that uses log scanning /// for the discovery. class LogScanningVMServiceDiscoveryForAttach extends VMServiceDiscoveryForAttach { LogScanningVMServiceDiscoveryForAttach( Future logReader, { DevicePortForwarder? portForwarder, int? hostPort, int? devicePort, required bool ipv6, required Logger logger, }) { _protocolDiscovery = (() async => ProtocolDiscovery.vmService( await logReader, portForwarder: portForwarder, ipv6: ipv6, devicePort: devicePort, hostPort: hostPort, logger: logger, ))(); } late final Future _protocolDiscovery; @override Stream get uris { final StreamController controller = StreamController(); _protocolDiscovery.then((ProtocolDiscovery protocolDiscovery) async { await controller.addStream(protocolDiscovery.uris); await controller.close(); }, onError: (Object error) => controller.addError(error)); return controller.stream; } } /// An implementation of [VMServiceDiscoveryForAttach] that uses mdns for the /// discovery. class MdnsVMServiceDiscoveryForAttach extends VMServiceDiscoveryForAttach { MdnsVMServiceDiscoveryForAttach({ required this.device, this.appId, required this.usesIpv6, required this.useDeviceIPAsHost, this.deviceVmservicePort, this.hostVmservicePort, }); final Device device; final String? appId; final bool usesIpv6; final bool useDeviceIPAsHost; final int? deviceVmservicePort; final int? hostVmservicePort; @override Stream get uris { final Future mDNSDiscoveryFuture = MDnsVmServiceDiscovery.instance! .getVMServiceUriForAttach( appId, device, usesIpv6: usesIpv6, useDeviceIPAsHost: useDeviceIPAsHost, deviceVmservicePort: deviceVmservicePort, hostVmservicePort: hostVmservicePort, ); return Stream.fromFuture( mDNSDiscoveryFuture, ).where((Uri? uri) => uri != null).cast().asBroadcastStream(); } } /// An implementation of [VMServiceDiscoveryForAttach] that delegates to other /// [VMServiceDiscoveryForAttach] instances for discovery. class DelegateVMServiceDiscoveryForAttach extends VMServiceDiscoveryForAttach { DelegateVMServiceDiscoveryForAttach(this.delegates); final List delegates; @override Stream get uris => StreamGroup.merge( delegates.map((VMServiceDiscoveryForAttach delegate) => delegate.uris), ); }