void _delegateRequest()

in pkg/vm_service/tool/dart/generate_dart.dart [690:1107]


    void _delegateRequest(Map<String, Object?> request) async {
      try {
        var id = request['id'];
        // Check if this is actually a response to a pending request.
        if (_pendingServiceExtensionRequests.containsKey(id)) {
          final pending = _pendingServiceExtensionRequests[id]!;
          pending.complete(Map<String, Object?>.of(request));
          return;
        }
        final method = request['method'] as String?;
        if (method == null) {
          throw RPCError(
            null, RPCError.kInvalidRequest, 'Invalid Request', request);
        }
        final params = request['params'] as Map<String, dynamic>?;
        late Response response;

        switch(method) {
          case 'registerService':
            $_registerServiceImpl
            break;
    ''');
    methods.forEach((m) {
      if (m.name != 'registerService') {
        gen.writeln("case '${m.name}':");
        if (m.name == 'streamListen') {
          gen.writeln(_streamListenCaseImpl);
        } else if (m.name == 'streamCancel') {
          gen.writeln(_streamCancelCaseImpl);
        } else {
          bool firstParam = true;
          final nullCheck = () {
            final result = firstParam ? '!' : '';
            if (firstParam) {
              firstParam = false;
            }
            return result;
          };
          if (m.deprecated) {
            gen.writeln("// ignore: deprecated_member_use_from_same_package");
          }
          gen.write("response = await _serviceImplementation.${m.name}(");
          // Positional args
          m.args.where((arg) => !arg.optional).forEach((MethodArg arg) {
            if (arg.type.isArray) {
              gen.write(
                  "${arg.type.listCreationRef}.from(params${nullCheck()}['${arg.name}'] ?? []), ");
            } else {
              gen.write("params${nullCheck()}['${arg.name}'], ");
            }
          });
          // Optional named args
          var namedArgs = m.args.where((arg) => arg.optional);
          if (namedArgs.isNotEmpty) {
            namedArgs.forEach((arg) {
              if (arg.name == 'scope') {
                gen.writeln(
                    "${arg.name}: params${nullCheck()}['${arg.name}']?.cast<String, String>(), ");
              } else {
                gen.writeln(
                    "${arg.name}: params${nullCheck()}['${arg.name}'], ");
              }
            });
          }
          gen.writeln(");");
        }
        gen.writeln('break;');
      }
    });
    // Handle service extensions
    gen.writeln('default:');
    gen.writeln('''
        final registeredClient = _serviceExtensionRegistry.clientFor(method);
        if (registeredClient != null) {
          // Check for any client which has registered this extension, if we
          // have one then delegate the request to that client.
          _responseSink.add(
              await registeredClient._forwardServiceExtensionRequest(request));
          // Bail out early in this case, we are just acting as a proxy and
          // never get a `Response` instance.
          return;
        } else if (method.startsWith('ext.')) {
          // Remaining methods with `ext.` are assumed to be registered via
          // dart:developer, which the service implementation handles.
          final args = params == null ? null : Map<String, dynamic>.of(params);
          final isolateId = args?.remove('isolateId');
          response = await _serviceImplementation.callServiceExtension(method,
              isolateId: isolateId, args: args);
        } else {
          throw RPCError(method, RPCError.kMethodNotFound, 'Method not found', request);
        }
''');
    // Terminate the switch
    gen.writeln('}');

    // Generate the json success response
    gen.write("""_responseSink.add({
  'jsonrpc': '2.0',
  'id': id,
  'result': response.toJson(),
});
""");

    // Close the try block, handle errors
    gen.write(r'''
      } catch (e, st) {
        final error = e is RPCError
            ? e.toMap()
            : {
                'code': RPCError.kInternalError,
                'message': '${request['method']}: $e',
                'data': {'details': '$st'},
              };
        _responseSink.add({
          'jsonrpc': '2.0',
          'id': request['id'],
          'error': error,
        });
      }
''');

    // terminate the _delegateRequest method
    gen.write('}');
    gen.writeln();

    gen.write('}');
    gen.writeln();

    gen.write('''
class _OutstandingRequest<T> {
  _OutstandingRequest(this.method);
  static int _idCounter = 0;
  final String id = '\${_idCounter++}';
  final String method;
  final StackTrace _stackTrace = StackTrace.current;
  final Completer<T> _completer = Completer<T>();

  Future<T> get future => _completer.future;

  void complete(T value) => _completer.complete(value);
  void completeError(Object error) =>
      _completer.completeError(error, _stackTrace);
}
''');

    // The client side service implementation.
    gen.writeStatement('class VmService implements VmServiceInterface {');
    gen.writeStatement('late final StreamSubscription _streamSub;');
    gen.writeStatement('late final Function _writeMessage;');
    gen.writeStatement(
        'final Map<String, _OutstandingRequest> _outstandingRequests = {};');
    gen.writeStatement('Map<String, ServiceCallback> _services = {};');
    gen.writeStatement('late final Log _log;');
    gen.write('''

StreamController<String> _onSend = StreamController.broadcast(sync: true);
StreamController<String> _onReceive = StreamController.broadcast(sync: true);

final Completer _onDoneCompleter = Completer();

Map<String, StreamController<Event>> _eventControllers = {};

StreamController<Event> _getEventController(String eventName) {
  StreamController<Event>? controller = _eventControllers[eventName];
  if (controller == null) {
    controller = StreamController.broadcast();
    _eventControllers[eventName] = controller;
  }
  return controller;
}

late final DisposeHandler? _disposeHandler;

VmService(Stream<dynamic> /*String|List<int>*/ inStream, void writeMessage(String message), {
  Log? log,
  DisposeHandler? disposeHandler,
  Future? streamClosed,
}) {
  _streamSub = inStream.listen(_processMessage, onDone: ()=> _onDoneCompleter.complete());
  _writeMessage = writeMessage;
  _log = log == null ? _NullLog() : log;
  _disposeHandler = disposeHandler;
  streamClosed?.then((_) {
    if (!_onDoneCompleter.isCompleted) {
      _onDoneCompleter.complete();
    }
  });
}

@override
Stream<Event> onEvent(String streamId) => _getEventController(streamId).stream;
''');

    // streamCategories
    streamCategories.forEach((s) => s.generate(gen));

    gen.writeln();
    methods.forEach((m) => m.generate(gen));
    gen.out(_implCode);
    gen.writeStatement('}');
    gen.writeln();
    gen.out(_rpcError);
    gen.writeln('// enums');
    enums.forEach((e) {
      if (e.name == 'EventKind') {
        _generateEventStream(gen);
      }
      e.generate(gen);
    });
    gen.writeln();
    gen.writeln('// types');
    types.where((t) => !t!.skip).forEach((t) => t!.generate(gen));
  }

  void generateAsserts(DartGenerator gen) {
    gen.out(r'''
// Copyright (c) 2015, 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.

// This is a generated file.

/// A library for asserting correct responses from the VM Service.

import 'package:vm_service/vm_service.dart' as vms;

dynamic assertNotNull(dynamic obj) {
  if (obj == null) throw 'assert failed';
  return obj;
}

bool assertBool(bool obj) {
  return obj;
}

int assertInt(int obj) {
  return obj;
}

double assertDouble(double obj) {
  return obj;
}

dynamic assertDynamic(dynamic obj) {
  assertNotNull(obj);
  return obj;
}

List<dynamic> assertListOfDynamic(List<dynamic> list) {
  return list;
}

List<int> assertListOfInt(List<int> list) {
  for (int elem in list) {
    assertInt(elem);
  }
  return list;
}

List<String> assertListOfString(List<String> list) {
  for (String elem in list) {
    assertString(elem);
  }
  return list;
}

List<vms.IsolateFlag> assertListOfIsolateFlag(List<vms.IsolateFlag> list) {
  for (vms.IsolateFlag elem in list) {
    assertIsolateFlag(elem);
  }
  return list;
}

String assertString(String obj) {
  if (obj.isEmpty) throw 'expected non-zero length string';
  return obj;
}

vms.Success assertSuccess(vms.Success obj) {
  if (obj.type != 'Success') throw 'expected Success';
  return obj;
}

/// Assert PauseStart, PauseExit, PauseBreakpoint, PauseInterrupted,
/// PauseException, Resume, BreakpointAdded, BreakpointResolved,
/// BreakpointRemoved, and Inspect events.
vms.Event assertDebugEvent(vms.Event event) {
  assertEvent(event);
  if (event.kind == vms.EventKind.kPauseBreakpoint ||
      event.kind == vms.EventKind.kBreakpointAdded ||
      event.kind == vms.EventKind.kBreakpointRemoved ||
      event.kind == vms.EventKind.kBreakpointResolved) {
    assertBreakpoint(event.breakpoint!);
  }
  if (event.kind == vms.EventKind.kPauseBreakpoint) {
    for (vms.Breakpoint elem in event.pauseBreakpoints!) {
      assertBreakpoint(elem);
    }
  }
  if (event.kind == vms.EventKind.kPauseBreakpoint ||
      event.kind == vms.EventKind.kPauseInterrupted ||
      event.kind == vms.EventKind.kPauseException ||
      event.kind == vms.EventKind.kResume) {
    // For PauseInterrupted events, there will be no top frame if the isolate is
    // idle (waiting in the message loop).
    // For the Resume event, the top frame is provided at all times except for
    // the initial resume event that is delivered when an isolate begins
    // execution.
    if (event.topFrame != null ||
        (event.kind != vms.EventKind.kPauseInterrupted &&
            event.kind != vms.EventKind.kResume)) {
      assertFrame(event.topFrame!);
    }
  }
  if (event.kind == vms.EventKind.kPauseException) {
    assertInstanceRef(event.exception!);
  }
  if (event.kind == vms.EventKind.kPauseBreakpoint ||
      event.kind == vms.EventKind.kPauseInterrupted) {
    assertBool(event.atAsyncSuspension!);
  }
  if (event.kind == vms.EventKind.kInspect) {
    assertInstanceRef(event.inspectee!);
  }
  return event;
}

/// Assert IsolateStart, IsolateRunnable, IsolateExit, IsolateUpdate,
/// and ServiceExtensionAdded events.
vms.Event assertIsolateEvent(vms.Event event) {
  assertEvent(event);
  if (event.kind == vms.EventKind.kServiceExtensionAdded) {
    assertString(event.extensionRPC!);
  }
  return event;
}

''');
    for (Enum e in enums) {
      e.generateAssert(gen);
    }
    for (Type? type in types) {
      if (type!.name == 'Success') continue;
      type.generateAssert(gen);
      if (type.name!.endsWith('Ref') ||
          [
            'BoundVariable',
            'Breakpoint',
            'ClassHeapStats',
            'CodeRegion',
            'ContextElement',
            'CpuSample',
            'Flag',
            'Frame',
            'InboundReference',
            'LibraryDependency',
            'Message',
            'ProcessMemoryItem',
            'ProfileFunction',
            'ProcessMemoryItem',
            'Protocol',
            'RetainingObject',
            'SourceReportRange',
            'TimelineEvent',
          ].contains(type.name)) {
        type.generateListAssert(gen);
      }
    }
  }

  void setDefaultValue(String typeName, String fieldName, String defaultValue) {
    types
        .firstWhere((t) => t!.name == typeName)!
        .fields
        .firstWhere((f) => f.name == fieldName)
        .defaultValue = defaultValue;
  }

  bool isEnumName(String? typeName) =>
      enums.any((Enum e) => e.name == typeName);

  Type? getType(String? name) =>
      types.firstWhere((t) => t!.name == name, orElse: () => null);

  void _parseStreamListenDocs(String docs) {
    Iterator<String> lines = docs.split('\n').map((l) => l.trim()).iterator;
    bool inStreamDef = false;

    while (lines.moveNext()) {
      final String line = lines.current;

      if (line.startsWith('streamId |')) {
        inStreamDef = true;
        lines.moveNext();
      } else if (inStreamDef) {
        if (line.isEmpty) {
          inStreamDef = false;
        } else {
          streamCategories.add(StreamCategory(line));
        }
      }
    }
  }

  void _generateEventStream(DartGenerator gen) {
    gen.writeln();
    gen.writeDocs('An enum of available event streams.');
    gen.writeln('class EventStreams {');
    gen.writeln('EventStreams._();');
    gen.writeln();

    streamCategories.forEach((c) {
      gen.writeln("static const String k${c.name} = '${c.name}';");
    });

    gen.writeln('}');
  }
}