mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-17 05:41:29 +02:00
Improve Automatic Node Switching (#2596)
* feat: Enhance node switching logic with connectivity checks and attempt limits - Added connectivity checks before node health verification to ensure network availability. - Introduced maximum node switching attempts and cooldown periods to prevent excessive retries. * refactor: Improve node switch PR comments - Reduce cooldown time to 15 seconds - Combine increment code into one within the finally block --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
This commit is contained in:
co-authored by
Omar Hatem
parent
b0b053a19d
commit
c457a7fea6
@@ -5,6 +5,7 @@ import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
|
||||
class NodeSwitchingService {
|
||||
NodeSwitchingService({
|
||||
@@ -15,12 +16,16 @@ class NodeSwitchingService {
|
||||
|
||||
static const int _healthCheckIntervalSeconds = 30;
|
||||
|
||||
// The number of times we want to reset the overall used trusted nodes list.
|
||||
// We don't want an infinite loop if all trusted nodes are down.
|
||||
static const int _usedTrustedNodeResetCount = 1;
|
||||
// Maximum number of node switching attempts per session
|
||||
static const int _maxNodeSwitchingAttempts = 5;
|
||||
|
||||
// State to manage the reset count
|
||||
int _resetCount = 0;
|
||||
// Cooldown period between node switching attempts (in seconds)
|
||||
static const int _nodeSwitchingCooldownSeconds = 15;
|
||||
|
||||
// State to manage switching attempts and cooldown
|
||||
int _switchingAttempts = 0;
|
||||
DateTime? _lastSwitchingAttempt;
|
||||
bool _hasExhaustedAllNodes = false;
|
||||
|
||||
String walletName = '';
|
||||
|
||||
@@ -58,11 +63,45 @@ class NodeSwitchingService {
|
||||
|
||||
if (_isSwitching) return;
|
||||
|
||||
// Reset counters when wallet changes
|
||||
if (walletName.isNotEmpty && walletName != appStore.wallet!.name) {
|
||||
_resetSwitchingState();
|
||||
}
|
||||
walletName = appStore.wallet!.name;
|
||||
|
||||
// Check if we've exhausted all switching attempts
|
||||
if (_hasExhaustedAllNodes) {
|
||||
printV('Node switching exhausted for wallet: $walletName. Skipping health check.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check cooldown period
|
||||
if (_lastSwitchingAttempt != null) {
|
||||
final timeSinceLastAttempt = DateTime.now().difference(_lastSwitchingAttempt!);
|
||||
if (timeSinceLastAttempt.inSeconds < _nodeSwitchingCooldownSeconds) {
|
||||
printV('Node switching in cooldown period. Skipping health check.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Check network connectivity first
|
||||
final connectivityResult = await Connectivity().checkConnectivity();
|
||||
if (connectivityResult == ConnectivityResult.none) {
|
||||
printV('No network connectivity detected. Skipping node health check.');
|
||||
return;
|
||||
}
|
||||
|
||||
final isHealthy = await appStore.wallet!.checkNodeHealth();
|
||||
|
||||
if (!isHealthy) {
|
||||
printV('Node health check failed. Attempting to switch to next trusted node.');
|
||||
await _switchToNextTrustedNode();
|
||||
} else {
|
||||
// Reset switching attempts on successful health check
|
||||
_switchingAttempts = 0;
|
||||
_hasExhaustedAllNodes = false;
|
||||
printV('Node health check passed. Current node is healthy.');
|
||||
}
|
||||
} catch (e) {
|
||||
printV('Error during health check: $e');
|
||||
@@ -73,11 +112,15 @@ class NodeSwitchingService {
|
||||
Future<void> _switchToNextTrustedNode() async {
|
||||
_isSwitching = true;
|
||||
|
||||
if (walletName.isNotEmpty && (walletName != appStore.wallet!.name)) _resetCount = 0;
|
||||
|
||||
walletName = appStore.wallet!.name;
|
||||
|
||||
try {
|
||||
// Check if we've exceeded maximum switching attempts
|
||||
if (_switchingAttempts >= _maxNodeSwitchingAttempts) {
|
||||
printV('Maximum node switching attempts ($_maxNodeSwitchingAttempts) reached. '
|
||||
'Disabling automatic switching.');
|
||||
_hasExhaustedAllNodes = true;
|
||||
return;
|
||||
}
|
||||
|
||||
final walletType = appStore.wallet!.type;
|
||||
final currentNode = settingsStore.getCurrentNode(walletType);
|
||||
|
||||
@@ -88,6 +131,7 @@ class NodeSwitchingService {
|
||||
|
||||
if (trustedNodes.isEmpty) {
|
||||
printV('No trusted nodes available for switching');
|
||||
_hasExhaustedAllNodes = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -108,21 +152,27 @@ class NodeSwitchingService {
|
||||
}
|
||||
}
|
||||
|
||||
// If all trusted nodes have been used, reset the list and start over
|
||||
// If all trusted nodes have been used, check if we should reset
|
||||
if (nextNode == null) {
|
||||
printV('All trusted nodes have been tried, resetting and starting over');
|
||||
_resetCount++;
|
||||
printV('All trusted nodes have been tried for wallet type: $walletType');
|
||||
|
||||
if (_resetCount > _usedTrustedNodeResetCount) return;
|
||||
|
||||
_usedNodeKeys[walletType]!.clear();
|
||||
nextNode = trustedNodes.first;
|
||||
// If we've tried all nodes and still haven't reached max attempts, reset and try again
|
||||
if (_switchingAttempts < _maxNodeSwitchingAttempts) {
|
||||
printV('Resetting used nodes list and trying again');
|
||||
_usedNodeKeys[walletType]!.clear();
|
||||
nextNode = trustedNodes.first;
|
||||
} else {
|
||||
printV('Maximum attempts reached. No more node switching.');
|
||||
_hasExhaustedAllNodes = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the next node to used list
|
||||
_usedNodeKeys[walletType]!.add(nextNode.key);
|
||||
|
||||
printV('Switching from ${currentNode.uriRaw} to ${nextNode.uriRaw}');
|
||||
printV(
|
||||
'Switching from ${currentNode.uriRaw} to ${nextNode.uriRaw} (attempt $_switchingAttempts/$_maxNodeSwitchingAttempts)');
|
||||
printV('Used nodes for ${walletType}: ${_usedNodeKeys[walletType]}');
|
||||
|
||||
// Update the current node in settings
|
||||
@@ -137,7 +187,22 @@ class NodeSwitchingService {
|
||||
} catch (e) {
|
||||
printV('Error switching to next trusted node: $e');
|
||||
} finally {
|
||||
// Increment switching attempts counter on every attempt
|
||||
_switchingAttempts++;
|
||||
_lastSwitchingAttempt = DateTime.now();
|
||||
_isSwitching = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Reset switching state when wallet changes
|
||||
void _resetSwitchingState() {
|
||||
_switchingAttempts = 0;
|
||||
_lastSwitchingAttempt = null;
|
||||
_hasExhaustedAllNodes = false;
|
||||
_usedNodeKeys.clear();
|
||||
printV('Node switching state reset for new wallet');
|
||||
}
|
||||
|
||||
/// Check if automatic node switching is currently disabled due to exhaustion
|
||||
bool get isAutomaticSwitchingDisabled => _hasExhaustedAllNodes;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user