|
|
|
|
@ -20,6 +20,17 @@ protocol SomeCallCollection { |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
enum ApiCallError: Error, LocalizedError { |
|
|
|
|
case encodingError(id: String, type: String) |
|
|
|
|
|
|
|
|
|
var errorDescription: String? { |
|
|
|
|
switch self { |
|
|
|
|
case .encodingError(let id, let type): |
|
|
|
|
return "Can't encode instance \(type) with id: \(id)" |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// ApiCallCollection is an object communicating with a server to synchronize data managed locally |
|
|
|
|
/// The Api calls are serialized and stored in a JSON file |
|
|
|
|
/// Failing Api calls are stored forever and will be executed again later |
|
|
|
|
@ -267,7 +278,7 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Prepares a call for execution by updating its properties and adding it to its collection for storage |
|
|
|
|
fileprivate func _prepareCall(apiCall: ApiCall<T>) throws { |
|
|
|
|
fileprivate func _prepareCall(apiCall: ApiCall<T>) { |
|
|
|
|
apiCall.lastAttemptDate = Date() |
|
|
|
|
apiCall.attemptsCount += 1 |
|
|
|
|
self.addOrUpdate(apiCall) |
|
|
|
|
@ -291,6 +302,7 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection { |
|
|
|
|
return try await self._sendServerRequest(HTTPMethod.post, instance: instance) |
|
|
|
|
} catch { |
|
|
|
|
self.rescheduleApiCallsIfNecessary() |
|
|
|
|
StoreCenter.main.log(message: "POST failed for \(instance): \(error.localizedDescription)") |
|
|
|
|
Logger.error(error) |
|
|
|
|
} |
|
|
|
|
return nil |
|
|
|
|
@ -303,6 +315,7 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection { |
|
|
|
|
return try await self._sendServerRequest(HTTPMethod.put, instance: instance) |
|
|
|
|
} catch { |
|
|
|
|
self.rescheduleApiCallsIfNecessary() |
|
|
|
|
StoreCenter.main.log(message: "PUT failed for \(instance): \(error.localizedDescription)") |
|
|
|
|
Logger.error(error) |
|
|
|
|
} |
|
|
|
|
return nil |
|
|
|
|
@ -314,6 +327,7 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection { |
|
|
|
|
let _: Empty? = try await self._sendServerRequest(HTTPMethod.delete, instance: instance) |
|
|
|
|
} catch { |
|
|
|
|
self.rescheduleApiCallsIfNecessary() |
|
|
|
|
StoreCenter.main.log(message: "DELETE failed for \(instance): \(error.localizedDescription)") |
|
|
|
|
Logger.error(error) |
|
|
|
|
} |
|
|
|
|
return |
|
|
|
|
@ -331,16 +345,10 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fileprivate func _prepareAndSendCall<V: Decodable>(_ apiCall: ApiCall<T>) async throws -> V? { |
|
|
|
|
try self._prepareCall(apiCall: apiCall) |
|
|
|
|
self._prepareCall(apiCall: apiCall) |
|
|
|
|
return try await self._executeApiCall(apiCall) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Executes an API call |
|
|
|
|
/// For POST requests, potentially copies additional data coming from the server during the insert |
|
|
|
|
// fileprivate func _executeApiCall(_ apiCall: ApiCall<T>) async throws -> T { |
|
|
|
|
// return try await StoreCenter.main.execute(apiCall: apiCall) |
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
/// Executes an API call |
|
|
|
|
/// For POST requests, potentially copies additional data coming from the server during the insert |
|
|
|
|
fileprivate func _executeApiCall<V: Decodable>(_ apiCall: ApiCall<T>) async throws -> V { |
|
|
|
|
|