|
|
|
|
@ -40,6 +40,9 @@ let userNamesCall: ServiceCall = ServiceCall( |
|
|
|
|
/// A class used to send HTTP request to the django server |
|
|
|
|
public class Services { |
|
|
|
|
|
|
|
|
|
/// The base API URL to send requests |
|
|
|
|
fileprivate(set) var baseURL: String |
|
|
|
|
|
|
|
|
|
/// A KeychainStore object used to store the user's token |
|
|
|
|
let keychainStore: KeychainStore |
|
|
|
|
|
|
|
|
|
@ -47,13 +50,8 @@ public class Services { |
|
|
|
|
self.baseURL = url |
|
|
|
|
self.keychainStore = KeychainStore(serverId: url) |
|
|
|
|
Logger.log("create keystore with id: \(url)") |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// The base API URL to send requests |
|
|
|
|
fileprivate(set) var baseURL: String |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// MARK: - Base |
|
|
|
|
|
|
|
|
|
/// Runs a request using a configuration object |
|
|
|
|
@ -61,8 +59,7 @@ public class Services { |
|
|
|
|
/// - serviceConf: A instance of ServiceConf |
|
|
|
|
/// - apiCallId: an optional id referencing an ApiCall |
|
|
|
|
fileprivate func _runRequest<U: Decodable>(serviceCall: ServiceCall) |
|
|
|
|
async throws -> U |
|
|
|
|
{ |
|
|
|
|
async throws -> U { |
|
|
|
|
let request = try self._baseRequest(call: serviceCall) |
|
|
|
|
return try await _runRequest(request) |
|
|
|
|
} |
|
|
|
|
@ -84,13 +81,14 @@ public class Services { |
|
|
|
|
/// - request: the URLRequest to run |
|
|
|
|
/// - apiCallId: the id of the ApiCall to delete in case of success, or to schedule for a rerun in case of failure |
|
|
|
|
fileprivate func _runSyncPostRequest<T: SyncedStorable>( |
|
|
|
|
_ request: URLRequest, type: T.Type) async throws { |
|
|
|
|
_ request: URLRequest, type: T.Type) async throws -> [T] { |
|
|
|
|
let debugURL = request.url?.absoluteString ?? "" |
|
|
|
|
// print("Run \(request.httpMethod ?? "") \(debugURL)") |
|
|
|
|
let task: (Data, URLResponse) = try await URLSession.shared.data(for: request) |
|
|
|
|
print("sync POST \(String(describing: T.self)) => \(String(data: task.0, encoding: .utf8) ?? "")") |
|
|
|
|
|
|
|
|
|
var rescheduleApiCalls: Bool = false |
|
|
|
|
var success: [T] = [] |
|
|
|
|
|
|
|
|
|
if let response = task.1 as? HTTPURLResponse { |
|
|
|
|
let statusCode = response.statusCode |
|
|
|
|
@ -100,8 +98,12 @@ public class Services { |
|
|
|
|
|
|
|
|
|
let decoded: BatchResponse<T> = try self._decode(data: task.0) |
|
|
|
|
for result in decoded.results { |
|
|
|
|
|
|
|
|
|
switch result.status { |
|
|
|
|
case 200..<300: |
|
|
|
|
if let data = result.data { |
|
|
|
|
success.append(data) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
try await StoreCenter.main.deleteApiCallById(type: T.self, id: result.apiCallId) |
|
|
|
|
default: |
|
|
|
|
@ -109,7 +111,7 @@ public class Services { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
default: // error |
|
|
|
|
default: // error |
|
|
|
|
Logger.log( |
|
|
|
|
"Failed Run \(request.httpMethod ?? "") \(request.url?.absoluteString ?? "")") |
|
|
|
|
let errorString: String = String(data: task.0, encoding: .utf8) ?? "" |
|
|
|
|
@ -133,8 +135,10 @@ public class Services { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if rescheduleApiCalls { |
|
|
|
|
try await StoreCenter.main.rescheduleApiCalls(type: T.self) |
|
|
|
|
try? await StoreCenter.main.rescheduleApiCalls(type: T.self) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return success |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Runs a request using a traditional URLRequest |
|
|
|
|
@ -496,9 +500,9 @@ public class Services { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Executes an ApiCall |
|
|
|
|
func runApiCalls<T: SyncedStorable>(_ apiCalls: [ApiCall<T>]) async throws { |
|
|
|
|
func runApiCalls<T: SyncedStorable>(_ apiCalls: [ApiCall<T>]) async throws -> [T] { |
|
|
|
|
let request = try self._syncPostRequest(from: apiCalls) |
|
|
|
|
try await self._runSyncPostRequest(request, type: T.self) |
|
|
|
|
return try await self._runSyncPostRequest(request, type: T.self) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Returns the URLRequest for an ApiCall |
|
|
|
|
|