blob: e572a347f3b5958e0927486105df5c90bad08732 [file] [log] [blame]
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:json_rpc_2/json_rpc_2.dart';
import '../constants.dart';
import '../dart_tooling_daemon.dart';
import '../response_types/response_types.dart';
import '../rpc_error_codes.dart';
/// Extension methods on the [DartToolingDaemon] that call the ConnectedApps
/// service.
extension ConnectedAppsExtension on DartToolingDaemon {
/// Registers a new VM service connection at [uri].
///
/// This is a privileged RPC that requires a [secret] to be called
/// successfully. This [secret] is generated by DTD at startup and provided to
/// the spawner of DTD only so that it is the only DTD client that can call
/// protected methods. If [secret] is invalid, an [RpcException] with error
/// code [RpcErrorCodes.kPermissionDenied] will be thrown.
///
/// [exposedUri] is the URI for the VM service connection that has been
/// exposed to the user/client machine if the backend VM service is running in
/// a different location (for example, an editor running in the user's browser
/// with the backend on a remote server).
///
/// Code that runs on the user/client machine (such as DevTools and DevTools
/// extensions) should prefer this URI (if provided) whereas code that also
/// runs on the backend (such as the debug adapter) should always use [uri].
///
/// [exposedUri] will be null or identical to [uri] in environments where
/// there is no exposing to do (for example, an editor running locally on the
/// same machine that the VM service is running).
///
/// [name] is the human-readable name for this VM service connection as
/// defined by the DTD client calling this method (e.g. 'Flutter - Pixel 5').
/// This is optional and may be null if the DTD client registering the VM
/// service does not have any useful naming information to provide.
///
/// If a VM service connection cannot be established for [uri], an
/// [RpcException] with error code [RpcErrorCodes.kConnectionFailed] will be
/// thrown.
///
/// When this method is called, a
/// [ConnectedAppServiceConstants.vmServiceRegistered] event will be sent over
/// the [ConnectedAppServiceConstants.serviceName] stream.
Future<Success> registerVmService({
required String uri,
required String secret,
String? exposedUri,
String? name,
}) {
return _callOnConnectedAppService<Success>(
ConnectedAppServiceConstants.registerVmService,
params: {
EventParameters.uri: uri,
EventParameters.secret: secret,
if (exposedUri != null) EventParameters.exposedUri: exposedUri,
if (name != null) EventParameters.name: name,
},
parseResponse: Success.fromDTDResponse,
);
}
/// Unregisters the VM service connection at [uri], if it exists.
///
/// If the VM service at [uri] was not already registered, this method does
/// nothing.
///
/// This is a privileged RPC that requires a [secret] to be called
/// successfully. This [secret] is generated by DTD at startup and provided to
/// the spawner of DTD only so that it is the only DTD client that can call
/// protected methods. If [secret] is invalid, an [RpcException] with error
/// code [RpcErrorCodes.kPermissionDenied] will be thrown.
///
/// When this method is called, a
/// [ConnectedAppServiceConstants.vmServiceUnregistered] event will be sent
/// over the [ConnectedAppServiceConstants.serviceName] stream.
Future<Success> unregisterVmService({
required String uri,
required String secret,
}) {
return _callOnConnectedAppService<Success>(
ConnectedAppServiceConstants.unregisterVmService,
params: {EventParameters.uri: uri, EventParameters.secret: secret},
parseResponse: Success.fromDTDResponse,
);
}
/// Returns a response containing information about the set of VM service
/// connections this DTD instance is aware of.
Future<VmServicesResponse> getVmServices() {
return _callOnConnectedAppService<VmServicesResponse>(
ConnectedAppServiceConstants.getVmServices,
parseResponse: VmServicesResponse.fromDTDResponse,
);
}
/// The stream of VM service update events.
///
/// Events sent over this stream will be of kind 'VmServiceRegistered'
/// or 'VmServiceUnregistered' and will contain the VM service URI they are
/// associated with.
///
/// A listener added to this [Stream] should be immediately followed by a
/// call to `streamListen(kConnectedAppServiceName)`, which will allow the
/// listener to start receiving events on this stream. Any events received
/// before the listener is added and `streamListen` is called will be dropeed.
Stream<DTDEvent> onVmServiceUpdate() {
return onEvent(ConnectedAppServiceConstants.serviceName);
}
Future<T> _callOnConnectedAppService<T>(
String methodName, {
Map<String, Object> params = const {},
required T Function(DTDResponse) parseResponse,
}) async {
final response = await call(
ConnectedAppServiceConstants.serviceName,
methodName,
params: params,
);
return parseResponse(response);
}
}