From 1f269ae5b384fab4e7292a39f2322f05b08b3456 Mon Sep 17 00:00:00 2001 From: otsmr Date: Wed, 5 Aug 2026 00:50:58 +0200 Subject: [PATCH] try to connect first --- .../callback_dispatcher.background.dart | 71 ++++++++------- .../notifications/fcm.background.dart | 2 +- .../notifications/fcm.notifications.dart | 87 +++++++++++-------- 3 files changed, 90 insertions(+), 70 deletions(-) diff --git a/lib/src/services/background/callback_dispatcher.background.dart b/lib/src/services/background/callback_dispatcher.background.dart index a738214c..1b57c9d7 100644 --- a/lib/src/services/background/callback_dispatcher.background.dart +++ b/lib/src/services/background/callback_dispatcher.background.dart @@ -89,36 +89,40 @@ Future initBackgroundExecution() async { final Mutex _keyValueMutex = Mutex(); // ignore: unreachable_from_main -Future handlePeriodicTask({int lastExecutionInSecondsLimit = 120}) async { - final shouldBeExecuted = await exclusiveAccess( - lockName: 'periodic_task', - mutex: _keyValueMutex, - action: () async { - final lastExecution = await KeyValueStore.get( - KeyValueKeys.lastPeriodicTaskExecution, - ); - if (lastExecution != null && lastExecution.containsKey('timestamp')) { - final lastExecutionTime = lastExecution['timestamp'] as int?; - if (lastExecutionTime != null) { - final lastExecutionDate = DateTime.fromMillisecondsSinceEpoch( - lastExecutionTime, - ); - if (DateTime.now().difference(lastExecutionDate).inSeconds < - lastExecutionInSecondsLimit) { - return false; +Future backgroundFetch({ + int? lastExecutionInSecondsLimit = 120, +}) async { + if (lastExecutionInSecondsLimit != null) { + final shouldBeExecuted = await exclusiveAccess( + lockName: 'periodic_task', + mutex: _keyValueMutex, + action: () async { + final lastExecution = await KeyValueStore.get( + KeyValueKeys.lastPeriodicTaskExecution, + ); + if (lastExecution != null && lastExecution.containsKey('timestamp')) { + final lastExecutionTime = lastExecution['timestamp'] as int?; + if (lastExecutionTime != null) { + final lastExecutionDate = DateTime.fromMillisecondsSinceEpoch( + lastExecutionTime, + ); + if (DateTime.now().difference(lastExecutionDate).inSeconds < + lastExecutionInSecondsLimit) { + return false; + } } } - } - await KeyValueStore.put(KeyValueKeys.lastPeriodicTaskExecution, { - 'timestamp': DateTime.now().millisecondsSinceEpoch, - }); - return true; - }, - ); + await KeyValueStore.put(KeyValueKeys.lastPeriodicTaskExecution, { + 'timestamp': DateTime.now().millisecondsSinceEpoch, + }); + return true; + }, + ); - if (!shouldBeExecuted) return; + if (!shouldBeExecuted) return false; + } - Log.info('eu.twonly.periodic_task was called.'); + Log.info('Periodic task was called.'); AppState.gotMessageFromServer = false; final stopwatch = Stopwatch()..start(); @@ -130,14 +134,16 @@ Future handlePeriodicTask({int lastExecutionInSecondsLimit = 120}) async { if (!await apiService.connect()) { Log.info('Could not connect to the api. Returning early.'); - return; + return false; } if (!apiService.isAuthenticated) { Log.info('Api is not authenticated. Returning early.'); - return; + return false; } + var receiveMessage = false; + try { while (!AppState.gotMessageFromServer) { if (stopwatch.elapsed.inSeconds >= 15) { @@ -148,19 +154,22 @@ Future handlePeriodicTask({int lastExecutionInSecondsLimit = 120}) async { } if (AppState.gotMessageFromServer) { + receiveMessage = true; Log.info('Received a server message from the server.'); } await finishStartedPreprocessing(); - await Future.delayed(const Duration(milliseconds: 2000)); + if (lastExecutionInSecondsLimit != null) { + await Future.delayed(const Duration(milliseconds: 2000)); + } } finally { await apiService.close(() {}); stopwatch.stop(); } - Log.info('eu.twonly.periodic_task finished after ${stopwatch.elapsed}.'); - return; + Log.info('Periodic task finished after ${stopwatch.elapsed}.'); + return receiveMessage; } Future handleProcessingTask() async { diff --git a/lib/src/services/notifications/fcm.background.dart b/lib/src/services/notifications/fcm.background.dart index d47e9bb6..01a39396 100644 --- a/lib/src/services/notifications/fcm.background.dart +++ b/lib/src/services/notifications/fcm.background.dart @@ -20,7 +20,7 @@ Future firebaseMessagingBackgroundHandler(RemoteMessage message) async { if (Platform.isAndroid) { if (isInitialized) { - await handlePeriodicTask(lastExecutionInSecondsLimit: 3); + await backgroundFetch(lastExecutionInSecondsLimit: 3); } } else { // make sure every thing run... diff --git a/lib/src/services/notifications/fcm.notifications.dart b/lib/src/services/notifications/fcm.notifications.dart index 5f1938dc..d6539d50 100644 --- a/lib/src/services/notifications/fcm.notifications.dart +++ b/lib/src/services/notifications/fcm.notifications.dart @@ -10,6 +10,7 @@ import 'package:twonly/globals.dart'; import 'package:twonly/locator.dart'; import 'package:twonly/src/constants/secure_storage.keys.dart'; import 'package:twonly/src/model/protobuf/client/generated/push_notification.pb.dart'; +import 'package:twonly/src/services/background/callback_dispatcher.background.dart'; import 'package:twonly/src/services/notifications/background.notifications.dart'; import 'package:twonly/src/services/notifications/fcm.background.dart'; import 'package:twonly/src/services/notifications/pushkeys.notifications.dart'; @@ -167,51 +168,61 @@ class FcmNotificationService { // This is just a workarround until the new Rust decryption is enrolled fully. final pushDataString = message.data['push_data'] as String?; if (pushDataString != null) { - try { - final pushDataBytes = base64Decode(pushDataString); - final encryptedPush = EncryptedPushNotification.fromBuffer( - pushDataBytes, - ); - final pushUsers = await getPushKeys( - SecureStorageKeys.receivingPushKeys, - ); - for (final pushUser in pushUsers) { - for (final pushKey in pushUser.pushKeys) { - final decrypted = await tryDecryptMessage( - pushKey.key, - encryptedPush, - ); - if (decrypted != null) { - if (isUUIDNewer(pushUser.lastMessageId, decrypted.messageId)) { + if (apiService.isConnected) { + Log.info('Got FCM message, but API is connected...'); + } else { + Log.info('Trying to connect to the API in the background.'); + + if (await backgroundFetch()) { + return; + } + + try { + final pushDataBytes = base64Decode(pushDataString); + final encryptedPush = EncryptedPushNotification.fromBuffer( + pushDataBytes, + ); + final pushUsers = await getPushKeys( + SecureStorageKeys.receivingPushKeys, + ); + for (final pushUser in pushUsers) { + for (final pushKey in pushUser.pushKeys) { + final decrypted = await tryDecryptMessage( + pushKey.key, + encryptedPush, + ); + if (decrypted != null) { + if (isUUIDNewer(pushUser.lastMessageId, decrypted.messageId)) { + Log.info( + 'Skipping local push notification because message is older than lastMessageId', + ); + return; + } Log.info( - 'Skipping local push notification because message is older than lastMessageId', + 'Successfully decrypted push_data directly from FCM payload! Showing notification.', + ); + await showLocalPushNotification( + pushUser, + decrypted, + titleSuffix: + (userService.isUserCreated && + userService.currentUser.isDeveloper) + ? ' [d]' + : null, + ); + unawaited( + updateLastMessageId( + pushUser.userId.toInt(), + decrypted.messageId, + ), ); return; } - Log.info( - 'Successfully decrypted push_data directly from FCM payload! Showing notification.', - ); - await showLocalPushNotification( - pushUser, - decrypted, - titleSuffix: - (userService.isUserCreated && - userService.currentUser.isDeveloper) - ? ' [d]' - : null, - ); - unawaited( - updateLastMessageId( - pushUser.userId.toInt(), - decrypted.messageId, - ), - ); - return; } } + } catch (e) { + Log.error('Error handling push_data: $e'); } - } catch (e) { - Log.error('Error handling push_data: $e'); } }