Skip to content
Snippets Groups Projects
Commit 8778fec8 authored by vjrj's avatar vjrj
Browse files

Improved retry

parent ae40fd6a
No related branches found
No related tags found
No related merge requests found
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) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment