1
0
mirror of https://github.com/immich-app/immich.git synced 2025-08-07 23:03:36 +02:00

feat: websocket background sync (#19888)

* feat: websocket background sync

* batch websocket

* pr feedback
This commit is contained in:
Alex
2025-07-15 09:38:28 -05:00
committed by GitHub
parent 0acbf1199a
commit 59e7754bdc
3 changed files with 116 additions and 1 deletions

View File

@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:convert';
import 'package:collection/collection.dart';
@ -10,6 +11,7 @@ import 'package:immich_mobile/entities/store.entity.dart';
import 'package:immich_mobile/models/server_info/server_version.model.dart';
import 'package:immich_mobile/providers/asset.provider.dart';
import 'package:immich_mobile/providers/auth.provider.dart';
import 'package:immich_mobile/providers/background_sync.provider.dart';
import 'package:immich_mobile/providers/db.provider.dart';
import 'package:immich_mobile/providers/server_info.provider.dart';
import 'package:immich_mobile/services/api.service.dart';
@ -106,6 +108,18 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
final Debouncer _debounce =
Debouncer(interval: const Duration(milliseconds: 500));
final Debouncer _batchDebouncer = Debouncer(
interval: const Duration(seconds: 5),
maxWaitTime: const Duration(seconds: 10),
);
final List<dynamic> _batchedAssetUploadReady = [];
@override
void dispose() {
_batchDebouncer.dispose();
super.dispose();
}
/// Connects websocket to server unless already connected
void connect() {
if (state.isConnected) return;
@ -171,6 +185,7 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
socket.on('on_asset_stack_update', _handleServerUpdates);
socket.on('on_asset_hidden', _handleOnAssetHidden);
socket.on('on_new_release', _handleReleaseUpdates);
socket.on('AssetUploadReadyV1', _handleSyncAssetUploadReady);
} catch (e) {
debugPrint("[WEBSOCKET] Catch Websocket Error - ${e.toString()}");
}
@ -180,6 +195,8 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
void disconnect() {
debugPrint("Attempting to disconnect from websocket");
_batchedAssetUploadReady.clear();
var socket = state.socket?.disconnect();
if (socket?.disconnected == true) {
@ -288,7 +305,7 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
}
}
void handlePendingChanges() async {
Future<void> handlePendingChanges() async {
await _handlePendingUploaded();
await _handlePendingDeletes();
await _handlingPendingHidden();
@ -347,6 +364,29 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
.read(serverInfoProvider.notifier)
.handleNewRelease(serverVersion, releaseVersion);
}
void _handleSyncAssetUploadReady(dynamic data) {
_batchedAssetUploadReady.add(data);
_batchDebouncer.run(_processBatchedAssetUploadReady);
}
void _processBatchedAssetUploadReady() {
if (_batchedAssetUploadReady.isEmpty) {
return;
}
try {
unawaited(
_ref
.read(backgroundSyncProvider)
.syncWebsocketBatch(_batchedAssetUploadReady.toList()),
);
} catch (error) {
_log.severe("Error processing batched AssetUploadReadyV1 events: $error");
}
_batchedAssetUploadReady.clear();
}
}
final websocketProvider =