|
|
|
|
@ -409,14 +409,13 @@ public class StoreCenter { |
|
|
|
|
|
|
|
|
|
// MARK: - Synchronization |
|
|
|
|
|
|
|
|
|
/// Creates the ApiCallCollection to manage the calls to the API |
|
|
|
|
fileprivate func _createSyncApiCallCollection() { |
|
|
|
|
self.loadApiCallCollection(type: GetSyncData.self) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Loads all the data from the server for the users |
|
|
|
|
public func initialSynchronization() { |
|
|
|
|
self._settingsStorage.update { settings in |
|
|
|
|
settings.lastSynchronization = Date() |
|
|
|
|
} |
|
|
|
|
Store.main.loadCollectionsFromServer() |
|
|
|
|
|
|
|
|
|
// request data that has been shared with the user |
|
|
|
|
@ -430,6 +429,7 @@ public class StoreCenter { |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Basically asks the server for new content |
|
|
|
|
func synchronizeLastUpdates() async throws { |
|
|
|
|
|
|
|
|
|
let lastSync = self._settingsStorage.item.lastSynchronization |
|
|
|
|
@ -445,6 +445,7 @@ public class StoreCenter { |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Processes Data Access data |
|
|
|
|
func userDataAccessRetrieved(_ data: Data) { |
|
|
|
|
do { |
|
|
|
|
guard |
|
|
|
|
@ -463,6 +464,7 @@ public class StoreCenter { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Processes the data coming from a sync request |
|
|
|
|
func synchronizeContent(_ data: Data) { |
|
|
|
|
|
|
|
|
|
do { |
|
|
|
|
@ -504,6 +506,10 @@ public class StoreCenter { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Processes data that should be inserted or updated inside the app |
|
|
|
|
/// - Parameters: |
|
|
|
|
/// - updates: the server updates |
|
|
|
|
/// - shared: indicates if the content should be flagged as shared |
|
|
|
|
fileprivate func _parseSyncUpdates(_ updates: [String: Any], shared: Bool = false) throws { |
|
|
|
|
for (className, updateData) in updates { |
|
|
|
|
guard let updateArray = updateData as? [[String: Any]] else { |
|
|
|
|
@ -530,6 +536,7 @@ public class StoreCenter { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Processes data that should be deleted inside the app |
|
|
|
|
fileprivate func _parseSyncDeletions(_ deletions: [String: Any]) throws { |
|
|
|
|
for (className, deleteData) in deletions { |
|
|
|
|
guard let deletedItems = deleteData as? [Any] else { |
|
|
|
|
@ -552,6 +559,7 @@ public class StoreCenter { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Processes data that has been revoked |
|
|
|
|
fileprivate func _parseSyncRevocations(_ deletions: [String: Any], parents: [[String: Any]]?) throws { |
|
|
|
|
for (className, revocationData) in deletions { |
|
|
|
|
guard let revokedItems = revocationData as? [Any] else { |
|
|
|
|
@ -590,6 +598,7 @@ public class StoreCenter { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Returns a Type object for a class name |
|
|
|
|
static func classFromName(_ className: String) throws -> any SyncedStorable.Type { |
|
|
|
|
if let type = ClassLoader.getClass(className) as? any SyncedStorable.Type { |
|
|
|
|
return type |
|
|
|
|
@ -598,6 +607,7 @@ public class StoreCenter { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Returns the store corresponding to the provided id, and creates one if necessary |
|
|
|
|
fileprivate func _store(id: String?) -> Store { |
|
|
|
|
if let storeId = id { |
|
|
|
|
if let store = self._stores[storeId] { |
|
|
|
|
@ -612,12 +622,14 @@ public class StoreCenter { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Returns whether a data has already been deleted by, to avoid inserting it again |
|
|
|
|
fileprivate func _hasAlreadyBeenDeleted<T: Storable>(_ instance: T) -> Bool { |
|
|
|
|
return self._dataLogs.contains(where: { |
|
|
|
|
$0.dataId == instance.stringId && $0.operation == .delete |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Adds or updates an instance into the store |
|
|
|
|
func synchronizationAddOrUpdate<T: SyncedStorable>(_ instance: T, storeId: String?, shared: Bool) { |
|
|
|
|
let hasAlreadyBeenDeleted: Bool = self._hasAlreadyBeenDeleted(instance) |
|
|
|
|
if !hasAlreadyBeenDeleted { |
|
|
|
|
@ -627,6 +639,7 @@ public class StoreCenter { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Deletes an instance with the given parameters |
|
|
|
|
func synchronizationDelete(id: String, model: String, storeId: String?) { |
|
|
|
|
|
|
|
|
|
DispatchQueue.main.async { |
|
|
|
|
@ -640,6 +653,7 @@ public class StoreCenter { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Revokes a data that has been shared with the user |
|
|
|
|
func synchronizationRevoke(id: String, model: String, storeId: String?) { |
|
|
|
|
|
|
|
|
|
DispatchQueue.main.async { |
|
|
|
|
@ -657,25 +671,25 @@ public class StoreCenter { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Returns whether an instance has been shared with the user |
|
|
|
|
fileprivate func _instanceShared<T: SyncedStorable>(id: String, type: T.Type) -> Bool { |
|
|
|
|
let realId: T.ID = T.buildRealId(id: id) |
|
|
|
|
let instance: T? = Store.main.findById(realId) |
|
|
|
|
return instance?.shared == true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Deletes a data log by data id |
|
|
|
|
fileprivate func _cleanupDataLog(dataId: String) { |
|
|
|
|
let logs = self._dataLogs.filter { $0.dataId == dataId } |
|
|
|
|
self._dataLogs.delete(contentOfs: logs) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// func createInsertLog<T: Storable>(_ instance: T) { |
|
|
|
|
// self._addDataLog(instance, method: .post) |
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
/// Creates a delete log for an instance |
|
|
|
|
func createDeleteLog<T: Storable>(_ instance: T) { |
|
|
|
|
self._addDataLog(instance, method: .delete) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Adds a datalog for an instance with the associated method |
|
|
|
|
fileprivate func _addDataLog<T: Storable>(_ instance: T, method: HTTPMethod) { |
|
|
|
|
let dataLog = DataLog( |
|
|
|
|
dataId: instance.stringId, modelName: String(describing: T.self), operation: method) |
|
|
|
|
@ -684,6 +698,7 @@ public class StoreCenter { |
|
|
|
|
|
|
|
|
|
// MARK: - Miscellanous |
|
|
|
|
|
|
|
|
|
/// Returns the count of api calls for a Type |
|
|
|
|
public func apiCallCount<T: SyncedStorable>(type: T.Type) async -> Int { |
|
|
|
|
do { |
|
|
|
|
let collection: ApiCallCollection<T> = try self.apiCallCollection() |
|
|
|
|
@ -842,6 +857,7 @@ public class StoreCenter { |
|
|
|
|
|
|
|
|
|
// MARK: - Data Access |
|
|
|
|
|
|
|
|
|
/// Returns the list of users have access to a data given its id |
|
|
|
|
public func authorizedUsers(for modelId: String) -> [String] { |
|
|
|
|
guard let dataAccessCollection = self._dataAccess else { |
|
|
|
|
return [] |
|
|
|
|
@ -852,6 +868,7 @@ public class StoreCenter { |
|
|
|
|
return [] |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Sets the the list of authorized users for an instance |
|
|
|
|
public func setAuthorizedUsers<T: SyncedStorable>(for instance: T, users: [String]) throws { |
|
|
|
|
guard let dataAccessCollection = self._dataAccess else { |
|
|
|
|
return |
|
|
|
|
|