blob: 5b4920b377596819c0c21c720c50fa069e4ccd10 [file] [log] [blame]
// 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<Uri> get uris;
}
/// An implementation of [VMServiceDiscoveryForAttach] that uses log scanning
/// for the discovery.
class LogScanningVMServiceDiscoveryForAttach extends VMServiceDiscoveryForAttach {
LogScanningVMServiceDiscoveryForAttach(
Future<DeviceLogReader> 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> _protocolDiscovery;
@override
Stream<Uri> get uris {
final StreamController<Uri> controller = StreamController<Uri>();
_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<Uri> get uris {
final Future<Uri?> mDNSDiscoveryFuture = MDnsVmServiceDiscovery.instance!.getVMServiceUriForAttach(
appId,
device,
usesIpv6: usesIpv6,
useDeviceIPAsHost: useDeviceIPAsHost,
deviceVmservicePort: deviceVmservicePort,
hostVmservicePort: hostVmservicePort,
);
return Stream<Uri?>.fromFuture(mDNSDiscoveryFuture).where((Uri? uri) => uri != null).cast<Uri>().asBroadcastStream();
}
}
/// An implementation of [VMServiceDiscoveryForAttach] that delegates to other
/// [VMServiceDiscoveryForAttach] instances for discovery.
class DelegateVMServiceDiscoveryForAttach extends VMServiceDiscoveryForAttach {
DelegateVMServiceDiscoveryForAttach(this.delegates);
final List<VMServiceDiscoveryForAttach> delegates;
@override
Stream<Uri> get uris =>
StreamGroup.merge<Uri>(
delegates.map((VMServiceDiscoveryForAttach delegate) => delegate.uris));
}