From b975061a6701a6d5ccfae519dd5e7f47e5e92f55 Mon Sep 17 00:00:00 2001 From: poka Date: Sat, 16 Jul 2022 21:03:40 +0200 Subject: [PATCH] change indexer endpoint in settings --- lib/main.dart | 8 +- lib/providers/duniter_indexer.dart | 98 +++++-- lib/screens/home.dart | 8 +- lib/screens/settings.dart | 395 +++++++++++++++++++---------- 4 files changed, 340 insertions(+), 169 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 5517851..148d336 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -60,12 +60,16 @@ Future main() async { } HomeProvider _homeProvider = HomeProvider(); - DuniterIndexer _duniterIndexer = DuniterIndexer(); + // DuniterIndexer _duniterIndexer = DuniterIndexer(); await initHiveForFlutter(); await _homeProvider.initHive(); appVersion = await _homeProvider.getAppVersion(); prefs = await SharedPreferences.getInstance(); + // Reset GraphQL cache + final cache = HiveStore(); + cache.reset(); + // Configure Hive and open boxes Hive.registerAdapter(WalletDataAdapter()); Hive.registerAdapter(ChestDataAdapter()); @@ -85,8 +89,6 @@ Future main() async { } // log.d(await configBox.get('endpoint')); - _duniterIndexer.getValidIndexerEndpoint(); - HttpOverrides.global = MyHttpOverrides(); if (kReleaseMode && enableSentry) { diff --git a/lib/providers/duniter_indexer.dart b/lib/providers/duniter_indexer.dart index 26c8c5f..62aadbe 100644 --- a/lib/providers/duniter_indexer.dart +++ b/lib/providers/duniter_indexer.dart @@ -22,41 +22,82 @@ class DuniterIndexer with ChangeNotifier { int nPage = 1; int nRepositories = 20; List? transBC; + List listIndexerEndpoints = []; + bool isLoadingIndexer = false; void reload() { notifyListeners(); } - Future checkIndexerEndpoint() async { - final oldEndpoint = indexerEndpoint; - while (true) { - await Future.delayed(const Duration(seconds: 30)); - final _client = HttpClient(); - _client.connectionTimeout = const Duration(milliseconds: 4000); - try { - final request = - await _client.postUrl(Uri.parse('$oldEndpoint/v1/graphql')); - final response = await request.close(); - if (response.statusCode != 200) { - log.d('INDEXER IS OFFILINE'); - indexerEndpoint = ''; - } else { - // log.d('Indexer is online'); - indexerEndpoint = oldEndpoint; - } - } catch (e) { + Future checkIndexerEndpoint(String endpoint) async { + isLoadingIndexer = true; + notifyListeners(); + final _client = HttpClient(); + _client.connectionTimeout = const Duration(milliseconds: 4000); + try { + final request = await _client.postUrl(Uri.parse('$endpoint/v1/graphql')); + final response = await request.close(); + if (response.statusCode != 200) { log.d('INDEXER IS OFFILINE'); indexerEndpoint = ''; + isLoadingIndexer = false; + notifyListeners(); + return false; + } else { + indexerEndpoint = endpoint; + await configBox.put('indexerEndpoint', endpoint); + // await configBox.put('customEndpoint', endpoint); + isLoadingIndexer = false; + notifyListeners(); + final cache = HiveStore(); + cache.reset(); + return true; } + } catch (e) { + log.d('INDEXER IS OFFILINE'); + indexerEndpoint = ''; + isLoadingIndexer = false; + notifyListeners(); + return false; } } + // Future checkIndexerEndpointBackground() async { + // final oldEndpoint = indexerEndpoint; + // while (true) { + // await Future.delayed(const Duration(seconds: 30)); + // final isValid = await checkIndexerEndpoint(oldEndpoint); + // if (!isValid) { + // log.d('INDEXER IS OFFILINE'); + // indexerEndpoint = ''; + // } else { + // // log.d('Indexer is online'); + // indexerEndpoint = oldEndpoint; + // } + // } + // } + Future getValidIndexerEndpoint() async { - List _listEndpoints = await rootBundle + // await configBox.delete('indexerEndpoint'); + + listIndexerEndpoints = await rootBundle .loadString('config/indexer_endpoints.json') .then((jsonStr) => jsonDecode(jsonStr)); // _listEndpoints.shuffle(); + log.d(listIndexerEndpoints); + + if (configBox.containsKey('customIndexer')) { + // return configBox.get('customIndexer'); + listIndexerEndpoints.insert(0, configBox.get('customIndexer')); + } + + if (configBox.containsKey('indexerEndpoint')) { + if (await checkIndexerEndpoint(configBox.get('indexerEndpoint'))) { + return configBox.get('indexerEndpoint'); + } + } + int i = 0; // String _endpoint = ''; int _statusCode = 0; @@ -65,25 +106,28 @@ class DuniterIndexer with ChangeNotifier { _client.connectionTimeout = const Duration(milliseconds: 3000); do { - int listLenght = _listEndpoints.length; + int listLenght = listIndexerEndpoints.length; if (i >= listLenght) { log.e('NO VALID INDEXER ENDPOINT FOUND'); indexerEndpoint = ''; break; } - log.d( - (i + 1).toString() + 'n indexer endpoint try: ${_listEndpoints[i]}'); + log.d((i + 1).toString() + + 'n indexer endpoint try: ${listIndexerEndpoints[i]}'); if (i != 0) { await Future.delayed(const Duration(milliseconds: 300)); } try { - final request = - await _client.postUrl(Uri.parse('${_listEndpoints[i]}/v1/graphql')); + String endpointPath = '${listIndexerEndpoints[i]}/v1/graphql'; + + final request = await _client.postUrl(Uri.parse(endpointPath)); final response = await request.close(); - indexerEndpoint = _listEndpoints[i]; + indexerEndpoint = listIndexerEndpoints[i]; + await configBox.put('indexerEndpoint', listIndexerEndpoints[i]); + _statusCode = response.statusCode; i++; } on TimeoutException catch (_) { @@ -202,13 +246,15 @@ class DuniterIndexer with ChangeNotifier { return const Text('Aucun résultat'); } + log.d(indexerEndpoint); final _httpLink = HttpLink( '$indexerEndpoint/v1/graphql', ); final _client = ValueNotifier( GraphQLClient( - cache: GraphQLCache(store: HiveStore()), + cache: GraphQLCache( + store: HiveStore()), // GraphQLCache(store: HiveStore()) link: _httpLink, ), ); diff --git a/lib/screens/home.dart b/lib/screens/home.dart index 58468b3..26c75f4 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -107,6 +107,10 @@ class HomeScreen extends StatelessWidget { builder: (ctx) => StatefulWrapper( onInit: () { WidgetsBinding.instance.addPostFrameCallback((_) async { + DuniterIndexer _duniterIndexer = + Provider.of(ctx, listen: false); + _duniterIndexer.getValidIndexerEndpoint(); + if (!_sub.sdkReady && !_sub.sdkLoading) await _sub.initApi(); if (_sub.sdkReady && !_sub.nodeConnected) { // Check if versionData non compatible, drop everything @@ -147,9 +151,7 @@ class HomeScreen extends StatelessWidget { } }); } - DuniterIndexer _duniterIndexer = - Provider.of(ctx, listen: false); - _duniterIndexer.checkIndexerEndpoint(); + // _duniterIndexer.checkIndexerEndpointBackground(); }); }, child: isWalletsExists ? geckHome(context) : welcomeHome(context) diff --git a/lib/screens/settings.dart b/lib/screens/settings.dart index 83f6fb5..80ff60e 100644 --- a/lib/screens/settings.dart +++ b/lib/screens/settings.dart @@ -1,13 +1,14 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:gecko/providers/duniter_indexer.dart'; import 'package:gecko/providers/my_wallets.dart'; import 'package:gecko/providers/settings_provider.dart'; import 'package:gecko/providers/substrate_sdk.dart'; import 'package:gecko/globals.dart'; import 'package:polkawallet_sdk/api/types/networkParams.dart'; import 'package:provider/provider.dart'; -import 'package:dropdown_button2/dropdown_button2.dart'; +// import 'package:dropdown_button2/dropdown_button2.dart'; // ignore: must_be_immutable class SettingsScreen extends StatelessWidget { @@ -15,18 +16,61 @@ class SettingsScreen extends StatelessWidget { SettingsScreen({Key? key}) : super(key: key); - // Initial Selected Value - String? selectedDuniterEndpoint; - @override Widget build(BuildContext context) { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); - SubstrateSdk _sub = Provider.of(context, listen: false); const double buttonHigh = 50; const double buttonWidth = 240; const double fontSize = 16; + return Scaffold( + backgroundColor: backgroundColor, + appBar: AppBar( + toolbarHeight: 60 * ratio, + title: SizedBox( + height: 22, + child: Text('parameters'.tr()), + )), + body: Column(children: [ + const SizedBox(height: 30), + duniterEndpointSelection(context), + const SizedBox(height: 50), + indexerEndpointSelection(context), + + // SizedBox(height: isTall ? 80 : 120), + const Spacer(), + SizedBox( + height: buttonHigh, + width: buttonWidth, + child: Center( + child: InkWell( + key: const Key('deleteChest'), + onTap: () async { + log.i('Oublier tous mes coffres'); + await _myWallets.deleteAllWallet(context); + }, + child: Text( + 'forgetAllMyChests'.tr(), + style: const TextStyle( + fontSize: fontSize + 4, + color: Color(0xffD80000), + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ), + // const Spacer(), + SizedBox(height: isTall ? 90 : 60), + ]), + ); + } + + Widget duniterEndpointSelection(BuildContext context) { + SubstrateSdk _sub = Provider.of(context, listen: false); + String? selectedDuniterEndpoint; + // List of items in our dropdown menu var duniterBootstrapNodes = _sub.getDuniterBootstrap(); selectedDuniterEndpoint = @@ -56,147 +100,224 @@ class SettingsScreen extends StatelessWidget { ? configBox.get('customEndpoint') : 'wss://'); - return Scaffold( - backgroundColor: backgroundColor, - appBar: AppBar( - toolbarHeight: 60 * ratio, - title: SizedBox( - height: 22, - child: Text('parameters'.tr()), - )), - body: Column(children: [ - const SizedBox(height: 60), - - Row(children: [ - Consumer(builder: (context, _sub, _) { - log.d(_sub.sdk.api.connectedNode?.endpoint); - return Expanded( - child: Row(children: [ - const SizedBox(width: 10), - Text('currencyNode'.tr(args: [currencyName])), - const Spacer(), - Icon(_sub.nodeConnected && !_sub.isLoadingEndpoint - ? Icons.check - : Icons.close), - const Spacer(), - Consumer(builder: (context, _set, _) { - return DropdownButtonHideUnderline( - child: DropdownButton( - // alignment: AlignmentDirectional.topStart, - value: selectedDuniterEndpoint, - icon: const Icon(Icons.keyboard_arrow_down), - items: duniterBootstrapNodes - .map((NetworkParams _endpointParams) { - return DropdownMenuItem( - value: _endpointParams.endpoint, - child: Text(_endpointParams.endpoint!), - ); - }).toList(), - onChanged: (String? _newEndpoint) { - log.d(_newEndpoint!); - selectedDuniterEndpoint = _newEndpoint; - _set.reload(); - }, - ), - ); - }), - const Spacer(flex: 5), - _sub.isLoadingEndpoint - ? CircularProgressIndicator(color: orangeC) - : Consumer(builder: (context, _set, _) { - return IconButton( - icon: Icon( - Icons.send, - color: selectedDuniterEndpoint != - _sub.getConnectedEndpoint() - ? orangeC - : Colors.grey[500], - size: 40, - ), - onPressed: selectedDuniterEndpoint != + return Column(children: [ + Row(children: [ + Consumer(builder: (context, _sub, _) { + log.d(_sub.sdk.api.connectedNode?.endpoint); + return Expanded( + child: Row(children: [ + const SizedBox(width: 10), + Text('currencyNode'.tr(args: [currencyName])), + const Spacer(), + Icon(_sub.nodeConnected && !_sub.isLoadingEndpoint + ? Icons.check + : Icons.close), + const Spacer(), + Consumer(builder: (context, _set, _) { + return DropdownButtonHideUnderline( + child: DropdownButton( + // alignment: AlignmentDirectional.topStart, + value: selectedDuniterEndpoint, + icon: const Icon(Icons.keyboard_arrow_down), + items: duniterBootstrapNodes + .map((NetworkParams _endpointParams) { + return DropdownMenuItem( + value: _endpointParams.endpoint, + child: Text(_endpointParams.endpoint!), + ); + }).toList(), + onChanged: (String? _newEndpoint) { + log.d(_newEndpoint!); + selectedDuniterEndpoint = _newEndpoint; + _set.reload(); + }, + ), + ); + }), + const Spacer(flex: 5), + _sub.isLoadingEndpoint + ? CircularProgressIndicator(color: orangeC) + : Consumer(builder: (context, _set, _) { + return IconButton( + icon: Icon( + Icons.send, + color: selectedDuniterEndpoint != _sub.getConnectedEndpoint() - ? () async { - if (selectedDuniterEndpoint == 'Auto') { - configBox.delete('customEndpoint'); - configBox.put('autoEndpoint', true); - } else { - configBox.put('autoEndpoint', false); - final finalEndpoint = - selectedDuniterEndpoint == - 'Personnalisé' - ? _endpointController.text - : selectedDuniterEndpoint; - configBox.put( - 'customEndpoint', finalEndpoint); - } - await _sub.connectNode(context); + ? orangeC + : Colors.grey[500], + size: 40, + ), + onPressed: selectedDuniterEndpoint != + _sub.getConnectedEndpoint() + ? () async { + if (selectedDuniterEndpoint == 'Auto') { + configBox.delete('customEndpoint'); + configBox.put('autoEndpoint', true); + } else { + configBox.put('autoEndpoint', false); + final finalEndpoint = + selectedDuniterEndpoint == + 'Personnalisé' + ? _endpointController.text + : selectedDuniterEndpoint; + configBox.put( + 'customEndpoint', finalEndpoint); } - : null); - }), - const Spacer(flex: 8), - ]), - ); - }), - ]), - Consumer(builder: (context, _set, _) { + await _sub.connectNode(context); + } + : null); + }), + const Spacer(flex: 8), + ]), + ); + }), + ]), + Consumer(builder: (context, _set, _) { + return Visibility( + visible: selectedDuniterEndpoint == 'Personnalisé', + child: SizedBox( + width: 200, + height: 50, + child: TextField( + controller: _endpointController, + autocorrect: false, + ), + ), + ); + }), + Consumer(builder: (context, _sub, _) { + return Consumer(builder: (context, _set, _) { return Visibility( - visible: selectedDuniterEndpoint == 'Personnalisé', + visible: selectedDuniterEndpoint == 'Auto', child: SizedBox( - width: 200, - height: 50, - child: TextField( - controller: _endpointController, - autocorrect: false, + width: 250, + height: _sub.getConnectedEndpoint() == null ? 60 : 20, + child: Text( + _sub.getConnectedEndpoint() ?? + "Un noeud sûr et valide sera choisi automatiquement parmis une liste aléatoire.", + style: TextStyle( + fontSize: 15, + fontStyle: FontStyle.italic, + color: Colors.grey[700]), ), ), ); - }), - Consumer(builder: (context, _sub, _) { - return Consumer(builder: (context, _set, _) { - return Visibility( - visible: selectedDuniterEndpoint == 'Auto', - child: SizedBox( - width: 250, - height: 60, - child: Text( - _sub.getConnectedEndpoint() ?? - "Un noeud sûr et valide sera choisi automatiquement parmis une liste aléatoire.", - style: TextStyle( - fontSize: 15, - fontStyle: FontStyle.italic, - color: Colors.grey[700]), - ), - ), - ); - }); - }), + }); + }), + ]); + } - // SizedBox(height: isTall ? 80 : 120), - const Spacer(), - SizedBox( - height: buttonHigh, - width: buttonWidth, - child: Center( - child: InkWell( - key: const Key('deleteChest'), - onTap: () async { - log.i('Oublier tous mes coffres'); - await _myWallets.deleteAllWallet(context); - }, - child: Text( - 'forgetAllMyChests'.tr(), - style: const TextStyle( - fontSize: fontSize + 4, - color: Color(0xffD80000), - fontWeight: FontWeight.w600, - ), - ), + Widget indexerEndpointSelection(BuildContext context) { + DuniterIndexer _indexer = + Provider.of(context, listen: false); + + String? selectedIndexerEndpoint; + if (configBox.containsKey('customIndexer')) { + selectedIndexerEndpoint = ''; + } else { + selectedIndexerEndpoint = indexerEndpoint; + } + + if (selectedIndexerEndpoint == '') { + selectedIndexerEndpoint = _indexer.listIndexerEndpoints[0]; + } + + TextEditingController _endpointController = TextEditingController( + text: configBox.containsKey('customIndexer') + ? configBox.get('customIndexer') + : 'https://'); + + return Column(children: [ + Row(children: [ + Consumer(builder: (context, _indexer, _) { + log.d(selectedIndexerEndpoint); + log.d(_indexer.listIndexerEndpoints); + return Expanded( + child: Row(children: [ + const SizedBox(width: 10), + const Text('Indexer : '), + const Spacer(), + Icon(indexerEndpoint != '' ? Icons.check : Icons.close), + const Spacer(), + Consumer(builder: (context, _set, _) { + return DropdownButtonHideUnderline( + child: DropdownButton( + // alignment: AlignmentDirectional.topStart, + value: selectedIndexerEndpoint, + icon: const Icon(Icons.keyboard_arrow_down), + items: + _indexer.listIndexerEndpoints.map((_indexerEndpoint) { + return DropdownMenuItem( + value: _indexerEndpoint, + child: Text(_indexerEndpoint), + ); + }).toList(), + onChanged: (_newEndpoint) { + log.d(_newEndpoint!); + selectedIndexerEndpoint = _newEndpoint.toString(); + _set.reload(); + }, + ), + ); + }), + const Spacer(flex: 5), + _indexer.isLoadingIndexer + ? CircularProgressIndicator(color: orangeC) + : Consumer(builder: (context, _set, _) { + return IconButton( + icon: Icon( + Icons.send, + color: selectedIndexerEndpoint != indexerEndpoint + ? orangeC + : Colors.grey[500], + size: 40, + ), + onPressed: selectedIndexerEndpoint != indexerEndpoint + ? () async { + log.d( + 'connection to indexer $selectedIndexerEndpoint'); + await _indexer.checkIndexerEndpoint( + selectedIndexerEndpoint!); + } + : null); + }), + const Spacer(flex: 8), + ]), + ); + }), + ]), + Consumer(builder: (context, _set, _) { + return Visibility( + visible: selectedIndexerEndpoint == 'Personnalisé', + child: SizedBox( + width: 200, + height: 50, + child: TextField( + controller: _endpointController, + autocorrect: false, ), ), - ), - // const Spacer(), - SizedBox(height: isTall ? 90 : 60), - ]), - ); + ); + }), + Consumer(builder: (context, _sub, _) { + return Consumer(builder: (context, _set, _) { + return Visibility( + visible: selectedIndexerEndpoint == 'Auto', + child: SizedBox( + width: 250, + height: 60, + child: Text( + _sub.getConnectedEndpoint() ?? + "Un noeud sûr et valide sera choisi automatiquement parmis une liste aléatoire.", + style: TextStyle( + fontSize: 15, + fontStyle: FontStyle.italic, + color: Colors.grey[700]), + ), + ), + ); + }); + }), + ]); } }