From 184d1fd401edd28e3682a32c9f037b8d07fd71e3 Mon Sep 17 00:00:00 2001 From: tobias <thinkdifferent055@gmail.com> Date: Mon, 6 Dec 2021 13:51:24 +0100 Subject: [PATCH] Add async method for data requests --- AppleLibs.xcodeproj/project.pbxproj | 2 + AppleLibs/Info.plist | 2 +- AppleLibs/Network/Requests/DataManager.swift | 93 ++++++++++++++----- .../Network/Requests/ResponseError.swift | 1 + .../Network/Requests/ResponseHandler.swift | 2 +- 5 files changed, 73 insertions(+), 27 deletions(-) diff --git a/AppleLibs.xcodeproj/project.pbxproj b/AppleLibs.xcodeproj/project.pbxproj index d0453a6..157933f 100644 --- a/AppleLibs.xcodeproj/project.pbxproj +++ b/AppleLibs.xcodeproj/project.pbxproj @@ -519,6 +519,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); + MARKETING_VERSION = 1.1; PRODUCT_BUNDLE_IDENTIFIER = de.tobias.AppleLibs; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -546,6 +547,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); + MARKETING_VERSION = 1.1; PRODUCT_BUNDLE_IDENTIFIER = de.tobias.AppleLibs; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; diff --git a/AppleLibs/Info.plist b/AppleLibs/Info.plist index 9bcb244..c0701c6 100644 --- a/AppleLibs/Info.plist +++ b/AppleLibs/Info.plist @@ -15,7 +15,7 @@ <key>CFBundlePackageType</key> <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string> <key>CFBundleShortVersionString</key> - <string>1.0</string> + <string>$(MARKETING_VERSION)</string> <key>CFBundleVersion</key> <string>$(CURRENT_PROJECT_VERSION)</string> </dict> diff --git a/AppleLibs/Network/Requests/DataManager.swift b/AppleLibs/Network/Requests/DataManager.swift index 07400ab..4f7cf9c 100644 --- a/AppleLibs/Network/Requests/DataManager.swift +++ b/AppleLibs/Network/Requests/DataManager.swift @@ -12,12 +12,12 @@ import os.log public protocol HttpResponseFilter { - func handleResponse(request: Request, data: Data?, responseHandler: ResponseHandler?, sender: Any?, promise: Promise<Data?, ResponseError>) + func handleResponse(request: Request, data: Data?, responseHandler: ResponseHandler?, sender: Any?) throws -> Any? } public protocol HttpSuccessFilter { - func handleResponse(data: Data?, response: HTTPURLResponse, responseHandler: ResponseHandler?, sender: Any?, promise: Promise<Data?, ResponseError>) + func handleResponse(data: Data?, response: HTTPURLResponse, responseHandler: ResponseHandler?, sender: Any?) throws -> Any? } public protocol DataManagerDelegate @@ -91,8 +91,8 @@ public class DataManager: NSObject, URLSessionDelegate public func request(request r: Request, responseHandler: ResponseHandler? = nil, sender: Any? = nil, - promise: Promise<Data?, ResponseError> = Promise<Data?, ResponseError>()) - -> Future<Data?, ResponseError> { + promise: Promise<Any?, ResponseError> = Promise<Any?, ResponseError>()) + -> Future<Any?, ResponseError> { if #available(iOS 14.0, *) { os_log("Request: \(r)") } else { @@ -101,37 +101,74 @@ public class DataManager: NSObject, URLSessionDelegate let request = delegate?.manipulateRequest(request: r) ?? r - if var req: URLRequest = createUrlRequest(request: request) { - if let authentication = request.authentication { - if let headerKey = authentication.headerKey, let headerValue = authentication.headerValue { - req.setValue(headerValue, forHTTPHeaderField: headerKey) - } + guard let req: URLRequest = createUrlRequest(request: request) else { + return promise.future + } + let task = urlSession.dataTask(with: req) { data, response, error in + if let error: NSError = error as NSError? { + promise.fail(error: self.determineResponseError(error)) + return } - let task = urlSession.dataTask(with: req) { data, response, error in - if let error: NSError = error as NSError? { - promise.fail(error: self.determineResponseError(error)) - return - } - - guard let response: HTTPURLResponse = response as? HTTPURLResponse else { - promise.fail(error: ResponseError.networkError(error: .unknown())) - return - } + guard let response: HTTPURLResponse = response as? HTTPURLResponse else { + promise.fail(error: ResponseError.networkError(error: .unknown())) + return + } + do { if response.is2xx { - self.responseOkFilter.handleResponse(data: data, response: response, responseHandler: responseHandler, sender: sender, promise: promise) + let result = try self.responseOkFilter.handleResponse(data: data, response: response, responseHandler: responseHandler, sender: sender) + promise.succeed(value: result) } else if let filter = self.responseFilters[response.statusCode] { - filter.handleResponse(request: request, data: data, responseHandler: responseHandler, sender: sender, promise: promise) + try filter.handleResponse(request: request, data: data, responseHandler: responseHandler, sender: sender) } else { promise.fail(error: ResponseError.getErrorForStatusCode(code: response.statusCode)) } + } catch { + promise.fail(error: ResponseError.clientError(error: error)) } - task.resume() } + task.resume() return promise.future } + @available(iOS 15.0, *) + @available(macCatalyst 15.0.0, *) + @discardableResult + public func request(request r: Request, responseHandler: ResponseHandler? = nil, sender: Any? = nil) async throws -> Any? { + os_log("Request: \(r)") + + let request = delegate?.manipulateRequest(request: r) ?? r + + guard let req: URLRequest = createUrlRequest(request: request) else { + throw ResponseError.requestError + } + + let (data, response): (Data, URLResponse) + do { + (data, response) = try await urlSession.data(for: req) + } catch { + throw self.determineResponseError(error) + } + + guard let response: HTTPURLResponse = response as? HTTPURLResponse else { + throw ResponseError.networkError(error: .unknown()) + } + + do { + if response.is2xx { + return try self.responseOkFilter.handleResponse(data: data, response: response, responseHandler: responseHandler, sender: sender) + } else if let filter = self.responseFilters[response.statusCode] { + return try filter.handleResponse(request: request, data: data, responseHandler: responseHandler, sender: sender) + } else { + throw ResponseError.getErrorForStatusCode(code: response.statusCode) + } + } catch { + throw error + } + } + + private func createUrlRequest(request: Request) -> URLRequest? { if let url: URL = request.constructUrl() { var req: URLRequest = URLRequest(url: url) @@ -144,19 +181,25 @@ public class DataManager: NSObject, URLSessionDelegate } req.timeoutInterval = self.timeout + + if let authentication = request.authentication { + if let headerKey = authentication.headerKey, let headerValue = authentication.headerValue { + req.setValue(headerValue, forHTTPHeaderField: headerKey) + } + } return req } return nil } - fileprivate func determineResponseError(_ error: NSError) -> ResponseError { + fileprivate func determineResponseError(_ error: Error) -> ResponseError { + let error = error as NSError if error.code == NSURLErrorNotConnectedToInternet { return ResponseError.networkError(error: .noInternet) } else if error.code == NSURLErrorTimedOut { return ResponseError.networkError(error: .timeout) - } else { - return ResponseError.networkError(error: .unknown(error: error)) } + return ResponseError.networkError(error: .unknown(error: error)) } public func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { diff --git a/AppleLibs/Network/Requests/ResponseError.swift b/AppleLibs/Network/Requests/ResponseError.swift index 62797e6..9d6f6d4 100644 --- a/AppleLibs/Network/Requests/ResponseError.swift +++ b/AppleLibs/Network/Requests/ResponseError.swift @@ -31,6 +31,7 @@ public enum ResponseError: Error case internalError } + case requestError case authError(error: AuthError) case httpError(error: HttpError) case networkError(error: NetworkError) diff --git a/AppleLibs/Network/Requests/ResponseHandler.swift b/AppleLibs/Network/Requests/ResponseHandler.swift index b21c3ec..091026f 100644 --- a/AppleLibs/Network/Requests/ResponseHandler.swift +++ b/AppleLibs/Network/Requests/ResponseHandler.swift @@ -10,5 +10,5 @@ import Foundation public protocol ResponseHandler { - func handleResponse(data: Data?, response: URLResponse?, sender: Any?) throws + func handleResponse(data: Data?, response: URLResponse?, sender: Any?) throws -> Any? } -- GitLab