feat: global websocket connection for indexer and datapod

This commit is contained in:
poka 2024-01-08 03:10:56 +01:00
parent ebf7420615
commit 2bef9c1790
14 changed files with 81 additions and 142 deletions

View File

@ -1,6 +1,5 @@
[ [
"https://gdev-indexer.p2p.legal", "gdev-indexer.p2p.legal",
"https://hasura.gdev.coinduf.eu", "gdev-hasura.cgeek.fr",
"https://gdev-hasura.cgeek.fr", "hasura-gdev.pini.fr"
"https://hasura-gdev.pini.fr"
] ]

View File

@ -29,7 +29,7 @@ const cesiumPod = "https://g1.data.le-sou.org";
// String cesiumPod = "https://g1.data.presles.fr"; // String cesiumPod = "https://g1.data.presles.fr";
// String cesiumPod = "https://g1.data.e-is.pro"; // String cesiumPod = "https://g1.data.e-is.pro";
const datapodEndpoint = 'https://gdev-datapod.p2p.legal'; const datapodEndpoint = 'gdev-datapod.p2p.legal';
// const v2sDatapod = 'http://10.0.2.2:8080'; // const v2sDatapod = 'http://10.0.2.2:8080';
// Contexts // Contexts

View File

@ -16,6 +16,7 @@ class DuniterIndexer with ChangeNotifier {
bool isLoadingIndexer = false; bool isLoadingIndexer = false;
bool hasNextPage = false; bool hasNextPage = false;
Future<QueryResult<Object?>?> Function()? refetch; Future<QueryResult<Object?>?> Function()? refetch;
late GraphQLClient indexerClient;
void reload() { void reload() {
notifyListeners(); notifyListeners();
@ -27,10 +28,11 @@ class DuniterIndexer with ChangeNotifier {
final client = HttpClient(); final client = HttpClient();
client.connectionTimeout = const Duration(milliseconds: 4000); client.connectionTimeout = const Duration(milliseconds: 4000);
try { try {
final request = await client.postUrl(Uri.parse('$endpoint/v1/graphql')); final request =
await client.postUrl(Uri.parse('https://$endpoint/v1/graphql'));
final response = await request.close(); final response = await request.close();
if (response.statusCode != 200) { if (response.statusCode != 200) {
log.w('INDEXER IS OFFLINE'); log.w('Indexer $endpoint is offline');
indexerEndpoint = ''; indexerEndpoint = '';
isLoadingIndexer = false; isLoadingIndexer = false;
notifyListeners(); notifyListeners();
@ -46,7 +48,7 @@ class DuniterIndexer with ChangeNotifier {
return true; return true;
} }
} catch (e) { } catch (e) {
log.w('INDEXER IS OFFLINE'); log.w('Indexer $endpoint is offline');
indexerEndpoint = ''; indexerEndpoint = '';
isLoadingIndexer = false; isLoadingIndexer = false;
notifyListeners(); notifyListeners();
@ -96,7 +98,7 @@ class DuniterIndexer with ChangeNotifier {
} }
try { try {
final endpointPath = '${listIndexerEndpoints[i]}/v1/graphql'; final endpointPath = 'https://${listIndexerEndpoints[i]}/v1/graphql';
final request = await client.postUrl(Uri.parse(endpointPath)); final request = await client.postUrl(Uri.parse(endpointPath));
final response = await request.close(); final response = await request.close();
@ -217,42 +219,24 @@ class DuniterIndexer with ChangeNotifier {
Future<QueryResult> _execQuery( Future<QueryResult> _execQuery(
String query, Map<String, dynamic> variables) async { String query, Map<String, dynamic> variables) async {
final httpLink = HttpLink(
'$indexerEndpoint/v1/graphql',
);
final client = GraphQLClient(
cache: GraphQLCache(),
link: httpLink,
);
final options = QueryOptions(document: gql(query), variables: variables); final options = QueryOptions(document: gql(query), variables: variables);
// 5GMyvKsTNk9wDBy9jwKaX6mhSzmFFtpdK9KNnmrLoSTSuJHv // 5GMyvKsTNk9wDBy9jwKaX6mhSzmFFtpdK9KNnmrLoSTSuJHv
return await client.query(options); return await indexerClient.query(options);
} }
Stream<QueryResult> subscribeHistoryIssued(String address) { Stream<QueryResult> subscribeHistoryIssued(String address) {
final wsLink = WebSocketLink(
'${indexerEndpoint.replaceFirst('https', 'wss')}/v1/graphql',
);
final variables = <String, dynamic>{ final variables = <String, dynamic>{
'address': address, 'address': address,
}; };
final client = GraphQLClient(
cache: GraphQLCache(),
link: wsLink,
);
final options = SubscriptionOptions( final options = SubscriptionOptions(
document: gql(subscribeHistoryIssuedQ), document: gql(subscribeHistoryIssuedQ),
variables: variables, variables: variables,
); );
return client.subscribe(options); return indexerClient.subscribe(options);
} }
Map computeHistoryView(repository, String address) { Map computeHistoryView(repository, String address) {

View File

@ -11,19 +11,14 @@ import 'package:provider/provider.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
class V2sDatapodProvider with ChangeNotifier { class V2sDatapodProvider with ChangeNotifier {
late GraphQLClient datapodClient;
Future<QueryResult> _execQuery( Future<QueryResult> _execQuery(
String query, Map<String, dynamic> variables) async { String query, Map<String, dynamic> variables) async {
final httpLink = HttpLink('$datapodEndpoint/v1/graphql');
final GraphQLClient client = GraphQLClient(
cache: GraphQLCache(),
link: httpLink,
);
final QueryOptions options = final QueryOptions options =
QueryOptions(document: gql(query), variables: variables); QueryOptions(document: gql(query), variables: variables);
return await client.query(options); return await datapodClient.query(options);
} }
Future<bool> updateProfile( Future<bool> updateProfile(
@ -174,34 +169,21 @@ class V2sDatapodProvider with ChangeNotifier {
} }
Future<File> cacheAvatar(String address, String data) async { Future<File> cacheAvatar(String address, String data) async {
final file = File('${avatarsCacheDirectory.path}/$address'); final uuid = const Uuid().v4();
return await file.writeAsBytes(base64.decode(data)); final tempFile = File('${avatarsCacheDirectory.path}/$uuid$address');
final targetFile = File('${avatarsCacheDirectory.path}/$address');
try {
// Write to a temporary file first to prevent data race
await tempFile.writeAsBytes(base64.decode(data));
log.d('Caching avatar of $address');
return await tempFile.rename(targetFile.path);
} catch (e) {
log.e("An error occurred while caching avatar: $e");
rethrow;
}
} }
// Future<File> cacheAvatar(String address, String data) async {
// // Get the list of all files in the directory
// final dir = Directory(avatarsCacheDirectory.path);
// var filesList = dir.listSync().whereType<File>().toList();
// // Sorting files by modified date, oldest first
// filesList
// .sort((a, b) => a.lastModifiedSync().compareTo(b.lastModifiedSync()));
// // If there are more than 20 files, remove the oldest ones
// while (filesList.length > 20) {
// filesList.first.deleteSync();
// filesList.removeAt(0);
// }
// // Write the new avatar file
// final file = File('${avatarsCacheDirectory.path}/$address');
// await file.writeAsBytes(base64.decode(data));
// log.d('cache files: ${filesList.length}');
// return file;
// }
Image getAvatarLocal(String address) { Image getAvatarLocal(String address) {
final avatarFile = File('${avatarsCacheDirectory.path}/$address'); final avatarFile = File('${avatarsCacheDirectory.path}/$address');
return Image.file( return Image.file(

View File

@ -20,6 +20,7 @@ import 'package:gecko/screens/myWallets/restore_chest.dart';
import 'package:gecko/screens/onBoarding/1.dart'; import 'package:gecko/screens/onBoarding/1.dart';
import 'package:gecko/widgets/drawer.dart'; import 'package:gecko/widgets/drawer.dart';
import 'package:gecko/widgets/buttons/home_buttons.dart'; import 'package:gecko/widgets/buttons/home_buttons.dart';
import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:hive_flutter/hive_flutter.dart'; import 'package:hive_flutter/hive_flutter.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -76,7 +77,25 @@ class _HomeScreenState extends State<HomeScreen> {
homeProvider.isWalletBoxInit = true; homeProvider.isWalletBoxInit = true;
myWalletProvider.reload(); myWalletProvider.reload();
duniterIndexer.getValidIndexerEndpoint(); duniterIndexer.getValidIndexerEndpoint().then((validIndexerEndpoint) {
final wsLinkIndexer = WebSocketLink(
'wss://$validIndexerEndpoint/v1/graphql',
);
final wsLinkDatapod = WebSocketLink(
'wss://$datapodEndpoint/v1/graphql',
);
duniterIndexer.indexerClient = GraphQLClient(
cache: GraphQLCache(),
link: wsLinkIndexer,
);
datapod.datapodClient = GraphQLClient(
cache: GraphQLCache(),
link: wsLinkDatapod,
);
});
await homeProvider.getValidEndpoints(); await homeProvider.getValidEndpoints();
if (configBox.get('isCacheChecked') == null) { if (configBox.get('isCacheChecked') == null) {
@ -101,7 +120,6 @@ class _HomeScreenState extends State<HomeScreen> {
} }
}); });
} }
// _duniterIndexer.checkIndexerEndpointBackground();
}); });
super.initState(); super.initState();
} }

View File

@ -86,7 +86,7 @@ class WalletOptions extends StatelessWidget {
? duniterIndexer ? duniterIndexer
.walletNameIndexer[walletOptions.address.text]! .walletNameIndexer[walletOptions.address.text]!
: wallet.name!, : wallet.name!,
style: scaledTextStyle(fontSize: 18), style: scaledTextStyle(fontSize: 19),
); );
}), }),
actions: [ actions: [

View File

@ -4,8 +4,10 @@ import 'package:gecko/globals.dart';
import 'package:gecko/models/queries_indexer.dart'; import 'package:gecko/models/queries_indexer.dart';
import 'package:gecko/models/scale_functions.dart'; import 'package:gecko/models/scale_functions.dart';
import 'package:gecko/models/widgets_keys.dart'; import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/duniter_indexer.dart';
import 'package:gecko/widgets/cert_tile.dart'; import 'package:gecko/widgets/cert_tile.dart';
import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:provider/provider.dart';
class CertsList extends StatelessWidget { class CertsList extends StatelessWidget {
const CertsList( const CertsList(
@ -18,14 +20,11 @@ class CertsList extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final indexerProvider = Provider.of<DuniterIndexer>(context, listen: false);
final screenHeight = MediaQuery.of(context).size.height; final screenHeight = MediaQuery.of(context).size.height;
final appBarHeight = AppBar().preferredSize.height; final appBarHeight = AppBar().preferredSize.height;
final windowHeight = screenHeight - appBarHeight - (isTall ? 170 : 140); final windowHeight = screenHeight - appBarHeight - (isTall ? 170 : 140);
final httpLink = HttpLink(
'$indexerEndpoint/v1/graphql',
);
late String gertCertsReq; late String gertCertsReq;
late String certFrom; late String certFrom;
@ -37,14 +36,8 @@ class CertsList extends StatelessWidget {
certFrom = 'receiver'; certFrom = 'receiver';
} }
final client = ValueNotifier(
GraphQLClient(
cache: GraphQLCache(store: HiveStore()),
link: httpLink,
),
);
return GraphQLProvider( return GraphQLProvider(
client: client, client: ValueNotifier(indexerProvider.indexerClient),
child: Query( child: Query(
options: QueryOptions( options: QueryOptions(
document: gql(gertCertsReq), document: gql(gertCertsReq),
@ -53,7 +46,7 @@ class CertsList extends StatelessWidget {
}, },
), ),
builder: (QueryResult result, {fetchMore, refetch}) { builder: (QueryResult result, {fetchMore, refetch}) {
if (result.isLoading && result.data == null) { if (result.isLoading || result.data == null) {
return const Center( return const Center(
child: CircularProgressIndicator(), child: CircularProgressIndicator(),
); );

View File

@ -30,21 +30,10 @@ class DatapodAvatar extends StatelessWidget {
); );
} }
final httpLink = HttpLink(
'$datapodEndpoint/v1/graphql',
);
final client = ValueNotifier(
GraphQLClient(
cache: GraphQLCache(),
link: httpLink,
),
);
return ScaledSizedBox( return ScaledSizedBox(
width: size, width: size,
child: GraphQLProvider( child: GraphQLProvider(
client: client, client: ValueNotifier(datapod.datapodClient),
child: Query( child: Query(
options: QueryOptions( options: QueryOptions(
document: gql(getAvatarQ), document: gql(getAvatarQ),
@ -53,7 +42,7 @@ class DatapodAvatar extends StatelessWidget {
}, },
), ),
builder: (QueryResult result, {fetchMore, refetch}) { builder: (QueryResult result, {fetchMore, refetch}) {
if (result.isLoading) { if (result.isLoading || result.data == null) {
return Center( return Center(
child: ClipOval(child: datapod.defaultAvatar(size)), child: ClipOval(child: datapod.defaultAvatar(size)),
); );

View File

@ -36,19 +36,8 @@ class HistoryQuery extends StatelessWidget {
]); ]);
} }
final httpLink = HttpLink(
'$indexerEndpoint/v1/graphql',
);
final client = ValueNotifier(
GraphQLClient(
cache: GraphQLCache(),
link: httpLink,
),
);
return GraphQLProvider( return GraphQLProvider(
client: client, client: ValueNotifier(duniterIndexer.indexerClient),
child: Expanded( child: Expanded(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,

View File

@ -54,7 +54,8 @@ class HistoryView extends StatelessWidget {
return Column(children: <Widget>[ return Column(children: <Widget>[
if (isMigrationTime) if (isMigrationTime)
Padding( Padding(
padding: EdgeInsets.symmetric(vertical: scaleSize(23)), padding: EdgeInsets.only(
top: scaleSize(25), bottom: scaleSize(15)),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [
@ -64,9 +65,9 @@ class HistoryView extends StatelessWidget {
Text( Text(
'blockchainStart'.tr(), 'blockchainStart'.tr(),
style: scaledTextStyle( style: scaledTextStyle(
fontSize: 19, fontSize: 20,
color: Colors.blueAccent, color: Colors.blueAccent,
fontWeight: FontWeight.w500), fontWeight: FontWeight.w400),
), ),
Image( Image(
image: const AssetImage('assets/party.png'), image: const AssetImage('assets/party.png'),
@ -83,7 +84,7 @@ class HistoryView extends StatelessWidget {
child: Text( child: Text(
answer['dateDelimiter'], answer['dateDelimiter'],
style: scaledTextStyle( style: scaledTextStyle(
fontSize: 19, fontSize: 20,
color: orangeC, color: orangeC,
fontWeight: FontWeight.w300), fontWeight: FontWeight.w300),
), ),
@ -131,7 +132,7 @@ class HistoryView extends StatelessWidget {
Text( Text(
'identityMigrated'.tr(), 'identityMigrated'.tr(),
style: scaledTextStyle( style: scaledTextStyle(
fontSize: 19, fontSize: 20,
color: Colors.green[700], color: Colors.green[700],
fontWeight: FontWeight.w500), fontWeight: FontWeight.w500),
), ),
@ -155,10 +156,18 @@ class HistoryView extends StatelessWidget {
Column( Column(
children: <Widget>[ children: <Widget>[
ScaledSizedBox(height: 15), ScaledSizedBox(height: 15),
Text("historyStart".tr(), Row(
textAlign: TextAlign.center, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
style: scaledTextStyle(fontSize: 20)), children: [
ScaledSizedBox(height: 15) Icon(Icons.blur_on_outlined, size: scaleSize(31)),
Text("historyStart".tr(),
textAlign: TextAlign.center,
style: scaledTextStyle(
fontSize: 20, fontWeight: FontWeight.w300)),
Icon(Icons.blur_on_outlined, size: scaleSize(31)),
],
),
ScaledSizedBox(height: 30)
], ],
) )
]); ]);

View File

@ -6,6 +6,7 @@ import 'package:gecko/models/queries_indexer.dart';
import 'package:gecko/models/scale_functions.dart'; import 'package:gecko/models/scale_functions.dart';
import 'package:gecko/models/wallet_data.dart'; import 'package:gecko/models/wallet_data.dart';
import 'package:gecko/providers/duniter_indexer.dart'; import 'package:gecko/providers/duniter_indexer.dart';
import 'package:gecko/widgets/commons/loading.dart';
import 'package:gecko/widgets/wallet_name.dart'; import 'package:gecko/widgets/wallet_name.dart';
import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -34,22 +35,8 @@ class NameByAddress extends StatelessWidget {
return WalletName(wallet: wallet, size: size, color: color); return WalletName(wallet: wallet, size: size, color: color);
} }
// if (g1WalletsBox.get(wallet.address)?.username != null) {
// return Text(g1WalletsBox.get(wallet.address)!.username!);
// }
final httpLink = HttpLink(
'$indexerEndpoint/v1/graphql',
);
final client = ValueNotifier(
GraphQLClient(
cache: GraphQLCache(store: HiveStore()),
link: httpLink,
),
);
return GraphQLProvider( return GraphQLProvider(
client: client, client: ValueNotifier(duniterIndexer.indexerClient),
child: Query( child: Query(
options: QueryOptions( options: QueryOptions(
document: gql(getNameByAddressQ), document: gql(getNameByAddressQ),
@ -66,7 +53,7 @@ class NameByAddress extends StatelessWidget {
} }
if (result.isLoading) { if (result.isLoading) {
return const Text('Loading'); return const Loading();
} }
duniterIndexer.walletNameIndexer[wallet.address] = duniterIndexer.walletNameIndexer[wallet.address] =

View File

@ -29,19 +29,8 @@ class SearchIdentityQuery extends StatelessWidget {
return Text('noResult'.tr()); return Text('noResult'.tr());
} }
final httpLink = HttpLink(
'$indexerEndpoint/v1/graphql',
);
final client = ValueNotifier(
GraphQLClient(
cache: GraphQLCache(
store: HiveStore()),
link: httpLink,
),
);
return GraphQLProvider( return GraphQLProvider(
client: client, client: ValueNotifier(duniterIndexer.indexerClient),
child: Query( child: Query(
options: QueryOptions( options: QueryOptions(
document: gql(searchAddressByNameQ), document: gql(searchAddressByNameQ),

View File

@ -108,7 +108,7 @@ class _TransactionInProgressTuleState extends State<TransactionInProgressTule> {
Text( Text(
'Transaction en cours', 'Transaction en cours',
style: scaledTextStyle( style: scaledTextStyle(
fontSize: 19, fontSize: 20,
color: Colors.blueAccent, color: Colors.blueAccent,
fontWeight: FontWeight.w400), fontWeight: FontWeight.w400),
), ),

View File

@ -5,7 +5,7 @@ description: Pay with G1.
# pub.dev using `pub publish`. This is preferred for private packages. # pub.dev using `pub publish`. This is preferred for private packages.
publish_to: "none" # Remove this line if you wish to publish to pub.dev publish_to: "none" # Remove this line if you wish to publish to pub.dev
version: 0.1.3+64 version: 0.1.4+65
environment: environment:
sdk: ">=2.12.0 <3.0.0" sdk: ">=2.12.0 <3.0.0"