From 927589a50503c7bb17ab98fa25e96659a6f32614 Mon Sep 17 00:00:00 2001 From: otsmr Date: Tue, 19 May 2026 02:12:12 +0200 Subject: [PATCH] fix: background message fetching reliability --- CHANGELOG.md | 7 +++++- lib/src/services/api.service.dart | 23 +++++++++++++++---- .../callback_dispatcher.background.dart | 6 +++++ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4c4d816..9c8beed7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 0.2.17 + +- Fix: Issue with receiving messages when user closed app while decrypting +- Fix: Background message fetching reliability. + ## 0.2.16 - Fix: Images not shown after opening due to cleanup @@ -14,7 +19,7 @@ - New: Tutorial on how to use zoom. - New: Manage storage view. - Improved: Media thumbnails for faster loading. -- Fix: Some message where not marked as opened. +- Fix: Some messages were not marked as opened. ## 0.2.12 diff --git a/lib/src/services/api.service.dart b/lib/src/services/api.service.dart index 623db097..d1a37e8a 100644 --- a/lib/src/services/api.service.dart +++ b/lib/src/services/api.service.dart @@ -101,12 +101,20 @@ class ApiService { Uri.parse(apiUrl), pingInterval: const Duration(seconds: 30), ); + + try { + await channel.ready.timeout(const Duration(seconds: 10)); + } catch (e) { + channel.sink.close().ignore(); + rethrow; + } + _channel = channel; _channel!.stream.listen(_onData, onDone: _onDone, onError: _onError); - await _channel!.ready; Log.info('websocket connected to $apiUrl'); return true; } catch (e, s) { + _channel = null; if (kDebugMode) { print('DEBUG: _connectTo caught exception: $e\n$s'); } @@ -156,6 +164,7 @@ class ApiService { } Future onClosed() async { + if (_channel == null) return; Log.info('websocket connection closed'); _channel = null; isAuthenticated = false; @@ -187,15 +196,19 @@ class ApiService { _reconnectionDelay = 3; } - Future close(Function callback) async { + Future close(Function? callback) async { Log.info('closing websocket connection'); if (_channel != null) { - await _channel!.sink.close(); + try { + await _channel!.sink.close().timeout(const Duration(seconds: 2)); + } catch (e) { + Log.warn('Timeout or error closing websocket: $e'); + } await onClosed(); - callback(); + callback?.call(); return; } - callback(); + callback?.call(); } Future listenToNetworkChanges() async { diff --git a/lib/src/services/background/callback_dispatcher.background.dart b/lib/src/services/background/callback_dispatcher.background.dart index 3b689615..a738214c 100644 --- a/lib/src/services/background/callback_dispatcher.background.dart +++ b/lib/src/services/background/callback_dispatcher.background.dart @@ -119,9 +119,15 @@ Future handlePeriodicTask({int lastExecutionInSecondsLimit = 120}) async { if (!shouldBeExecuted) return; Log.info('eu.twonly.periodic_task was called.'); + AppState.gotMessageFromServer = false; final stopwatch = Stopwatch()..start(); + // Issue: Because the background isolate can be reused across multiple periodic tasks, + // the API connection state might be stale or disconnected from a previous run. + // Explicitly close it here to ensure a clean slate before connecting. + await apiService.close(null); + if (!await apiService.connect()) { Log.info('Could not connect to the api. Returning early.'); return;