reconnect if needed in _checkRpcClient

with failovers
This commit is contained in:
sneurlax 2024-02-05 15:49:05 -06:00
parent 3ec6e2a008
commit 66354e8ecd
3 changed files with 71 additions and 9 deletions

View file

@ -202,7 +202,7 @@ class ElectrumXClient {
// ... But if the killswitch is set, then we throw an exception. // ... But if the killswitch is set, then we throw an exception.
throw Exception( throw Exception(
"Tor preference and killswitch set but Tor is not enabled, not connecting to ElectrumX"); "Tor preference and killswitch set but Tor is not enabled, not connecting to ElectrumX");
// TODO [prio=low]: Restart Tor. Update Tor package for restart feature. // TODO [prio=low]: Try to start Tor.
} }
} else { } else {
// Get the proxy info from the TorService. // Get the proxy info from the TorService.

View file

@ -69,9 +69,13 @@ class SubscribableElectrumXClient {
final Mutex _torConnectingLock = Mutex(); final Mutex _torConnectingLock = Mutex();
bool _requireMutex = false; bool _requireMutex = false;
List<ElectrumXNode>? failovers;
int currentFailoverIndex = -1;
SubscribableElectrumXClient({ SubscribableElectrumXClient({
required bool useSSL, required bool useSSL,
required Prefs prefs, required Prefs prefs,
required List<ElectrumXNode> failovers,
TorService? torService, TorService? torService,
this.onConnectionStatusChanged, this.onConnectionStatusChanged,
Duration connectionTimeout = const Duration(seconds: 5), Duration connectionTimeout = const Duration(seconds: 5),
@ -138,11 +142,13 @@ class SubscribableElectrumXClient {
factory SubscribableElectrumXClient.from({ factory SubscribableElectrumXClient.from({
required ElectrumXNode node, required ElectrumXNode node,
required Prefs prefs, required Prefs prefs,
required List<ElectrumXNode> failovers,
TorService? torService, TorService? torService,
}) { }) {
return SubscribableElectrumXClient( return SubscribableElectrumXClient(
useSSL: node.useSSL, useSSL: node.useSSL,
prefs: prefs, prefs: prefs,
failovers: failovers,
torService: torService ?? TorService.sharedInstance, torService: torService ?? TorService.sharedInstance,
); );
} }
@ -161,6 +167,57 @@ class SubscribableElectrumXClient {
// return client; // return client;
// } // }
/// Check if the RPC client is connected and connect if needed.
///
/// If Tor is enabled but not running, it will attempt to start Tor.
Future<void> _checkRpcClient() async {
if (_prefs.useTor) {
// If we're supposed to use Tor...
if (_torService.status != TorConnectionStatus.connected) {
// ... but Tor isn't running...
if (!_prefs.torKillSwitch) {
// ... and the killswitch isn't set, then we'll just return below.
Logging.instance.log(
"Tor preference set but Tor is not enabled, killswitch not set, connecting to ElectrumX through clearnet.",
level: LogLevel.Warning,
);
} else {
// ... but if the killswitch is set, then let's try to start Tor.
await _torService.start();
// TODO [prio=low]: Attempt to restart Tor if needed. Update Tor package for restart feature.
// Double-check that Tor is running.
if (_torService.status != TorConnectionStatus.connected) {
// If Tor still isn't running, then we'll throw an exception.
throw Exception("SubscribableElectrumXClient._checkRpcClient: "
"Tor preference and killswitch set but Tor not enabled and could not start, not connecting to ElectrumX.");
}
}
}
}
// Connect if needed.
if ((!_prefs.useTor && _socket == null) ||
(_prefs.useTor && _socksSocket == null)) {
if (currentFailoverIndex == -1) {
// Check if we have cached node information
if (_host == null && _port == null) {
throw Exception("SubscribableElectrumXClient._checkRpcClient: "
"No host or port provided and no cached node information.");
}
// Connect to the server.
await connect(host: _host!, port: _port!);
} else {
// Attempt to connect to the next failover server.
await connect(
host: failovers![currentFailoverIndex].address,
port: failovers![currentFailoverIndex].port,
);
}
}
}
/// Connect to the server. /// Connect to the server.
/// ///
/// If Tor is enabled, it will attempt to connect through Tor. /// If Tor is enabled, it will attempt to connect through Tor.
@ -179,8 +236,9 @@ class SubscribableElectrumXClient {
// If we're connecting to Tor, wait. // If we're connecting to Tor, wait.
if (_requireMutex) { if (_requireMutex) {
// Just use a dummy function that waits for the lock to be released. await _torConnectingLock.protect(() async => await _checkRpcClient());
await _torConnectingLock.protect(() async {}); } else {
await _checkRpcClient();
} }
if (!Prefs.instance.useTor) { if (!Prefs.instance.useTor) {
@ -509,8 +567,9 @@ class SubscribableElectrumXClient {
}) async { }) async {
// If we're connecting to Tor, wait. // If we're connecting to Tor, wait.
if (_requireMutex) { if (_requireMutex) {
// Just use a dummy function that waits for the lock to be released. await _torConnectingLock.protect(() async => await _checkRpcClient());
await _torConnectingLock.protect(() async {}); } else {
await _checkRpcClient();
} }
// Check socket is connected. // Check socket is connected.
@ -574,8 +633,9 @@ class SubscribableElectrumXClient {
}) async { }) async {
// If we're connecting to Tor, wait. // If we're connecting to Tor, wait.
if (_requireMutex) { if (_requireMutex) {
// Just use a dummy function that waits for the lock to be released. await _torConnectingLock.protect(() async => await _checkRpcClient());
await _torConnectingLock.protect(() async {}); } else {
await _checkRpcClient();
} }
// Check socket is connected. // Check socket is connected.
@ -728,8 +788,9 @@ class SubscribableElectrumXClient {
Future<bool> ping() async { Future<bool> ping() async {
// If we're connecting to Tor, wait. // If we're connecting to Tor, wait.
if (_requireMutex) { if (_requireMutex) {
// Just use a dummy function that waits for the lock to be released. await _torConnectingLock.protect(() async => await _checkRpcClient());
await _torConnectingLock.protect(() async {}); } else {
await _checkRpcClient();
} }
// Write to the socket. // Write to the socket.

View file

@ -948,6 +948,7 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
subscribableElectrumXClient = SubscribableElectrumXClient.from( subscribableElectrumXClient = SubscribableElectrumXClient.from(
node: newNode, node: newNode,
prefs: prefs, prefs: prefs,
failovers: failovers,
); );
await subscribableElectrumXClient.connect( await subscribableElectrumXClient.connect(
host: newNode.address, port: newNode.port); host: newNode.address, port: newNode.port);