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 _map = {}; final Map _heights = {}; final Map> _subscriptions = {}; final Map> _heightCompleters = {}; String _keyHelper(CryptoCurrency cryptoCurrency) { return "${cryptoCurrency.runtimeType}_${cryptoCurrency.network.name}"; } final Finalizer _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(); _subscriptions[key] = client.subscribeHeaders().listen((event) { _heights[key] = event.height; if (!_heightCompleters[key]!.isCompleted) { _heightCompleters[key]!.complete(event.height); } }); } Future getChainHeightFor(CryptoCurrency cryptoCurrency) async { final key = _keyHelper(cryptoCurrency); if (_map[key] == null) { throw Exception( "No managed ElectrumClient for $cryptoCurrency found.", ); } if (_heightCompleters[key] == null) { throw Exception( "No managed _heightCompleters for $cryptoCurrency found.", ); } return _heights[key] ?? await _heightCompleters[key]!.future; } Future 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 closeAll() async { await _kill(); _finalizer.detach(this); } Future _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(); } }