import 'dart:convert'; import 'package:dio/dio.dart' as dio; import 'package:fis_common/http/http_error.dart'; import 'package:fis_jsonrpc/encrpyt.dart'; import 'package:flutter/foundation.dart'; import 'exception.dart'; import 'http_pool.dart'; import 'interceptor.dart'; import 'request.dart'; // ignore: unused_element const _C_DIO_FUTURE_ERR_MSG = "Future already completed"; const _C_DIO_FUTURE_ERR_KEYWORDS = "browser_adapter"; /// JSON-RPC Client 基类 class JsonRpcClientBase { /// 默认超时时间 // ignore: non_constant_identifier_names static int DEAULT_TIMEOUT = 15000; /// 请求加密配置 static JsonRpcEncryptConfig requestEncryptConfig = JsonRpcEncryptConfig(); /// 响应加密配置 static JsonRpcEncryptConfig responseEncryptConfig = JsonRpcEncryptConfig(); late int _timeout; late String _serviceName; /// 服务主机地址 final String host; /// 自定义Http header final Map? headers; /// 超时时间(ms) int get timeout => _timeout; /// 服务名称 String get serviceName => _serviceName; /// 服务请求地址 String get servicePath => host.endsWith('/') ? "$host$serviceName" : "$host/$serviceName"; JsonRpcClientBase( this.host, String serviceName, { this.headers, int? timeout, }) { _timeout = timeout ?? DEAULT_TIMEOUT; _serviceName = serviceName; } void setTimeout(int milliseconds) {} /// 设置服务名 void setServiceName(String name) => _serviceName = name; /// 请求RPC method @protected Future call(String method, [args]) async { var request = JsonRpcRequest(method, args); return _transmit(request); } /// 通知 RPC method @protected void notify(String method, [args]) { var request = JsonRpcRequest(method, args, notify: true); _transmit(request); } Future _transmit(JsonRpcRequest request) async { var result; try { final req = await jsonRpcInterceptHost.onRequestTransmit(request); String package = jsonEncode(req.toJson()); if (requestEncryptConfig.enable) { package = _encryptRequestPackage(package); } var response = await _postRequest(package); if (response == null) throw JsonRpcException(message: "Response Empty"); if (response is String) { response = jsonDecode(response); } result = await _handleDecoded(response); } catch (e) { if (e is FHttpError) await _handleHttpRequestError(JsonRpcNetworkException( e.toString(), null, request.method, )); throw JsonRpcException(message: "Http error", data: e); } return result; } Future _postRequest(String package) async { try { final httpClient = jrpcHttpPool.getClient( this.host, timeout: this.timeout, headers: this.headers, ); var response = await httpClient.post('/${this.serviceName}', data: package); if (response.statusCode != 200) { throw JsonRpcException( message: "Http error.Status coder: ${response.statusCode}."); } if (response.headers.containsKey("response_encrypt_mode")) { final resEncryptMode = response.headers["response_encrypt_mode"]!; // 解密响应包 if (resEncryptMode.isNotEmpty && resEncryptMode.first.isNotEmpty) { final resPackage = _decryptResponsePackage(response.data); final resJsonMap = jsonDecode(resPackage); return resJsonMap; } } return response.data; } on dio.DioError catch (e) { throw JsonRpcException(message: "Http error", data: e); } on StateError catch (e) { if (e.message == _C_DIO_FUTURE_ERR_MSG) { if (e.stackTrace != null && e.stackTrace.toString().contains(_C_DIO_FUTURE_ERR_KEYWORDS)) { // don't rethrow } } } } Future _handleHttpRequestError(JsonRpcNetworkException error) async { final res = await jsonRpcInterceptHost.onHttpRequestError(error); throw res; } Future _handleDecoded(Map response) async { final res = await jsonRpcInterceptHost.onResponse(response); if (res.containsKey('error')) { var error = JsonRpcServerError.fromJson(res['error']); error = await jsonRpcInterceptHost.onResponseError(error); throw error; } var result = res['result']; result = await jsonRpcInterceptHost.onResponseResult(result); return result; } String _encryptRequestPackage(String package) { final mode = requestEncryptConfig.encryptMode.toLowerCase(); if (kIsWeb) { return package; } if (mode == "sm2") { // 使用国密2加密请求 return JsonRpcEncryptUtils.sm2Encrypt( package, requestEncryptConfig.encryptKey, ); } if (mode == "rsa") { // 使用RSA加密请求 return JsonRpcEncryptUtils.rsaEncrypt(package); } return package; } String _decryptResponsePackage(String package) { final mode = responseEncryptConfig.encryptMode.toLowerCase(); if (mode == "sm4") { // 使用国密4解密 return JsonRpcEncryptUtils.sm4Decrypt( package, responseEncryptConfig.encryptKey, ); } if (mode == "des") { // 使用DES解密 // 截取前8位 final key = responseEncryptConfig.encryptKey.substring(0, 8); return JsonRpcEncryptUtils.desDecrypt(package, key); } return package; } } abstract class JsonRpcRequestModelBase { /// 转成Json Map Map toJson(); }