diff --git a/lib/g1/api.dart b/lib/g1/api.dart index a991d5dbc298dba3774da304b0ea3cac9893ccd6..640d7276de54c8580055f9f362b9049454283796 100644 --- a/lib/g1/api.dart +++ b/lib/g1/api.dart @@ -1,4 +1,5 @@ import 'dart:convert'; + // import 'dart:developer' as developer; import 'dart:io'; @@ -22,7 +23,7 @@ import 'g1_helper.dart'; Future<String> getTxHistory(String publicKey) async { final Response response = - await requestWithRetry(NodeType.duniter, '/tx/history/$publicKey'); + await requestWithRetry(NodeType.duniter, '/tx/history/$publicKey'); if (response.statusCode == 200) { return response.body; } else { @@ -54,14 +55,14 @@ Future<Contact> getProfile(String pubKey) async { '/user/profile/$pubKey', retryWith404: false); final Map<String, dynamic> result = - const JsonDecoder().convert(cPlusResponse.body) as Map<String, dynamic>; + const JsonDecoder().convert(cPlusResponse.body) as Map<String, dynamic>; if (result['found'] == false) { return Contact(pubKey: pubKey); } final String? nick = await gvaNick(pubKey); final Map<String, dynamic> profile = - const JsonDecoder().convert(cPlusResponse.body) as Map<String, dynamic>; + const JsonDecoder().convert(cPlusResponse.body) as Map<String, dynamic>; final Contact c = contactFromResultSearch(profile); logger('Contact retrieved in search $c'); @@ -91,7 +92,7 @@ Future<List<Contact>> searchWot(String searchTerm) async { final List<Contact> contacts = <Contact>[]; if (response.statusCode == HttpStatus.ok) { final Map<String, dynamic> data = - json.decode(response.body) as Map<String, dynamic>; + json.decode(response.body) as Map<String, dynamic>; final List<dynamic> results = data['results'] as List<dynamic>; // logger('Returning wot results ${results.length}'); if (results.isNotEmpty) { @@ -115,11 +116,11 @@ Future<Contact> getWot(Contact contact) async { // Will be better to analyze the 404 response (to detect faulty node) if (response.statusCode == HttpStatus.ok) { final Map<String, dynamic> data = - json.decode(response.body) as Map<String, dynamic>; + json.decode(response.body) as Map<String, dynamic>; final List<dynamic> results = data['results'] as List<dynamic>; if (results.isNotEmpty) { final List<dynamic> uids = - (results[0] as Map<String, dynamic>)['uids'] as List<dynamic>; + (results[0] as Map<String, dynamic>)['uids'] as List<dynamic>; if (uids.isNotEmpty) { // ignore: avoid_dynamic_calls return contact.copyWith(nick: uids[0]!['uid'] as String); @@ -132,14 +133,14 @@ Future<Contact> getWot(Contact contact) async { @Deprecated('use getProfile') Future<String> _getDataImageFromKey(String publicKey) async { final Response response = - await requestCPlusWithRetry('/user/profile/$publicKey'); + await requestCPlusWithRetry('/user/profile/$publicKey'); if (response.statusCode == HttpStatus.ok) { final Map<String, dynamic> data = - json.decode(response.body) as Map<String, dynamic>; + json.decode(response.body) as Map<String, dynamic>; final Map<String, dynamic> source = data['_source'] as Map<String, dynamic>; if (source.containsKey('avatar')) { final Map<String, dynamic> avatarData = - source['avatar'] as Map<String, dynamic>; + source['avatar'] as Map<String, dynamic>; if (avatarData.containsKey('_content')) { final String content = avatarData['_content'] as String; return 'data:image/png;base64,$content'; @@ -192,16 +193,18 @@ Future<void> fetchCesiumPlusNodes({bool force = false}) async { NodeManager().updateNodes(type, nodes); } -int nodesWorking(NodeType type) => NodeManager() - .nodeList(type) - .where((Node n) => n.errors < NodeManager.maxNodeErrors) - .toList() - .length; +int nodesWorking(NodeType type) => + NodeManager() + .nodeList(type) + .where((Node n) => n.errors < NodeManager.maxNodeErrors) + .toList() + .length; -List<Node> nodesWorkingList(NodeType type) => NodeManager() - .nodeList(type) - .where((Node n) => n.errors < NodeManager.maxNodeErrors) - .toList(); +List<Node> nodesWorkingList(NodeType type) => + NodeManager() + .nodeList(type) + .where((Node n) => n.errors < NodeManager.maxNodeErrors) + .toList(); Future<List<Node>> _fetchDuniterNodesFromPeers(NodeType type) async { final List<Node> lNodes = <Node>[]; @@ -213,14 +216,14 @@ Future<List<Node>> _fetchDuniterNodesFromPeers(NodeType type) async { final Response response = await getPeers(); if (response.statusCode == 200) { final Map<String, dynamic> peerList = - jsonDecode(response.body) as Map<String, dynamic>; + jsonDecode(response.body) as Map<String, dynamic>; final List<dynamic> peers = (peerList['peers'] as List<dynamic>) .where((dynamic peer) => - (peer as Map<String, dynamic>)['currency'] == 'g1') + (peer as Map<String, dynamic>)['currency'] == 'g1') .where( (dynamic peer) => (peer as Map<String, dynamic>)['version'] == 10) .where((dynamic peer) => - (peer as Map<String, dynamic>)['status'] == 'UP') + (peer as Map<String, dynamic>)['status'] == 'UP') .toList(); // reorder peer list peers.shuffle(); @@ -228,7 +231,7 @@ Future<List<Node>> _fetchDuniterNodesFromPeers(NodeType type) async { final Map<String, dynamic> peer = peerR as Map<String, dynamic>; if (peer['endpoints'] != null) { final List<String> endpoints = - List<String>.from(peer['endpoints'] as List<dynamic>); + List<String>.from(peer['endpoints'] as List<dynamic>); for (int j = 0; j < endpoints.length; j++) { if (endpoints[j].startsWith(apyType)) { final String endpointUnParsed = endpoints[j]; @@ -239,9 +242,10 @@ Future<List<Node>> _fetchDuniterNodesFromPeers(NodeType type) async { try { final Duration latency = await _pingNode(endpoint, type); logger( - 'Evaluating node: $endpoint, latency ${latency.inMicroseconds}'); + 'Evaluating node: $endpoint, latency ${latency + .inMicroseconds}'); final Node node = - Node(url: endpoint, latency: latency.inMicroseconds); + Node(url: endpoint, latency: latency.inMicroseconds); if (fastestNode == null || latency < fastestLatency) { fastestNode = endpoint; fastestLatency = latency; @@ -269,7 +273,8 @@ Future<List<Node>> _fetchDuniterNodesFromPeers(NodeType type) async { } } logger( - 'Fetched ${lNodes.length} ${type.name} nodes ordered by latency (first: ${lNodes.first.url})'); + 'Fetched ${lNodes.length} ${type + .name} nodes ordered by latency (first: ${lNodes.first.url})'); } catch (e, stacktrace) { logger('General error in fetch ${type.name} nodes: $e'); logger(stacktrace); @@ -313,7 +318,8 @@ Future<List<Node>> _fetchNodes(NodeType type) async { } logger( - 'Fetched ${lNodes.length} ${type.name} nodes ordered by latency (first: ${lNodes.first.url})'); + 'Fetched ${lNodes.length} ${type + .name} nodes ordered by latency (first: ${lNodes.first.url})'); } catch (e, stacktrace) { logger('General error in fetch ${type.name}: $e'); logger(stacktrace); @@ -325,18 +331,19 @@ Future<List<Node>> _fetchNodes(NodeType type) async { Future<Duration> _pingNode(String node, NodeType type) async { try { - final Stopwatch stopwatch = Stopwatch()..start(); + final Stopwatch stopwatch = Stopwatch() + ..start(); await http .get(Uri.parse(type == NodeType.duniter - ? '$node/network/peers/self/ping' - : type == NodeType.cesiumPlus - ? - // see: http://g1.data.e-is.pro/network/peering - '$node/network/peering' - : - // gva (just the url) - node)) - // Decrease http timeout during ping + ? '$node/network/peers/self/ping' + : type == NodeType.cesiumPlus + ? + // see: http://g1.data.e-is.pro/network/peering + '$node/network/peering' + : + // gva (just the url) + node)) + // Decrease http timeout during ping .timeout(const Duration(seconds: 10)); stopwatch.stop(); return stopwatch.elapsed; @@ -367,29 +374,30 @@ Future<http.Response> requestGvaWithRetry(String path, return _requestWithRetry(NodeType.gva, path, true, retryWith404); } -Future<http.Response> _requestWithRetry( - NodeType type, String path, bool dontRecord, bool retryWith404) async { - final List<Node> nodes = NodeManager().nodeList(type); +Future<http.Response> _requestWithRetry(NodeType type, String path, + bool dontRecord, bool retryWith404) async { + final List<Node> nodes = NodeManager().nodeList(type).where(( + Node node) => node.errors <= NodeManager.maxNodeErrors).toList(); if (nodes.isEmpty) { nodes.addAll(type == NodeType.duniter ? defaultDuniterNodes : type == NodeType.cesiumPlus - ? defaultCesiumPlusNodes - : defaultGvaNodes); + ? defaultCesiumPlusNodes + : defaultGvaNodes); } for (int i = 0; i < nodes.length; i++) { final Node node = nodes[i]; - if (node.errors >= NodeManager.maxNodeErrors) { - logger('Too much errors skip ${node.url}'); - continue; - } try { final Uri url = Uri.parse('${node.url}$path'); logger('Fetching $url (${type.name})'); - final int startTime = DateTime.now().millisecondsSinceEpoch; + final int startTime = DateTime + .now() + .millisecondsSinceEpoch; final Response response = - await http.get(url).timeout(const Duration(seconds: 10)); - final int endTime = DateTime.now().millisecondsSinceEpoch; + await http.get(url).timeout(const Duration(seconds: 10)); + final int endTime = DateTime + .now() + .millisecondsSinceEpoch; final int newLatency = endTime - startTime; if (!kReleaseMode) { logger('response.statusCode: ${response.statusCode}'); @@ -463,7 +471,8 @@ String getGvaNode([bool useProxy = true]) { nodes.shuffle(); // Reference of working proxy 'https://g1demo.comunes.net/proxy/g1v1.p2p.legal/gva/'; final String node = useProxy - ? 'https://g1demo.comunes.net/proxy/${nodes.first.url.replaceFirst('https://', '').replaceFirst('http://', '')}/' + ? 'https://g1demo.comunes.net/proxy/${nodes.first.url.replaceFirst( + 'https://', '').replaceFirst('http://', '')}/' : nodes.first.url; return node; } else { @@ -485,18 +494,18 @@ Future<String?> gvaNick(String pubKey) async { pubKey, (Gva gva) => gva.getUsername(pubKey)); } -Future<T?> gvaFunctionWrapper<T>( - String pubKey, Future<T?> Function(Gva) specificFunction) async { - final List<Node> nodes = NodeManager().nodeList(NodeType.gva); +Future<T?> gvaFunctionWrapper<T>(String pubKey, + Future<T?> Function(Gva) specificFunction) async { + final List<Node> nodes = NodeManager() + .nodeList(NodeType.gva) + .where((Node node) => node.errors <= NodeManager.maxNodeErrors) + .toList(); if (nodes.isEmpty) { nodes.addAll(defaultGvaNodes); } for (int i = 0; i < nodes.length; i++) { final Node node = nodes[i]; - if (node.errors >= NodeManager.maxNodeErrors) { - logger('Too much errors skip ${node.url}'); - continue; - } + try { final String output = getGvaNode(); if (Uri.tryParse(output) != null) {