Fixes sync issues

sync2
Laurent 9 months ago
parent a3f6ad618e
commit a638947ea6
  1. 19
      LeStorage/ApiCallCollection.swift
  2. 13
      LeStorage/Codables/GetSyncData.swift
  3. 2
      LeStorage/Codables/Settings.swift
  4. 11
      LeStorage/Services.swift
  5. 23
      LeStorage/StoreCenter.swift
  6. 2
      LeStorage/StoredCollection+Sync.swift
  7. 7
      LeStorage/Utils/Date+Extensions.swift
  8. 2
      LeStorage/WebSocketManager.swift

@ -170,13 +170,13 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection {
func rescheduleApiCallsIfNecessary() {
if self.items.isNotEmpty && !self._isRescheduling {
self._schedulingTask = Task {
await self._rescheduleApiCalls()
await self._waitAndExecuteApiCalls()
}
}
}
/// Reschedule the execution of API calls
fileprivate func _rescheduleApiCalls() async {
fileprivate func _waitAndExecuteApiCalls() async {
// Logger.log("\(T.resourceName()) > RESCHED")
guard !self._isRescheduling, StoreCenter.main.collectionsCanSynchronize else { return }
@ -199,7 +199,6 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection {
if T.copyServerResponse {
StoreCenter.main.updateLocalInstances(results)
}
// self._attemptLoops = -1
}
} catch {
Logger.error(error)
@ -208,7 +207,7 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection {
self._isRescheduling = false
if self.items.isNotEmpty {
await self._rescheduleApiCalls()
await self._waitAndExecuteApiCalls()
}
// Logger.log("\(T.resourceName()) > isRescheduling = \(self._isRescheduling)")
@ -218,7 +217,7 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection {
fileprivate func _wait() async {
#if DEBUG
let seconds = 2 * self._attemptLoops
let seconds = self._attemptLoops
#else
let delay = pow(2, self._attemptLoops)
let seconds = NSDecimalNumber(decimal: delay).intValue
@ -236,10 +235,10 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection {
/// Returns an APICall instance for the Storable [instance] and an HTTP [method]
/// The method updates existing calls or creates a new one
fileprivate func _call(method: HTTPMethod, instance: T? = nil) throws -> ApiCall<T>? {
fileprivate func _call(method: HTTPMethod, instance: T? = nil) async throws -> ApiCall<T>? {
if let instance {
return try self._callForInstance(method, instance: instance)
return try await self._callForInstance(method, instance: instance)
} else {
if self.items.contains(where: { $0.method == .get }) {
return nil
@ -249,7 +248,7 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection {
}
}
fileprivate func _callForInstance(_ method: HTTPMethod, instance: T) throws -> ApiCall<T>? {
fileprivate func _callForInstance(_ method: HTTPMethod, instance: T) async throws -> ApiCall<T>? {
if let existingCall = self.items.first(where: { $0.dataId == instance.stringId }) {
switch method {
@ -322,10 +321,8 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection {
/// Initiates the process of sending the data with the server
fileprivate func _sendServerRequest<V: Decodable>(_ method: HTTPMethod, instance: T? = nil) async throws -> V? {
if let apiCall = try self._call(method: method, instance: instance) {
if let apiCall = try await self._call(method: method, instance: instance) {
return try await self._prepareAndSendCall(apiCall)
// try self._prepareCall(apiCall: apiCall)
// return try await self._executeApiCall(apiCall)
} else {
return nil
}

@ -9,25 +9,26 @@ import Foundation
class GetSyncData: SyncedModelObject, SyncedStorable, URLParameterConvertible {
var date: String = ""
static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
static func resourceName() -> String {
return "data"
return "sync-requests"
}
func copy(from other: any Storable) {
guard let getSyncData = other as? GetSyncData else { return }
self.lastUpdate = getSyncData.lastUpdate
self.date = getSyncData.date
}
func queryParameters() -> [String : String] {
return ["last_update" : self._formattedLastUpdate]
return ["last_update" : self._formattedLastUpdate,
"device_id" : StoreCenter.main.deviceId()]
}
fileprivate var _formattedLastUpdate: String {
let formattedDate = Date.iso8601FractionalFormatter.string(from: self.lastUpdate)
let encodedDate =
formattedDate.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
let encodedDate = self.date.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
return encodedDate.replacingOccurrences(of: "+", with: "%2B")
}

@ -16,6 +16,6 @@ class Settings: MicroStorable {
var userId: String? = nil
var username: String? = nil
var deviceId: String? = nil
var lastSynchronization: Date = Date()
var lastSynchronization: String = "2000-01-01T00:00:00.000000Z"
}

@ -271,7 +271,7 @@ public class Services {
// print("sync POST \(String(describing: T.self)) => \(String(data: task.0, encoding: .utf8) ?? "")")
var rescheduleApiCalls: Bool = false
var success: [T] = []
var successes: [T] = []
if let response = task.1 as? HTTPURLResponse {
let statusCode = response.statusCode
@ -285,11 +285,14 @@ public class Services {
switch result.status {
case 200..<300:
if let data = result.data {
success.append(data)
successes.append(data)
}
try await StoreCenter.main.deleteApiCallById(type: T.self, id: result.apiCallId)
default:
if let message = result.message {
print(message)
}
rescheduleApiCalls = true
}
}
@ -321,7 +324,7 @@ public class Services {
try? await StoreCenter.main.rescheduleApiCalls(type: T.self)
}
return success
return successes
}
/// Returns the URLRequest for an ApiCall
@ -596,7 +599,7 @@ public class Services {
let user: U = try await self._runRequest(postRequest)
// StoreCenter.main.setUserUUID(uuidString: user.id)
// StoreCenter.main.setUserName(user.username)
StoreCenter.main.userDidLog(user: user, date: loggingDate)
StoreCenter.main.userDidLogIn(user: user, at: loggingDate)
return user
}

@ -66,7 +66,7 @@ public class StoreCenter {
self._resumeApiCalls()
// self._configureWebSocket()
}
Logger.log("device Id = \(self.deviceId())")
// Logger.log("device Id = \(self.deviceId())")
}
public func configureURLs(secureScheme: Bool, domain: String) {
@ -173,11 +173,15 @@ public class StoreCenter {
// MARK: - Settings
/// Sets the user info given a user
func userDidLog(user: UserBase, date: Date) {
func userDidLogIn(user: UserBase, at date: Date) {
self._settingsStorage.update { settings in
settings.userId = user.id
settings.username = user.username
settings.lastSynchronization = date
let date = Date.microSecondFormatter.string(from: date)
Logger.log("LOG date = \(date)")
settings.lastSynchronization = Date.microSecondFormatter.string(from: Date.distantPast)
self._configureWebSocket()
}
}
@ -210,7 +214,7 @@ public class StoreCenter {
self._settingsStorage.update { settings in
settings.username = nil
settings.userId = nil
settings.lastSynchronization = Date()
settings.lastSynchronization = Date.microSecondFormatter.string(from: Date())
self._webSocketManager = nil
}
@ -467,7 +471,7 @@ public class StoreCenter {
await syncGetCollection.rescheduleImmediately()
} else {
let getSyncData = GetSyncData()
getSyncData.lastUpdate = lastSync
getSyncData.date = lastSync
try await syncGetCollection.sendGetRequest(instance: getSyncData)
}
@ -517,11 +521,10 @@ public class StoreCenter {
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("Sets sync date = \(date)")
if let dateString = json["date"] as? String {
Logger.log("Sets sync date = \(dateString)")
self._settingsStorage.update { settings in
settings.lastSynchronization = date
settings.lastSynchronization = dateString
}
}
@ -546,7 +549,7 @@ public class StoreCenter {
Logger.w("Invalid update data for \(className)")
continue
}
// Logger.log(">>> UPDATE \(updateArray.count) \(className)")
Logger.log(">>> UPDATE \(updateArray.count) \(className)")
let type = try StoreCenter.classFromName(className)

@ -276,7 +276,7 @@ extension StoredCollection: SomeSyncedCollection where T : SyncedStorable {
if instance.lastUpdate > localInstance.lastUpdate {
self.updateItem(instance, index: index)
} else {
Logger.log("do not update: \(instance.lastUpdate.timeIntervalSince1970) / local: \(localInstance.lastUpdate.timeIntervalSince1970)")
print("do not update \(T.resourceName()): \(instance.lastUpdate.timeIntervalSince1970) / local: \(localInstance.lastUpdate.timeIntervalSince1970)")
}
} else { // insert
if shared {

@ -23,4 +23,11 @@ extension Date {
return iso8601Formatter
}
public static var microSecondFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'" // puts 000 for the last decimals
formatter.timeZone = TimeZone(abbreviation: "UTC")
return formatter
}()
}

@ -61,7 +61,7 @@ class WebSocketManager: ObservableObject {
self._failure = false
switch message {
case .string(let deviceId):
print("device id = \(StoreCenter.main.deviceId()), origin id: \(deviceId)")
// print("device id = \(StoreCenter.main.deviceId()), origin id: \(deviceId)")
guard StoreCenter.main.deviceId() != deviceId else {
break
}

Loading…
Cancel
Save