mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-21 06:18:42 +02:00
CW-974: Add support for automatic node switching. (#2361)
* feat: Add support for automatic node switching. This change: - Adds isTrustedNodeForSwitching property to Node class. - Adds UI Checkbox to mark a node as trusted for automatic switching in Node create or edit form. - Implements checkNodeHealth method in wallet classes to verify node connectivity. - Adds NodeSwitchingService for managing automatic node switching based on health checks. - Adds setting option for user to enable/disable automated node switching * fix(automatic-node-switch): Set node health check interval to 5 minutes in NodeSwitchingService * refactor: Update handler method * feat: Automatic Node Switching Improvements This change: - Moves enable automatic node switch to the Manage Nodes Page - Adds check to verify node health before attempting to sync in EVM, Sol and Tron Wallets. - Modifies trusted ndoes list for monero - Adds trigger for Node Health Check when app resumes from background * fix: Increase default request timeout for Tron and update health check interval for node switch * feat: Enhance Node health check functionality. This change adds additional checks for token balance in EVM, Solana and Tron Wallets in checkNodeHealth. * fix: Update health check interval to 30 seconds in NodeSwitchingService * Update bitcoin_electrum_server_list.yml * fix: Electru wallet not connecting to new node after switching * fix: Automated Node Switch not working on Decred Wallet * fix: Add more nodes for AutoSwitching This change: - Enables more nodes across wallet types for auto switching - Modifies CTA for checkbox - Renames flags to fit * fix: Add migration function for setting up default nodes for autoswitching * fix: Review and testing fixes * chore: Adjust balance and history fetch timer
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
import 'dart:async';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
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';
|
||||
|
||||
class NodeSwitchingService {
|
||||
NodeSwitchingService({
|
||||
required this.appStore,
|
||||
required this.settingsStore,
|
||||
required this.nodeSource,
|
||||
});
|
||||
|
||||
static const int _healthCheckIntervalSeconds = 30;
|
||||
|
||||
Timer? _healthCheckTimer;
|
||||
|
||||
bool _isSwitching = false;
|
||||
bool get isSwitching => _isSwitching;
|
||||
|
||||
final AppStore appStore;
|
||||
final SettingsStore settingsStore;
|
||||
final Box<Node> nodeSource;
|
||||
|
||||
// Track used nodes to cycle through all trusted nodes
|
||||
final Map<WalletType, List<dynamic>> _usedNodeKeys = {};
|
||||
|
||||
void startHealthCheckTimer() {
|
||||
_healthCheckTimer?.cancel();
|
||||
_healthCheckTimer = Timer.periodic(
|
||||
Duration(seconds: _healthCheckIntervalSeconds),
|
||||
(_) => performHealthCheck(),
|
||||
);
|
||||
|
||||
performHealthCheck();
|
||||
}
|
||||
|
||||
void stopHealthCheckTimer() {
|
||||
_healthCheckTimer?.cancel();
|
||||
_healthCheckTimer = null;
|
||||
}
|
||||
|
||||
Future<void> performHealthCheck() async {
|
||||
if (appStore.wallet == null) return;
|
||||
|
||||
if (!settingsStore.enableAutomaticNodeSwitching) return;
|
||||
|
||||
if (_isSwitching) return;
|
||||
|
||||
try {
|
||||
final isHealthy = await appStore.wallet!.checkNodeHealth();
|
||||
|
||||
if (!isHealthy) {
|
||||
await _switchToNextTrustedNode();
|
||||
}
|
||||
} catch (e) {
|
||||
printV('Error during health check: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Switch to the next available trusted node
|
||||
Future<void> _switchToNextTrustedNode() async {
|
||||
_isSwitching = true;
|
||||
|
||||
try {
|
||||
final walletType = appStore.wallet!.type;
|
||||
final currentNode = settingsStore.getCurrentNode(walletType);
|
||||
|
||||
// Get all trusted nodes for this wallet type
|
||||
final trustedNodes = nodeSource.values
|
||||
.where((node) => node.type == walletType && node.isEnabledForAutoSwitching)
|
||||
.toList();
|
||||
|
||||
if (trustedNodes.isEmpty) {
|
||||
printV('No trusted nodes available for switching');
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize used nodes list for this wallet type if it does not exist
|
||||
_usedNodeKeys.putIfAbsent(walletType, () => []);
|
||||
|
||||
// Add current node to used list if not already there
|
||||
if (!_usedNodeKeys[walletType]!.contains(currentNode.key)) {
|
||||
_usedNodeKeys[walletType]!.add(currentNode.key);
|
||||
}
|
||||
|
||||
// Get next unused trusted node from the list
|
||||
Node? nextNode;
|
||||
for (final node in trustedNodes) {
|
||||
if (!_usedNodeKeys[walletType]!.contains(node.key)) {
|
||||
nextNode = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If all trusted nodes have been used, reset the list and start over
|
||||
if (nextNode == null) {
|
||||
printV('All trusted nodes have been tried, resetting and starting over');
|
||||
_usedNodeKeys[walletType]!.clear();
|
||||
nextNode = trustedNodes.first;
|
||||
}
|
||||
|
||||
// Add the next node to used list
|
||||
_usedNodeKeys[walletType]!.add(nextNode.key);
|
||||
|
||||
printV('Switching from ${currentNode.uriRaw} to ${nextNode.uriRaw}');
|
||||
printV('Used nodes for ${walletType}: ${_usedNodeKeys[walletType]}');
|
||||
|
||||
// Update the current node in settings
|
||||
settingsStore.nodes[walletType] = nextNode;
|
||||
|
||||
// Connect the wallet to the new node
|
||||
await appStore.wallet!.connectToNode(node: nextNode);
|
||||
|
||||
await appStore.wallet!.startSync();
|
||||
|
||||
printV('Successfully switched to node: ${nextNode.uriRaw}');
|
||||
} catch (e) {
|
||||
printV('Error switching to next trusted node: $e');
|
||||
} finally {
|
||||
_isSwitching = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user