fix(chat): Improve server message synchronization and streaming recovery

This commit is contained in:
cogwheel0
2025-12-02 16:15:16 +05:30
parent 384df15514
commit c59a46d568
4 changed files with 357 additions and 122 deletions

View File

@@ -5,6 +5,9 @@ import 'dart:async';
/// Call [ping] whenever activity occurs. If no activity happens
/// within [window], [onTimeout] fires. Optionally, an [absoluteCap]
/// enforces a maximum total duration regardless of activity.
///
/// The [onTimeout] callback can be sync or async - if async, it will be
/// awaited before the watchdog considers itself fully stopped.
class InactivityWatchdog {
InactivityWatchdog({
required Duration window,
@@ -13,16 +16,20 @@ class InactivityWatchdog {
}) : _window = window,
_absoluteCap = absoluteCap;
final void Function() onTimeout;
final FutureOr<void> Function() onTimeout;
Duration _window;
Duration? _absoluteCap;
Timer? _timer;
Timer? _absoluteTimer;
bool _started = false;
bool _firing = false;
Duration get window => _window;
/// Whether the timeout callback is currently executing.
bool get isFiring => _firing;
void setWindow(Duration newWindow) {
_window = newWindow;
if (_started) {
@@ -43,6 +50,8 @@ class InactivityWatchdog {
void start() {
if (_started) return;
// Prevent restart while callback is still executing to avoid double-fire
if (_firing) return;
_started = true;
_restart();
if (_absoluteCap != null) {
@@ -51,6 +60,8 @@ class InactivityWatchdog {
}
void ping() {
// Prevent restart while callback is still executing to avoid double-fire
if (_firing) return;
if (!_started) {
start();
return;
@@ -73,10 +84,24 @@ class InactivityWatchdog {
_timer = Timer(_window, _fire);
}
/// Synchronous entry point called by Timer. Kicks off async work.
void _fire() {
if (_firing) return; // Prevent re-entry
_firing = true;
stop();
// Execute the callback asynchronously. We don't await because Timer
// expects a sync callback, but the async work will complete in background.
_executeCallback();
}
/// Executes the timeout callback asynchronously.
Future<void> _executeCallback() async {
try {
onTimeout();
} catch (_) {}
await onTimeout();
} catch (_) {
// Swallow errors to prevent unhandled exceptions
} finally {
_firing = false;
}
}
}