From 0cf2b947beb5d28220b153c7fc90ef52a39285a1 Mon Sep 17 00:00:00 2001 From: Christien Rioux Date: Thu, 29 Feb 2024 13:54:03 -0500 Subject: [PATCH] fix refresh, error --- .../views/contact_invitation_display.dart | 14 ++-- .../lib/dht_support/src/dht_short_array.dart | 37 +++++++++ .../src/dht_short_array_cubit.dart | 79 +++++++++---------- pubspec.lock | 16 +--- pubspec.yaml | 2 +- 5 files changed, 86 insertions(+), 62 deletions(-) diff --git a/lib/contact_invitation/views/contact_invitation_display.dart b/lib/contact_invitation/views/contact_invitation_display.dart index fe2ed33..4a1a7c2 100644 --- a/lib/contact_invitation/views/contact_invitation_display.dart +++ b/lib/contact_invitation/views/contact_invitation_display.dart @@ -26,8 +26,8 @@ class ContactInvitationDisplayDialog extends StatefulWidget { final String message; @override - ContactInvitationDisplayDialogState createState() => - ContactInvitationDisplayDialogState(); + State createState() => + _ContactInvitationDisplayDialogState(); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { @@ -36,7 +36,7 @@ class ContactInvitationDisplayDialog extends StatefulWidget { } } -class ContactInvitationDisplayDialogState +class _ContactInvitationDisplayDialogState extends State { final focusNode = FocusNode(); final formKey = GlobalKey(); @@ -123,12 +123,8 @@ class ContactInvitationDisplayDialogState }, ).paddingAll(16), ])), - error: (e, s) { - Navigator.of(context).pop(); - showErrorToast(context, - translate('send_invite_dialog.failed_to_generate')); - return const Text(''); - }))); + error: (e, s) => + Text(translate('send_invite_dialog.failed_to_generate'))))); } @override diff --git a/packages/veilid_support/lib/dht_support/src/dht_short_array.dart b/packages/veilid_support/lib/dht_support/src/dht_short_array.dart index 09bd2d7..8cc0e37 100644 --- a/packages/veilid_support/lib/dht_support/src/dht_short_array.dart +++ b/packages/veilid_support/lib/dht_support/src/dht_short_array.dart @@ -212,17 +212,54 @@ class DHTShortArray { return record!.get(subkey: recordSubkey, forceRefresh: forceRefresh); } + Future?> getAllItems({bool forceRefresh = false}) async { + await _refreshHead(forceRefresh: forceRefresh, onlyUpdates: true); + + final out = []; + + for (var pos = 0; pos < _head.index.length; pos++) { + final index = _head.index[pos]; + final recordNumber = index ~/ _stride; + final record = _getLinkedRecord(recordNumber); + if (record == null) { + assert(record != null, 'Record does not exist'); + return null; + } + + final recordSubkey = (index % _stride) + ((recordNumber == 0) ? 1 : 0); + final elem = + await record.get(subkey: recordSubkey, forceRefresh: forceRefresh); + if (elem == null) { + return null; + } + out.add(elem); + } + + return out; + } + Future getItemJson(T Function(dynamic) fromJson, int pos, {bool forceRefresh = false}) => getItem(pos, forceRefresh: forceRefresh) .then((out) => jsonDecodeOptBytes(fromJson, out)); + Future?> getAllItemsJson(T Function(dynamic) fromJson, + {bool forceRefresh = false}) => + getAllItems(forceRefresh: forceRefresh) + .then((out) => out?.map(fromJson).toList()); + Future getItemProtobuf( T Function(List) fromBuffer, int pos, {bool forceRefresh = false}) => getItem(pos, forceRefresh: forceRefresh) .then((out) => (out == null) ? null : fromBuffer(out)); + Future?> getAllItemsProtobuf( + T Function(List) fromBuffer, + {bool forceRefresh = false}) => + getAllItems(forceRefresh: forceRefresh) + .then((out) => out?.map(fromBuffer).toList()); + Future tryAddItem(Uint8List value) async { await _refreshHead(onlyUpdates: true); diff --git a/packages/veilid_support/lib/dht_support/src/dht_short_array_cubit.dart b/packages/veilid_support/lib/dht_support/src/dht_short_array_cubit.dart index 8309254..b8920cd 100644 --- a/packages/veilid_support/lib/dht_support/src/dht_short_array_cubit.dart +++ b/packages/veilid_support/lib/dht_support/src/dht_short_array_cubit.dart @@ -18,13 +18,13 @@ class DHTShortArrayCubit extends Cubit> required T Function(List data) decodeElement, }) : _decodeElement = decodeElement, super(const BlocBusyState(AsyncValue.loading())) { - Future.delayed(Duration.zero, () async { + _initFuture = Future(() async { // Open DHT record _shortArray = await open(); _wantsCloseRecord = true; // Make initial state update - _update(); + await _refreshNoWait(); _subscription = await _shortArray.listen(_update); }); } @@ -35,57 +35,53 @@ class DHTShortArrayCubit extends Cubit> }) : _shortArray = shortArray, _decodeElement = decodeElement, super(const BlocBusyState(AsyncValue.loading())) { - // Make initial state update - _update(); - Future.delayed(Duration.zero, () async { + _initFuture = Future(() async { + // Make initial state update + await _refreshNoWait(); _subscription = await shortArray.listen(_update); }); } - Future refresh({bool forceRefresh = false}) async => busy((emit) async { - var out = IList(); - // xxx could be parallelized but we need to watch out for rate limits - for (var i = 0; i < _shortArray.length; i++) { - final cir = await _shortArray.getItem(i, forceRefresh: forceRefresh); - if (cir == null) { - throw Exception('Failed to get short array element'); - } - out = out.add(_decodeElement(cir)); - } - emit(AsyncValue.data(out)); + Future refresh({bool forceRefresh = false}) async { + await _initFuture; + await _refreshNoWait(forceRefresh: forceRefresh); + } + + Future _refreshNoWait({bool forceRefresh = false}) async => + busy((emit) async { + await _refreshInner(emit, forceRefresh: forceRefresh); }); + Future _refreshInner(void Function(AsyncValue>) emit, + {bool forceRefresh = false}) async { + try { + final newState = + (await _shortArray.getAllItems(forceRefresh: forceRefresh)) + ?.map(_decodeElement) + .toIList(); + if (newState == null) { + emit(const AsyncValue.loading()); + } else { + emit(AsyncValue.data(newState)); + } + } on Exception catch (e) { + emit(AsyncValue.error(e)); + } + } + void _update() { // Run at most one background update process // Because this is async, we could get an update while we're - // still processing the last one + // still processing the last one. Only called after init future has run + // so we dont have to wait for that here. _sspUpdate.busyUpdate>>(busy, (emit) async { - try { - final initialState = await _getElementsInner(); - emit(AsyncValue.data(initialState)); - } on Exception catch (e) { - emit(AsyncValue.error(e)); - } + await _refreshInner(emit); }); } - // Get and decode the entire short array - Future> _getElementsInner() async { - assert(isBusy, 'should only be called from a busy state'); - var out = IList(); - for (var i = 0; i < _shortArray.length; i++) { - // Get the element bytes (throw if fails, array state is invalid) - final bytes = (await _shortArray.getItem(i))!; - // Decode the element - final elem = _decodeElement(bytes); - // Append to the output list - out = out.add(elem); - } - return out; - } - @override Future close() async { + await _initFuture; await _subscription?.cancel(); _subscription = null; if (_wantsCloseRecord) { @@ -94,10 +90,13 @@ class DHTShortArrayCubit extends Cubit> await super.close(); } - Future operate(Future Function(DHTShortArray) closure) async => - _operateMutex.protect(() async => closure(_shortArray)); + Future operate(Future Function(DHTShortArray) closure) async { + await _initFuture; + return _operateMutex.protect(() async => closure(_shortArray)); + } final _operateMutex = Mutex(); + late final Future _initFuture; late final DHTShortArray _shortArray; final T Function(List data) _decodeElement; StreamSubscription? _subscription; diff --git a/pubspec.lock b/pubspec.lock index e6de13e..2a2bec9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -251,10 +251,10 @@ packages: dependency: "direct main" description: name: change_case - sha256: f4e08feaa845e75e4f5ad2b0e15f24813d7ea6c27e7b78252f0c17f752cf1157 + sha256: "47c48c36f95f20c6d0ba03efabceff261d05026cca322cc2c4c01c343371b5bb" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "2.0.1" characters: dependency: transitive description: @@ -423,14 +423,6 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" - file_utils: - dependency: transitive - description: - name: file_utils - sha256: d1e64389a22649095c8405c9e177272caf05139255931c9ff30d53b5c9bcaa34 - url: "https://pub.dev" - source: hosted - version: "1.0.1" fixnum: dependency: "direct main" description: @@ -1342,10 +1334,10 @@ packages: dependency: transitive description: name: system_info2 - sha256: af2f948e3f31a3367a049932a8ad59faf0063ecf836a020d975b9f41566d8bc9 + sha256: "65206bbef475217008b5827374767550a5420ce70a04d2d7e94d1d2253f3efc9" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "4.0.0" system_info_plus: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index e25b649..8b2341d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,7 +20,7 @@ dependencies: bloc_tools: path: packages/bloc_tools blurry_modal_progress_hud: ^1.1.1 - change_case: ^1.1.0 + change_case: ^2.0.1 charcode: ^1.3.1 circular_profile_avatar: ^2.0.5 circular_reveal_animation: ^2.0.1