Merge pull request #357 from cypherstack/epicbox-failover

Epicbox failover - When epicbox server is down default to EU server
This commit is contained in:
Diego Salazar 2023-02-21 17:12:00 -07:00 committed by GitHub
commit 6ac856d31b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 606 additions and 326 deletions

View file

@ -6,7 +6,6 @@ import 'dart:isolate';
import 'package:decimal/decimal.dart'; import 'package:decimal/decimal.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter_libepiccash/epic_cash.dart'; import 'package:flutter_libepiccash/epic_cash.dart';
import 'package:http/http.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:mutex/mutex.dart'; import 'package:mutex/mutex.dart';
import 'package:stack_wallet_backup/generate_password.dart'; import 'package:stack_wallet_backup/generate_password.dart';
@ -37,6 +36,7 @@ import 'package:stackwallet/utilities/prefs.dart';
import 'package:stackwallet/utilities/stack_file_system.dart'; import 'package:stackwallet/utilities/stack_file_system.dart';
import 'package:stackwallet/utilities/test_epic_box_connection.dart'; import 'package:stackwallet/utilities/test_epic_box_connection.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
import 'package:websocket_universal/websocket_universal.dart';
const int MINIMUM_CONFIRMATIONS = 10; const int MINIMUM_CONFIRMATIONS = 10;
@ -462,6 +462,18 @@ class EpicCashWallet extends CoinServiceAPI
dynamic message; dynamic message;
String receiverAddress = txData['addresss'] as String; String receiverAddress = txData['addresss'] as String;
if (!receiverAddress.startsWith("http://") ||
!receiverAddress.startsWith("https://")) {
final decoded = json.decode(epicboxConfig);
bool isEpicboxConnected = await testEpicboxServer(
decoded["epicbox_domain"] as String,
decoded["epicbox_port"] as int);
if (!isEpicboxConnected) {
throw Exception("Failed to send TX : Unable to reach epicbox server");
}
}
await m.protect(() async { await m.protect(() async {
if (receiverAddress.startsWith("http://") || if (receiverAddress.startsWith("http://") ||
receiverAddress.startsWith("https://")) { receiverAddress.startsWith("https://")) {
@ -980,22 +992,75 @@ class EpicCashWallet extends CoinServiceAPI
return stringConfig; return stringConfig;
} }
Future<bool> testEpicboxServer(String host, int port) async {
final websocketConnectionUri = 'wss://$host:$port';
const connectionOptions = SocketConnectionOptions(
pingIntervalMs: 3000,
timeoutConnectionMs: 4000,
/// see ping/pong messages in [logEventStream] stream
skipPingMessages: true,
/// Set this attribute to `true` if do not need any ping/pong
/// messages and ping measurement. Default is `false`
pingRestrictionForce: false,
);
final IMessageProcessor<String, String> textSocketProcessor =
SocketSimpleTextProcessor();
final textSocketHandler = IWebSocketHandler<String, String>.createClient(
websocketConnectionUri,
textSocketProcessor,
connectionOptions: connectionOptions,
);
// Listening to server responses:
bool isConnected = true;
textSocketHandler.incomingMessagesStream.listen((inMsg) {
Logging.instance.log(
'> webSocket got text message from server: "$inMsg" '
'[ping: ${textSocketHandler.pingDelayMs}]',
level: LogLevel.Info);
});
// Connecting to server:
final isTextSocketConnected = await textSocketHandler.connect();
if (!isTextSocketConnected) {
// ignore: avoid_print
Logging.instance.log(
'Connection to [$websocketConnectionUri] failed for some reason!',
level: LogLevel.Error);
isConnected = false;
}
return isConnected;
}
Future<String> getEpicBoxConfig() async { Future<String> getEpicBoxConfig() async {
final storedConfig = String? storedConfig =
await _secureStore.read(key: '${_walletId}_epicboxConfig'); await _secureStore.read(key: '${_walletId}_epicboxConfig');
if (storedConfig != null) { if (storedConfig == null) {
final decoded = json.decode(storedConfig!); return json.encode(DefaultNodes.defaultEpicBoxConfig);
} else {
dynamic decoded = json.decode(storedConfig!);
final domain = decoded["domain"] ?? "empty"; final domain = decoded["domain"] ?? "empty";
if (domain != "empty") { if (domain != "empty") {
//If we have the old invalid config - update //If we have the old invalid config, use the new default one
await _secureStore.write( // new storage format stores domain under "epicbox_domain", old storage format used "domain"
key: '${_walletId}_epicboxConfig', storedConfig = DefaultNodes.defaultEpicBoxConfig;
value: DefaultNodes.defaultEpicBoxConfig); decoded = json.decode(storedConfig);
} }
return await _secureStore.read(key: '${_walletId}_epicboxConfig') ?? //Check Epicbox is up before returning it
DefaultNodes.defaultEpicBoxConfig; bool isEpicboxConnected = await testEpicboxServer(
decoded["epicbox_domain"] as String, decoded["epicbox_port"] as int);
if (!isEpicboxConnected) {
//Default Epicbox is not connected, Defaulting to Europe
storedConfig = json.encode(DefaultNodes.epicBoxConfigEUR);
// TODO test this connection before returning it, iterating through the list of default Epic Box servers
}
return storedConfig;
} }
return DefaultNodes.defaultEpicBoxConfig;
} }
Future<String> getRealConfig() async { Future<String> getRealConfig() async {

View file

@ -262,4 +262,11 @@ abstract class DefaultNodes {
"epicbox_protocol_unsecure": false, "epicbox_protocol_unsecure": false,
"epicbox_address_index": 0, "epicbox_address_index": 0,
}); });
static final String epicBoxConfigEUR = jsonEncode({
"epicbox_domain": "epicbox.fastepic.eu",
"epicbox_port": 443,
"epicbox_protocol_unsecure": false,
"epicbox_address_index": 0,
});
} }

File diff suppressed because it is too large Load diff

View file

@ -21,6 +21,7 @@ dependencies:
sdk: flutter sdk: flutter
ffi: ^2.0.1 ffi: ^2.0.1
mutex: ^3.0.0 mutex: ^3.0.0
websocket_universal: ^0.5.1
lelantus: lelantus:
path: ./crypto_plugins/flutter_liblelantus path: ./crypto_plugins/flutter_liblelantus