116 lines
4.3 KiB
Dart
116 lines
4.3 KiB
Dart
// 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:dds/dds.dart' as dds;
|
|
import 'package:meta/meta.dart';
|
|
|
|
import 'common.dart';
|
|
import 'context.dart';
|
|
import 'io.dart' as io;
|
|
import 'logger.dart';
|
|
|
|
// TODO(fujino): This should be direct injected, rather than mutable global state.
|
|
@visibleForTesting
|
|
Future<dds.DartDevelopmentService> Function(
|
|
Uri remoteVmServiceUri, {
|
|
bool enableAuthCodes,
|
|
bool ipv6,
|
|
Uri? serviceUri,
|
|
List<String> cachedUserTags,
|
|
dds.UriConverter? uriConverter,
|
|
}) ddsLauncherCallback = dds.DartDevelopmentService.startDartDevelopmentService;
|
|
|
|
/// Helper class to launch a [dds.DartDevelopmentService]. Allows for us to
|
|
/// mock out this functionality for testing purposes.
|
|
class DartDevelopmentService {
|
|
dds.DartDevelopmentService? _ddsInstance;
|
|
|
|
Uri? get uri => _ddsInstance?.uri ?? _existingDdsUri;
|
|
Uri? _existingDdsUri;
|
|
|
|
Future<void> get done => _completer.future;
|
|
final Completer<void> _completer = Completer<void>();
|
|
|
|
Future<void> startDartDevelopmentService(
|
|
Uri vmServiceUri, {
|
|
required Logger logger,
|
|
int? hostPort,
|
|
bool? ipv6,
|
|
bool? disableServiceAuthCodes,
|
|
bool cacheStartupProfile = false,
|
|
}) async {
|
|
final Uri ddsUri = Uri(
|
|
scheme: 'http',
|
|
host: ((ipv6 ?? false) ? io.InternetAddress.loopbackIPv6 : io.InternetAddress.loopbackIPv4).host,
|
|
port: hostPort ?? 0,
|
|
);
|
|
logger.printTrace(
|
|
'Launching a Dart Developer Service (DDS) instance at $ddsUri, '
|
|
'connecting to VM service at $vmServiceUri.',
|
|
);
|
|
try {
|
|
_ddsInstance = await ddsLauncherCallback(
|
|
vmServiceUri,
|
|
serviceUri: ddsUri,
|
|
enableAuthCodes: disableServiceAuthCodes != true,
|
|
ipv6: ipv6 ?? false,
|
|
// Enables caching of CPU samples collected during application startup.
|
|
cachedUserTags: cacheStartupProfile ? const <String>['AppStartUp'] : const <String>[],
|
|
uriConverter: context.get<dds.UriConverter>(),
|
|
);
|
|
unawaited(_ddsInstance?.done.whenComplete(() {
|
|
if (!_completer.isCompleted) {
|
|
_completer.complete();
|
|
}
|
|
}));
|
|
logger.printTrace('DDS is listening at ${_ddsInstance?.uri}.');
|
|
} on dds.DartDevelopmentServiceException catch (e) {
|
|
logger.printTrace('Warning: Failed to start DDS: ${e.message}');
|
|
if (e.errorCode == dds.DartDevelopmentServiceException.existingDdsInstanceError) {
|
|
try {
|
|
// First try to use the new field to avoid parsing from the message.
|
|
_existingDdsUri = e is dds.ExistingDartDevelopmentServiceException ? e.ddsUri : null;
|
|
|
|
// Otherwise, fall back to parsing from the exception (old DDS).
|
|
// This is not completely reliable which is why the new field above
|
|
// was added.
|
|
if (_existingDdsUri == null) {
|
|
String parsedUrl = e.message.split(' ').firstWhere((String e) => e.startsWith('http'));
|
|
// Trim trailing full stops from the message.
|
|
// https://github.com/flutter/flutter/issues/118609.
|
|
if (parsedUrl.endsWith('.')) {
|
|
parsedUrl = parsedUrl.substring(0, parsedUrl.length - 1);
|
|
}
|
|
_existingDdsUri ??= Uri.parse(parsedUrl);
|
|
}
|
|
} on StateError {
|
|
if (e.message.contains('Existing VM service clients prevent DDS from taking control.')) {
|
|
throwToolExit('${e.message}. Please rebuild your application with a newer version of Flutter.');
|
|
}
|
|
logger.printError(
|
|
'DDS has failed to start and there is not an existing DDS instance '
|
|
'available to connect to. Please file an issue at https://github.com/flutter/flutter/issues '
|
|
'with the following error message:\n\n ${e.message}.'
|
|
);
|
|
// DDS was unable to start for an unknown reason. Raise a StateError
|
|
// so it can be reported by the crash reporter.
|
|
throw StateError(e.message);
|
|
}
|
|
}
|
|
if (!_completer.isCompleted) {
|
|
_completer.complete();
|
|
}
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<void> shutdown() async => _ddsInstance?.shutdown();
|
|
|
|
void setExternalDevToolsUri(Uri uri) {
|
|
_ddsInstance?.setExternalDevToolsUri(uri);
|
|
}
|
|
}
|