|
|
|
|
@ -427,52 +427,31 @@ public class StoreCenter { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if let updates = json["updates"] as? [String: Any] { |
|
|
|
|
do { |
|
|
|
|
try self._parseSyncUpdates(updates) |
|
|
|
|
} catch { |
|
|
|
|
StoreCenter.main.log(message: error.localizedDescription) |
|
|
|
|
Logger.error(error) |
|
|
|
|
} |
|
|
|
|
try self._parseSyncUpdates(updates) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if let deletions = json["deletions"] as? [String: Any] { |
|
|
|
|
do { |
|
|
|
|
try self._parseSyncDeletions(deletions) |
|
|
|
|
} catch { |
|
|
|
|
StoreCenter.main.log(message: error.localizedDescription) |
|
|
|
|
Logger.error(error) |
|
|
|
|
} |
|
|
|
|
try self._parseSyncDeletions(deletions) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if let updates = json["grants"] as? [String: Any] { |
|
|
|
|
do { |
|
|
|
|
try self._parseSyncUpdates(updates) |
|
|
|
|
} catch { |
|
|
|
|
StoreCenter.main.log(message: error.localizedDescription) |
|
|
|
|
Logger.error(error) |
|
|
|
|
} |
|
|
|
|
try self._parseSyncUpdates(updates) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if let deletions = json["revocations"] as? [String: Any] { |
|
|
|
|
do { |
|
|
|
|
try self._parseSyncRevocations(deletions) |
|
|
|
|
} catch { |
|
|
|
|
StoreCenter.main.log(message: error.localizedDescription) |
|
|
|
|
Logger.error(error) |
|
|
|
|
} |
|
|
|
|
if let revocations = json["revocations"] as? [String: Any] { |
|
|
|
|
try self._parseSyncRevocations(revocations, parents: json["revocation_parents"] as? [String: Any]) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if let dateString = json["date"] as? String, |
|
|
|
|
let date = Date.iso8601FractionalFormatter.date(from: dateString) { |
|
|
|
|
Logger.log("date = \(date)") |
|
|
|
|
Logger.log("Sets sync date = \(date)") |
|
|
|
|
self._settingsStorage.update { settings in |
|
|
|
|
settings.lastSynchronization = date |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
Logger.w("no date set for the last sync!!!") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} catch { |
|
|
|
|
StoreCenter.main.log(message: error.localizedDescription) |
|
|
|
|
Logger.error(error) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
@ -514,7 +493,7 @@ public class StoreCenter { |
|
|
|
|
|
|
|
|
|
do { |
|
|
|
|
let data = try JSONSerialization.data(withJSONObject: deleted, options: []) |
|
|
|
|
let deletedObject = try JSON.decoder.decode(DeletedObject.self, from: data) |
|
|
|
|
let deletedObject = try JSON.decoder.decode(ObjectIdentifier.self, from: data) |
|
|
|
|
|
|
|
|
|
StoreCenter.main.synchronizationDelete(id: deletedObject.modelId, model: className, storeId: deletedObject.storeId) |
|
|
|
|
} catch { |
|
|
|
|
@ -525,26 +504,41 @@ public class StoreCenter { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fileprivate func _parseSyncRevocations(_ deletions: [String: Any]) throws { |
|
|
|
|
fileprivate func _parseSyncRevocations(_ deletions: [String: Any], parents: [String: Any]?) throws { |
|
|
|
|
for (className, revocationData) in deletions { |
|
|
|
|
guard let rovokedItems = revocationData as? [Any] else { |
|
|
|
|
guard let revokedItems = revocationData as? [Any] else { |
|
|
|
|
Logger.w("Invalid update data for \(className)") |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for revoked in rovokedItems { |
|
|
|
|
|
|
|
|
|
for revoked in revokedItems { |
|
|
|
|
do { |
|
|
|
|
let data = try JSONSerialization.data(withJSONObject: revoked, options: []) |
|
|
|
|
let deletedObject = try JSON.decoder.decode(DeletedObject.self, from: data) |
|
|
|
|
|
|
|
|
|
StoreCenter.main.synchronizationDelete(id: deletedObject.modelId, model: className, storeId: deletedObject.storeId) |
|
|
|
|
let revokedObject = try JSON.decoder.decode(ObjectIdentifier.self, from: data) |
|
|
|
|
StoreCenter.main.synchronizationDelete(id: revokedObject.modelId, model: className, storeId: revokedObject.storeId) |
|
|
|
|
} catch { |
|
|
|
|
Logger.error(error) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if let parents { |
|
|
|
|
for (className, parentData) in parents { |
|
|
|
|
guard let parentItems = parentData as? [Any] else { |
|
|
|
|
Logger.w("Invalid update data for \(className): \(parentData)") |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
for parentItem in parentItems { |
|
|
|
|
do { |
|
|
|
|
let data = try JSONSerialization.data(withJSONObject: parentItem, options: []) |
|
|
|
|
let revokedObject = try JSON.decoder.decode(ObjectIdentifier.self, from: data) |
|
|
|
|
StoreCenter.main.synchronizationRevoke(id: revokedObject.modelId, model: className, storeId: revokedObject.storeId) |
|
|
|
|
} catch { |
|
|
|
|
Logger.error(error) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static func classFromName(_ className: String) throws -> any SyncedStorable.Type { |
|
|
|
|
@ -602,22 +596,16 @@ public class StoreCenter { |
|
|
|
|
DispatchQueue.main.async { |
|
|
|
|
do { |
|
|
|
|
let type = try StoreCenter.classFromName(model) |
|
|
|
|
try self._store(id: storeId).revokeNoSync(type: type, id: id) |
|
|
|
|
let count = Store.main.referenceCount(type: type, id: id) |
|
|
|
|
if count == 0 { |
|
|
|
|
try self._store(id: storeId).deleteNoSync(type: type, id: id) |
|
|
|
|
} |
|
|
|
|
} catch { |
|
|
|
|
Logger.error(error) |
|
|
|
|
} |
|
|
|
|
self._cleanupDataLog(dataId: id) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// func synchronizationDelete<T: Storable>(instance: T, storeId: String?) { |
|
|
|
|
// DispatchQueue.main.async { |
|
|
|
|
// self._store(id: storeId)?.deleteNoSync(instance: instance) |
|
|
|
|
// self._cleanupDataLog(dataId: instance.stringId) |
|
|
|
|
// } |
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
fileprivate func _cleanupDataLog(dataId: String) { |
|
|
|
|
let logs = self._dataLogs.filter { $0.dataId == dataId } |
|
|
|
|
self._dataLogs.delete(contentOfs: logs) |
|
|
|
|
@ -795,6 +783,44 @@ public class StoreCenter { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// MARK: - Data Access |
|
|
|
|
|
|
|
|
|
public func giveUserAccess<T: SyncedStorable>(_ user: String, data: T) throws { |
|
|
|
|
guard let dataAccessCollection = self._dataAccess else { |
|
|
|
|
throw LeStorageError.dataAccessCollectionNotDefined |
|
|
|
|
} |
|
|
|
|
guard let userId = self.userId else { |
|
|
|
|
throw LeStorageError.cantCreateDataAccessBecauseUserIdIsNil |
|
|
|
|
} |
|
|
|
|
let collection: StoredCollection<T> = try Store.main.collection() |
|
|
|
|
guard collection.findById(data.id) != nil else { |
|
|
|
|
throw LeStorageError.cantCreateDataAccessBecauseNotInMainStore |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if let dataAccess = dataAccessCollection.first(where: { $0.modelId == data.stringId }) { |
|
|
|
|
dataAccess.sharedWith.append(user) |
|
|
|
|
dataAccessCollection.addOrUpdate(instance: dataAccess) |
|
|
|
|
} else { |
|
|
|
|
let dataAccess = DataAccess(owner: userId, sharedWith: [user], modelName: T.resourceName(), modelId: data.stringId) |
|
|
|
|
dataAccessCollection.addOrUpdate(instance: dataAccess) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public func removeUserAccess<T: SyncedStorable>(_ user: String, data: T) { |
|
|
|
|
guard let dataAccessCollection = self._dataAccess else { |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
if let dataAccess = dataAccessCollection.first(where: { $0.modelId == data.stringId }) { |
|
|
|
|
dataAccess.sharedWith.removeAll(where: { $0 == user }) |
|
|
|
|
|
|
|
|
|
if dataAccess.sharedWith.isEmpty { |
|
|
|
|
dataAccessCollection.delete(instance: dataAccess) |
|
|
|
|
} else { |
|
|
|
|
dataAccessCollection.addOrUpdate(instance: dataAccess) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// MARK: - Logs |
|
|
|
|
|
|
|
|
|
/// Returns the logs collection and instantiates it if necessary |
|
|
|
|
@ -830,7 +856,7 @@ public class StoreCenter { |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
class DeletedObject: Codable { |
|
|
|
|
class ObjectIdentifier: Codable { |
|
|
|
|
var modelId: String |
|
|
|
|
var storeId: String? |
|
|
|
|
} |
|
|
|
|
|