2024-04-18 23:17:45 +00:00
|
|
|
import 'dart:async';
|
|
|
|
|
|
|
|
import 'package:electrum_adapter/electrum_adapter.dart';
|
|
|
|
import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
|
|
|
|
|
|
|
|
class ClientManager {
|
|
|
|
ClientManager._();
|
|
|
|
static final ClientManager sharedInstance = ClientManager._();
|
|
|
|
|
|
|
|
final Map<String, ElectrumClient> _map = {};
|
|
|
|
final Map<String, int> _heights = {};
|
|
|
|
final Map<String, StreamSubscription<BlockHeader>> _subscriptions = {};
|
|
|
|
final Map<String, Completer<int>> _heightCompleters = {};
|
|
|
|
|
|
|
|
String _keyHelper(CryptoCurrency cryptoCurrency) {
|
|
|
|
return "${cryptoCurrency.runtimeType}_${cryptoCurrency.network.name}";
|
|
|
|
}
|
|
|
|
|
|
|
|
final Finalizer<ClientManager> _finalizer = Finalizer((manager) async {
|
|
|
|
await manager._kill();
|
|
|
|
});
|
|
|
|
|
|
|
|
ElectrumClient? getClient({
|
|
|
|
required CryptoCurrency cryptoCurrency,
|
|
|
|
}) =>
|
|
|
|
_map[_keyHelper(cryptoCurrency)];
|
|
|
|
|
|
|
|
void addClient(
|
|
|
|
ElectrumClient client, {
|
|
|
|
required CryptoCurrency cryptoCurrency,
|
|
|
|
}) {
|
|
|
|
final key = _keyHelper(cryptoCurrency);
|
|
|
|
if (_map[key] != null) {
|
|
|
|
throw Exception("ElectrumX Client for $key already exists.");
|
|
|
|
} else {
|
|
|
|
_map[key] = client;
|
|
|
|
}
|
|
|
|
|
|
|
|
_heightCompleters[key] = Completer<int>();
|
|
|
|
_subscriptions[key] = client.subscribeHeaders().listen((event) {
|
|
|
|
_heights[key] = event.height;
|
|
|
|
|
|
|
|
if (!_heightCompleters[key]!.isCompleted) {
|
|
|
|
_heightCompleters[key]!.complete(event.height);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<int> getChainHeightFor(CryptoCurrency cryptoCurrency) async {
|
|
|
|
final key = _keyHelper(cryptoCurrency);
|
|
|
|
|
|
|
|
if (_map[key] == null) {
|
|
|
|
throw Exception(
|
2024-04-25 21:54:40 +00:00
|
|
|
"No managed ElectrumClient for $key found.",
|
2024-04-18 23:17:45 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
if (_heightCompleters[key] == null) {
|
|
|
|
throw Exception(
|
2024-04-25 21:54:40 +00:00
|
|
|
"No managed _heightCompleters for $key found.",
|
2024-04-18 23:17:45 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return _heights[key] ?? await _heightCompleters[key]!.future;
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<ElectrumClient?> remove({
|
|
|
|
required CryptoCurrency cryptoCurrency,
|
|
|
|
}) async {
|
|
|
|
final key = _keyHelper(cryptoCurrency);
|
|
|
|
await _subscriptions[key]?.cancel();
|
|
|
|
_subscriptions.remove(key);
|
|
|
|
_heights.remove(key);
|
|
|
|
_heightCompleters.remove(key);
|
|
|
|
|
|
|
|
return _map.remove(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> closeAll() async {
|
|
|
|
await _kill();
|
|
|
|
_finalizer.detach(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> _kill() async {
|
|
|
|
for (final sub in _subscriptions.values) {
|
|
|
|
await sub.cancel();
|
|
|
|
}
|
|
|
|
for (final client in _map.values) {
|
|
|
|
await client.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
_heightCompleters.clear();
|
|
|
|
_heights.clear();
|
|
|
|
_subscriptions.clear();
|
|
|
|
_map.clear();
|
|
|
|
}
|
|
|
|
}
|