LCOV - code coverage report
Current view: top level - crypto/utxo/repositories - json_rpc_client.dart (source / functions) Coverage Total Hit
Test: lcov.info Lines: 89.6 % 48 43
Test Date: 2025-01-30 01:10:00 Functions: - 0 0

            Line data    Source code
       1              : import 'dart:async';
       2              : import 'dart:convert';
       3              : import 'dart:io';
       4              : 
       5              : import 'package:walletkit_dart/src/domain/exceptions.dart';
       6              : 
       7              : abstract class JsonRpcClient {
       8              :   Future<void> connect(String host, int port);
       9              : 
      10              :   Future<bool> disconnect();
      11              : 
      12              :   Future<dynamic> sendRequest(Map<String, dynamic> procedure);
      13              : 
      14              :   Future<dynamic> sendRawRequest(Map<String, dynamic> procedure);
      15              : }
      16              : 
      17              : class TcpJsonRpcClient extends JsonRpcClient {
      18              :   final Completer<bool> _connected = Completer<bool>();
      19              : 
      20           39 :   Future<bool> get connected => _connected.future;
      21              : 
      22              :   final bool isZeniq;
      23              : 
      24              :   // final Random rand = Random();
      25              : 
      26              :   Socket? _socket;
      27              : 
      28           13 :   Socket get socket {
      29           39 :     if (_connected.isCompleted) return _socket!;
      30              :     throw const JsonRpcConnectionNotInitialized();
      31              :   }
      32              : 
      33              :   Stream? stream;
      34              : 
      35              :   final String host;
      36              :   final int port;
      37              : 
      38           13 :   TcpJsonRpcClient({
      39              :     this.isZeniq = false,
      40              :     required this.host,
      41              :     required this.port,
      42              :   }) {
      43           39 :     connect(host, port);
      44              :   }
      45              : 
      46           13 :   @override
      47              :   Future<void> connect(String host, int port) async {
      48              :     try {
      49           26 :       _socket = await Socket.connect(
      50              :         host,
      51              :         port,
      52              :         timeout: const Duration(seconds: 5),
      53              :       );
      54              : 
      55           39 :       stream = _socket!.asBroadcastStream();
      56              : 
      57           26 :       _connected.complete(true);
      58              :     } catch (e) {
      59           24 :       _connected.complete(false);
      60              :     }
      61              :   }
      62              : 
      63           13 :   @override
      64              :   Future<bool> disconnect() async {
      65              :     try {
      66           13 :       if (isZeniq) {
      67           16 :         await socket.flush();
      68              :       }
      69           26 :       await socket.flush();
      70           26 :       await socket.close();
      71              :     } catch (e) {
      72            0 :       print("$e");
      73              :       return true;
      74              :     }
      75              : 
      76              :     return true;
      77              :   }
      78              : 
      79           13 :   @override
      80              :   Future<dynamic> sendRequest(Map<String, dynamic> procedure) async {
      81              :     try {
      82           13 :       final rawResult = await sendRawRequest(procedure);
      83           13 :       final json = jsonDecode(rawResult);
      84           13 :       final result = json['result'];
      85              :       if (result == null) {
      86            0 :         final error = json['error'];
      87            0 :         final message = error['message'];
      88            0 :         throw Exception(message);
      89              :       }
      90              :       return result;
      91              :     } catch (e, _) {
      92              :       rethrow;
      93              :     }
      94              :   }
      95              : 
      96           13 :   @override
      97              :   Future<dynamic> sendRawRequest(Map<String, dynamic> procedure) async {
      98           26 :     final id = DateTime.now().millisecondsSinceEpoch;
      99           26 :     final procedureJson = jsonEncode({
     100           13 :       "id": id,
     101           13 :       ...procedure,
     102              :     });
     103              : 
     104              :     try {
     105           26 :       socket.writeln(procedureJson);
     106              :     } catch (e) {
     107              :       return null;
     108              :     }
     109              : 
     110           13 :     if (isZeniq) {
     111           16 :       await socket.flush();
     112              :     }
     113           26 :     await socket.flush();
     114              : 
     115              :     var txJson = "";
     116           39 :     await for (final uIntList in stream!) {
     117           26 :       txJson += String.fromCharCodes(uIntList);
     118           13 :       if (!isCompleteJson(txJson)) continue;
     119              :       return txJson;
     120              :     }
     121              : 
     122            0 :     throw Exception("Could not fetch result");
     123              :   }
     124              : }
     125              : 
     126           13 : bool isCompleteJson(String jsonString) {
     127              :   int numOpenCurly = 0;
     128              :   int numClosedCurly = 0;
     129              :   int numOpenSquare = 0;
     130              :   int numClosedSquare = 0;
     131              : 
     132           39 :   for (int i = 0; i < jsonString.length; i++) {
     133           13 :     switch (jsonString[i]) {
     134           13 :       case '{':
     135           13 :         numOpenCurly++;
     136              :         break;
     137           13 :       case '}':
     138           13 :         numClosedCurly++;
     139              :         break;
     140           13 :       case '[':
     141           10 :         numOpenSquare++;
     142              :         break;
     143           13 :       case ']':
     144           10 :         numClosedSquare++;
     145              :         break;
     146              :     }
     147              :   }
     148              : 
     149           26 :   return numOpenCurly == numClosedCurly && numOpenSquare == numClosedSquare;
     150              : }
        

Generated by: LCOV version 2.0-1