| // Copyright 2013 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. |
| |
| // ignore_for_file: avoid_print |
| |
| import 'dart:async'; |
| import 'dart:convert'; |
| import 'dart:io'; |
| |
| class ServiceClient { |
| ServiceClient( |
| this.client, { |
| this.isolateStartedId, |
| this.isolatePausedId, |
| this.isolateResumeId, |
| }) { |
| client.listen(_onData, onError: _onError, cancelOnError: true); |
| } |
| |
| Completer<Object?>? isolateStartedId; |
| Completer<Object?>? isolatePausedId; |
| Completer<Object?>? isolateResumeId; |
| |
| Future<Map<String, Object?>> invokeRPC( |
| String method, [ |
| Map<String, Object?>? params, |
| ]) async { |
| final String key = _createKey(); |
| final String request = json.encode({ |
| 'jsonrpc': '2.0', |
| 'method': method, |
| 'params': params ?? <String, Object?>{}, |
| 'id': key, |
| }); |
| client.add(request); |
| final completer = Completer<Map<String, Object?>>(); |
| _outstandingRequests[key] = completer; |
| print('-> $key ($method)'); |
| return completer.future; |
| } |
| |
| String _createKey() { |
| final String key = '$_id'; |
| _id++; |
| return key; |
| } |
| |
| void _onData(dynamic message) { |
| final response = json.decode(message as String) as Map<String, Object?>; |
| final dynamic key = response['id']; |
| if (key != null) { |
| print('<- $key'); |
| final completer = _outstandingRequests.remove(key)!; |
| final result = response['result']; |
| final error = response['error']; |
| if (error != null) { |
| completer.completeError(error); |
| } else { |
| completer.complete(result); |
| } |
| } else { |
| if (response['method'] == 'streamNotify') { |
| _onServiceEvent(response['params'] as Map<String, Object?>?); |
| } |
| } |
| } |
| |
| void _onServiceEvent(Map<String, Object?>? params) { |
| if (params == null) { |
| return; |
| } |
| final event = params['event'] as Map<String, Object?>?; |
| if (event == null || event['type'] != 'Event') { |
| return; |
| } |
| final dynamic isolateId = (event['isolate']! as Map<String, Object?>)['id']; |
| switch (params['streamId']) { |
| case 'Isolate': |
| if (event['kind'] == 'IsolateStart') { |
| isolateStartedId?.complete(isolateId); |
| } |
| case 'Debug': |
| switch (event['kind']) { |
| case 'Resume': |
| isolateResumeId?.complete(isolateId); |
| case 'PauseStart': |
| isolatePausedId?.complete(isolateId); |
| } |
| } |
| } |
| |
| void _onError(dynamic error) { |
| print('WebSocket error: $error'); |
| } |
| |
| final WebSocket client; |
| final _outstandingRequests = <String, Completer<dynamic>>{}; |
| int _id = 1; |
| } |