try to connect first
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run

This commit is contained in:
otsmr 2026-08-05 00:50:58 +02:00
parent 185ac49de9
commit 1f269ae5b3
3 changed files with 90 additions and 70 deletions

View file

@ -89,36 +89,40 @@ Future<bool> initBackgroundExecution() async {
final Mutex _keyValueMutex = Mutex(); final Mutex _keyValueMutex = Mutex();
// ignore: unreachable_from_main // ignore: unreachable_from_main
Future<void> handlePeriodicTask({int lastExecutionInSecondsLimit = 120}) async { Future<bool> backgroundFetch({
final shouldBeExecuted = await exclusiveAccess( int? lastExecutionInSecondsLimit = 120,
lockName: 'periodic_task', }) async {
mutex: _keyValueMutex, if (lastExecutionInSecondsLimit != null) {
action: () async { final shouldBeExecuted = await exclusiveAccess(
final lastExecution = await KeyValueStore.get( lockName: 'periodic_task',
KeyValueKeys.lastPeriodicTaskExecution, mutex: _keyValueMutex,
); action: () async {
if (lastExecution != null && lastExecution.containsKey('timestamp')) { final lastExecution = await KeyValueStore.get(
final lastExecutionTime = lastExecution['timestamp'] as int?; KeyValueKeys.lastPeriodicTaskExecution,
if (lastExecutionTime != null) { );
final lastExecutionDate = DateTime.fromMillisecondsSinceEpoch( if (lastExecution != null && lastExecution.containsKey('timestamp')) {
lastExecutionTime, final lastExecutionTime = lastExecution['timestamp'] as int?;
); if (lastExecutionTime != null) {
if (DateTime.now().difference(lastExecutionDate).inSeconds < final lastExecutionDate = DateTime.fromMillisecondsSinceEpoch(
lastExecutionInSecondsLimit) { lastExecutionTime,
return false; );
if (DateTime.now().difference(lastExecutionDate).inSeconds <
lastExecutionInSecondsLimit) {
return false;
}
} }
} }
} await KeyValueStore.put(KeyValueKeys.lastPeriodicTaskExecution, {
await KeyValueStore.put(KeyValueKeys.lastPeriodicTaskExecution, { 'timestamp': DateTime.now().millisecondsSinceEpoch,
'timestamp': DateTime.now().millisecondsSinceEpoch, });
}); return true;
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; AppState.gotMessageFromServer = false;
final stopwatch = Stopwatch()..start(); final stopwatch = Stopwatch()..start();
@ -130,14 +134,16 @@ Future<void> handlePeriodicTask({int lastExecutionInSecondsLimit = 120}) async {
if (!await apiService.connect()) { if (!await apiService.connect()) {
Log.info('Could not connect to the api. Returning early.'); Log.info('Could not connect to the api. Returning early.');
return; return false;
} }
if (!apiService.isAuthenticated) { if (!apiService.isAuthenticated) {
Log.info('Api is not authenticated. Returning early.'); Log.info('Api is not authenticated. Returning early.');
return; return false;
} }
var receiveMessage = false;
try { try {
while (!AppState.gotMessageFromServer) { while (!AppState.gotMessageFromServer) {
if (stopwatch.elapsed.inSeconds >= 15) { if (stopwatch.elapsed.inSeconds >= 15) {
@ -148,19 +154,22 @@ Future<void> handlePeriodicTask({int lastExecutionInSecondsLimit = 120}) async {
} }
if (AppState.gotMessageFromServer) { if (AppState.gotMessageFromServer) {
receiveMessage = true;
Log.info('Received a server message from the server.'); Log.info('Received a server message from the server.');
} }
await finishStartedPreprocessing(); await finishStartedPreprocessing();
await Future.delayed(const Duration(milliseconds: 2000)); if (lastExecutionInSecondsLimit != null) {
await Future.delayed(const Duration(milliseconds: 2000));
}
} finally { } finally {
await apiService.close(() {}); await apiService.close(() {});
stopwatch.stop(); stopwatch.stop();
} }
Log.info('eu.twonly.periodic_task finished after ${stopwatch.elapsed}.'); Log.info('Periodic task finished after ${stopwatch.elapsed}.');
return; return receiveMessage;
} }
Future<void> handleProcessingTask() async { Future<void> handleProcessingTask() async {

View file

@ -20,7 +20,7 @@ Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
if (Platform.isAndroid) { if (Platform.isAndroid) {
if (isInitialized) { if (isInitialized) {
await handlePeriodicTask(lastExecutionInSecondsLimit: 3); await backgroundFetch(lastExecutionInSecondsLimit: 3);
} }
} else { } else {
// make sure every thing run... // make sure every thing run...

View file

@ -10,6 +10,7 @@ import 'package:twonly/globals.dart';
import 'package:twonly/locator.dart'; import 'package:twonly/locator.dart';
import 'package:twonly/src/constants/secure_storage.keys.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/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/background.notifications.dart';
import 'package:twonly/src/services/notifications/fcm.background.dart'; import 'package:twonly/src/services/notifications/fcm.background.dart';
import 'package:twonly/src/services/notifications/pushkeys.notifications.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. // This is just a workarround until the new Rust decryption is enrolled fully.
final pushDataString = message.data['push_data'] as String?; final pushDataString = message.data['push_data'] as String?;
if (pushDataString != null) { if (pushDataString != null) {
try { if (apiService.isConnected) {
final pushDataBytes = base64Decode(pushDataString); Log.info('Got FCM message, but API is connected...');
final encryptedPush = EncryptedPushNotification.fromBuffer( } else {
pushDataBytes, Log.info('Trying to connect to the API in the background.');
);
final pushUsers = await getPushKeys( if (await backgroundFetch()) {
SecureStorageKeys.receivingPushKeys, return;
); }
for (final pushUser in pushUsers) {
for (final pushKey in pushUser.pushKeys) { try {
final decrypted = await tryDecryptMessage( final pushDataBytes = base64Decode(pushDataString);
pushKey.key, final encryptedPush = EncryptedPushNotification.fromBuffer(
encryptedPush, pushDataBytes,
); );
if (decrypted != null) { final pushUsers = await getPushKeys(
if (isUUIDNewer(pushUser.lastMessageId, decrypted.messageId)) { 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( 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; 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');
} }
} }