callServiceExtension method
Invoke a specific service protocol extension method.
See https://api.dart.dev/stable/dart-developer/dart-developer-library.html.
Implementation
@override
Future<Response> callServiceExtension(
String method, {
String? isolateId,
Map<String, dynamic>? args,
}) async {
// Fixture-serving short-circuit. When a fixture is
// configured, the binding's empty-tree observation is bypassed for
// exactly this one method; everything else falls through to the
// registry/extension routing below.
final Object? fx = observationFixture;
if (fx != null && method == _kObservationMethod) {
final Map<String, dynamic> body =
(fx as dynamic).body as Map<String, dynamic>;
final Response r = Response();
r.json = <String, dynamic>{'type': 'Observation', 'value': body};
return r;
}
final Map<String, String> stringArgs = <String, String>{
for (final MapEntry<String, dynamic> e
in (args ?? const <String, dynamic>{}).entries)
e.key: e.value is String ? e.value as String : jsonEncode(e.value),
};
// Route by registry, not by URL prefix. Extension tools (registered via
// ExtensionContext.registerExtension) live in extensionRegistry.mergedTools()
// keyed by '<ns>.<tool>'. Binding-owned extensions (handshake,
// get_stable_observation, get_recent_errors, screenshot,
// diagnostics_warnings) live in _extensionCallbacks and are reached
// via invokeServiceExtension. The 'core.*' URL prefix is NOT a
// routing signal — CoreExtension's per-tool extensions live in the
// registry, not in _extensionCallbacks.
const String prefix = 'ext.exploration.';
if (!method.startsWith(prefix)) {
throw RPCError(method, -32601, 'Unknown method "$method"');
}
final String suffix = method.substring(prefix.length);
final String body;
if (_binding.extensionRegistry.mergedTools().containsKey(suffix)) {
body = await _binding.invokeExtensionTool(method, stringArgs);
} else {
body = await _binding.invokeServiceExtension(method, stringArgs);
}
final Response r = Response();
r.json = jsonDecode(body) as Map<String, dynamic>;
return r;
}