From 572a2e9becc2930db9e5a66415db0f8ff03f704a Mon Sep 17 00:00:00 2001 From: Laurent Date: Thu, 26 Jun 2025 17:19:55 +0200 Subject: [PATCH] Improves syncing --- LeStorage/ApiCallCollection.swift | 2 +- LeStorage/Store.swift | 1 + LeStorage/StoreCenter.swift | 42 ++++++++++++++++++++++++++----- LeStorage/StoredCollection.swift | 13 ++++++++-- LeStorage/SyncedCollection.swift | 7 +++++- LeStorage/WebSocketManager.swift | 1 + 6 files changed, 56 insertions(+), 10 deletions(-) diff --git a/LeStorage/ApiCallCollection.swift b/LeStorage/ApiCallCollection.swift index 3ded39e..a5cafdd 100644 --- a/LeStorage/ApiCallCollection.swift +++ b/LeStorage/ApiCallCollection.swift @@ -250,7 +250,7 @@ actor ApiCallCollection: SomeCallCollection { @discardableResult func _executeGetCall(apiCall: ApiCall) async throws -> Data { let data = try await self.storeCenter.executeGet(apiCall: apiCall) - Logger.log("GET received = \(T.resourceName())") +// Logger.log("GET received = \(T.resourceName())") if T.self == GetSyncData.self { let syncData = try SyncData(data: data, storeCenter: self.storeCenter) diff --git a/LeStorage/Store.swift b/LeStorage/Store.swift index 5683724..d50b4fb 100644 --- a/LeStorage/Store.swift +++ b/LeStorage/Store.swift @@ -466,6 +466,7 @@ final public class Store { var fileURL = try self._directoryPath() fileURL.append(component: fileName) try content.write(to: fileURL, atomically: false, encoding: .utf8) + Logger.log("write into \(fileURL)...") } /// Returns the URL matching a Storable type diff --git a/LeStorage/StoreCenter.swift b/LeStorage/StoreCenter.swift index 418069a..b1c7760 100644 --- a/LeStorage/StoreCenter.swift +++ b/LeStorage/StoreCenter.swift @@ -67,6 +67,9 @@ public class StoreCenter { var useWebsockets: Bool = false var useSynchronization: Bool = false + var synchronizesData: Bool = false + var wantsToSynchronize: Bool = false + init(directoryName: String? = nil) { self.directoryName = directoryName ?? "storage" @@ -581,19 +584,35 @@ public class StoreCenter { guard self.isAuthenticated else { return } + guard !self.synchronizesData else { +// Logger.log("*** blocked sync") + self.wantsToSynchronize = true + return + } + self.synchronizesData = true + self.wantsToSynchronize = false + let lastSync = self._settingsStorage.item.lastSynchronization - Logger.log("REQUEST sync: \(lastSync)") let syncGetCollection: ApiCallCollection = try self.apiCallCollection() - if await syncGetCollection.hasPendingCalls() { - await syncGetCollection.rescheduleImmediately() - } else { + if await syncGetCollection.hasPendingCalls() == false { + Logger.log("*** START sync: \(lastSync)") let getSyncData = GetSyncData() getSyncData.date = lastSync try await syncGetCollection.sendGetRequest(instance: getSyncData) } +// if await syncGetCollection.hasPendingCalls() { +// await syncGetCollection.rescheduleImmediately() +// Logger.log("=> reschedule") +// } else { +// Logger.log("=> send GET") +// let getSyncData = GetSyncData() +// getSyncData.date = lastSync +// try await syncGetCollection.sendGetRequest(instance: getSyncData) +// } + } @discardableResult func testSynchronizeOnceAsync() async throws -> Data { @@ -653,7 +672,7 @@ public class StoreCenter { await self._syncAddOrUpdate(syncData.sharedRelationshipSets, shared: .granted) await self._syncRevoke(syncData.sharedRelationshipRemovals) - Logger.log("sync content: updates = \(syncData.updates.count) / deletions = \(syncData.deletions.count), grants = \(syncData.grants.count)") +// Logger.log("sync content: updates = \(syncData.updates.count) / deletions = \(syncData.deletions.count), grants = \(syncData.grants.count)") if let dateString = syncData.date { Logger.log("Sets sync date = \(dateString)") @@ -661,6 +680,17 @@ public class StoreCenter { settings.lastSynchronization = dateString } } + + self.synchronizesData = false + if self.wantsToSynchronize { + do { + try await self.synchronizeLastUpdates() + } catch { + Logger.error(error) + } + } + +// Logger.log(">>> SYNC ENDED") NotificationCenter.default.post( name: NSNotification.Name.LeStorageDidSynchronize, object: self) @@ -924,7 +954,7 @@ public class StoreCenter { Logger.w("Invalid update data for \(className)") continue } - Logger.log(">>> UPDATE \(array.count) \(className)") +// Logger.log(">>> UPDATE \(array.count) \(className)") let type = try self.classFromName(className) let decodedArray = try self._decodeArray(type: type, array: array) diff --git a/LeStorage/StoredCollection.swift b/LeStorage/StoredCollection.swift index 0d33968..d5a0c32 100644 --- a/LeStorage/StoredCollection.swift +++ b/LeStorage/StoredCollection.swift @@ -76,6 +76,8 @@ public class StoredCollection: SomeCollection { /// A PendingOperationManager instance that manages operations while the collection is not loaded fileprivate(set) var pendingOperationManager: PendingOperationManager? = nil + fileprivate var _writingTimer: Timer? = nil + /// Indicates whether the collection has changed, thus requiring a write operation fileprivate var _triggerWrite: Bool = false { didSet { @@ -499,12 +501,18 @@ public class StoredCollection: SomeCollection { /// Schedules a write operation fileprivate func _scheduleWrite() { DispatchQueue(label: "lestorage.queue.write", qos: .utility).asyncAndWait { - self._write() + self._cleanTimer() + self._writingTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self._write), userInfo: nil, repeats: false) } } + + fileprivate func _cleanTimer() { + self._writingTimer?.invalidate() + self._writingTimer = nil + } /// Writes all the items as a json array inside a file - fileprivate func _write() { + @objc fileprivate func _write() { do { let jsonString: String = try self.items.jsonString() try self.store.write(content: jsonString, fileName: T.fileName()) @@ -513,6 +521,7 @@ public class StoredCollection: SomeCollection { self.storeCenter.log( message: "write failed for \(T.resourceName()): \(error.localizedDescription)") } + self._cleanTimer() } /// Simply clears the items of the collection diff --git a/LeStorage/SyncedCollection.swift b/LeStorage/SyncedCollection.swift index 4fae2f3..c135ed0 100644 --- a/LeStorage/SyncedCollection.swift +++ b/LeStorage/SyncedCollection.swift @@ -332,10 +332,15 @@ public class SyncedCollection: SomeSyncedCollection, Collect // } /// Deletes the instance in the collection without synchronization - func deleteNoSync(contentOfs sequence: any RandomAccessCollection) { + public func deleteNoSync(contentOfs sequence: any RandomAccessCollection) { self.collection.delete(contentOfs: sequence) } + /// Deletes the instance in the collection without synchronization + public func deleteNoSync(instance: T, cascading: Bool = false) { + self.collection.delete(instance: instance, actionOption: .cascade) + } + func deleteUnusedGranted(instance: T) { guard instance.sharing != nil else { return } self.deleteByStringId(instance.stringId) diff --git a/LeStorage/WebSocketManager.swift b/LeStorage/WebSocketManager.swift index 85b3ade..da8a681 100644 --- a/LeStorage/WebSocketManager.swift +++ b/LeStorage/WebSocketManager.swift @@ -72,6 +72,7 @@ class WebSocketManager: ObservableObject { Task { do { +// Logger.log("Websocket notif, sync...") try await self.storeCenter.synchronizeLastUpdates() } catch { Logger.error(error)