| // 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); |
| } |
| } |