some fixes
This commit is contained in:
@@ -1,10 +1,7 @@
|
||||
import 'dart:async';
|
||||
import '../local/local_storage_service.dart';
|
||||
import '../local/models/item.dart';
|
||||
import '../immich/immich_service.dart';
|
||||
import '../immich/models/immich_asset.dart';
|
||||
import '../nostr/nostr_service.dart';
|
||||
import '../nostr/models/nostr_event.dart';
|
||||
import '../nostr/models/nostr_keypair.dart';
|
||||
import 'models/sync_status.dart';
|
||||
import 'models/sync_operation.dart';
|
||||
@@ -22,13 +19,13 @@ class SyncException implements Exception {
|
||||
}
|
||||
|
||||
/// Engine for coordinating data synchronization between local storage, Immich, and Nostr.
|
||||
///
|
||||
///
|
||||
/// This service provides:
|
||||
/// - Bidirectional sync between local storage, Immich, and Nostr
|
||||
/// - Conflict resolution strategies
|
||||
/// - Offline queue for operations when network is unavailable
|
||||
/// - Automatic retry with exponential backoff
|
||||
///
|
||||
///
|
||||
/// The service is modular and UI-independent, designed for offline-first behavior.
|
||||
class SyncEngine {
|
||||
/// Local storage service.
|
||||
@@ -50,7 +47,8 @@ class SyncEngine {
|
||||
SyncOperation? _currentOperation;
|
||||
|
||||
/// Stream controller for sync status updates.
|
||||
final StreamController<SyncOperation> _statusController = StreamController<SyncOperation>.broadcast();
|
||||
final StreamController<SyncOperation> _statusController =
|
||||
StreamController<SyncOperation>.broadcast();
|
||||
|
||||
/// Whether the engine has been disposed.
|
||||
bool _isDisposed = false;
|
||||
@@ -62,7 +60,7 @@ class SyncEngine {
|
||||
final int maxQueueSize;
|
||||
|
||||
/// Creates a [SyncEngine] instance.
|
||||
///
|
||||
///
|
||||
/// [localStorage] - Local storage service (required).
|
||||
/// [immichService] - Immich service (optional).
|
||||
/// [nostrService] - Nostr service (optional).
|
||||
@@ -97,7 +95,9 @@ class SyncEngine {
|
||||
|
||||
/// Gets the current queue of pending operations.
|
||||
List<SyncOperation> getPendingOperations() {
|
||||
return _operationQueue.where((op) => op.status == SyncStatus.pending).toList();
|
||||
return _operationQueue
|
||||
.where((op) => op.status == SyncStatus.pending)
|
||||
.toList();
|
||||
}
|
||||
|
||||
/// Gets all operations (pending, in-progress, completed, failed).
|
||||
@@ -106,15 +106,15 @@ class SyncEngine {
|
||||
}
|
||||
|
||||
/// Queues a sync operation.
|
||||
///
|
||||
///
|
||||
/// [operation] - The sync operation to queue.
|
||||
///
|
||||
///
|
||||
/// Throws [SyncException] if queue is full.
|
||||
void queueOperation(SyncOperation operation) {
|
||||
if (_isDisposed) {
|
||||
throw SyncException('SyncEngine has been disposed');
|
||||
}
|
||||
|
||||
|
||||
if (_operationQueue.length >= maxQueueSize) {
|
||||
throw SyncException('Sync queue is full (max: $maxQueueSize)');
|
||||
}
|
||||
@@ -129,12 +129,13 @@ class SyncEngine {
|
||||
}
|
||||
|
||||
/// Syncs an item from local storage to Immich.
|
||||
///
|
||||
///
|
||||
/// [itemId] - The ID of the item to sync.
|
||||
/// [priority] - Priority of the sync operation.
|
||||
///
|
||||
///
|
||||
/// Returns the sync operation ID.
|
||||
Future<String> syncToImmich(String itemId, {SyncPriority priority = SyncPriority.normal}) async {
|
||||
Future<String> syncToImmich(String itemId,
|
||||
{SyncPriority priority = SyncPriority.normal}) async {
|
||||
if (_immichService == null) {
|
||||
throw SyncException('Immich service not configured');
|
||||
}
|
||||
@@ -153,12 +154,13 @@ class SyncEngine {
|
||||
}
|
||||
|
||||
/// Syncs metadata from Immich to local storage.
|
||||
///
|
||||
///
|
||||
/// [assetId] - The Immich asset ID to sync.
|
||||
/// [priority] - Priority of the sync operation.
|
||||
///
|
||||
///
|
||||
/// Returns the sync operation ID.
|
||||
Future<String> syncFromImmich(String assetId, {SyncPriority priority = SyncPriority.normal}) async {
|
||||
Future<String> syncFromImmich(String assetId,
|
||||
{SyncPriority priority = SyncPriority.normal}) async {
|
||||
if (_immichService == null) {
|
||||
throw SyncException('Immich service not configured');
|
||||
}
|
||||
@@ -177,12 +179,13 @@ class SyncEngine {
|
||||
}
|
||||
|
||||
/// Syncs metadata to Nostr.
|
||||
///
|
||||
///
|
||||
/// [itemId] - The ID of the item to sync.
|
||||
/// [priority] - Priority of the sync operation.
|
||||
///
|
||||
///
|
||||
/// Returns the sync operation ID.
|
||||
Future<String> syncToNostr(String itemId, {SyncPriority priority = SyncPriority.normal}) async {
|
||||
Future<String> syncToNostr(String itemId,
|
||||
{SyncPriority priority = SyncPriority.normal}) async {
|
||||
if (_nostrService == null) {
|
||||
throw SyncException('Nostr service not configured');
|
||||
}
|
||||
@@ -205,11 +208,12 @@ class SyncEngine {
|
||||
}
|
||||
|
||||
/// Performs a full sync: syncs all items between configured services.
|
||||
///
|
||||
///
|
||||
/// [priority] - Priority of sync operations.
|
||||
///
|
||||
///
|
||||
/// Returns a list of operation IDs.
|
||||
Future<List<String>> syncAll({SyncPriority priority = SyncPriority.normal}) async {
|
||||
Future<List<String>> syncAll(
|
||||
{SyncPriority priority = SyncPriority.normal}) async {
|
||||
final operationIds = <String>[];
|
||||
|
||||
// Sync local items to Immich
|
||||
@@ -239,7 +243,8 @@ class SyncEngine {
|
||||
|
||||
/// Processes the sync queue.
|
||||
Future<void> _processQueue() async {
|
||||
if (_currentOperation != null || _isDisposed) return; // Already processing or disposed
|
||||
if (_currentOperation != null || _isDisposed)
|
||||
return; // Already processing or disposed
|
||||
|
||||
// Sort queue by priority (high first)
|
||||
_operationQueue.sort((a, b) {
|
||||
@@ -250,7 +255,8 @@ class SyncEngine {
|
||||
});
|
||||
|
||||
// Process pending operations
|
||||
while (!_isDisposed && _operationQueue.any((op) => op.status == SyncStatus.pending)) {
|
||||
while (!_isDisposed &&
|
||||
_operationQueue.any((op) => op.status == SyncStatus.pending)) {
|
||||
final operation = _operationQueue.firstWhere(
|
||||
(op) => op.status == SyncStatus.pending,
|
||||
);
|
||||
@@ -264,7 +270,7 @@ class SyncEngine {
|
||||
operation.markSuccess();
|
||||
} catch (e) {
|
||||
operation.markFailed(e.toString());
|
||||
|
||||
|
||||
// Retry if possible
|
||||
if (operation.canRetry() && !_isDisposed) {
|
||||
await Future.delayed(Duration(seconds: operation.retryCount));
|
||||
@@ -374,10 +380,10 @@ class SyncEngine {
|
||||
}
|
||||
|
||||
/// Resolves a conflict between local and remote data.
|
||||
///
|
||||
///
|
||||
/// [localItem] - Local item data.
|
||||
/// [remoteItem] - Remote item data.
|
||||
///
|
||||
///
|
||||
/// Returns the resolved item data.
|
||||
Map<String, dynamic> resolveConflict(
|
||||
Map<String, dynamic> localItem,
|
||||
@@ -421,4 +427,3 @@ class SyncEngine {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user