diff --git a/Sources/Apexy/AsyncAwaitHelper.swift b/Sources/Apexy/AsyncAwaitHelper.swift new file mode 100644 index 0000000..d7a8333 --- /dev/null +++ b/Sources/Apexy/AsyncAwaitHelper.swift @@ -0,0 +1,25 @@ +// +// AsyncAwaitHelper.swift +// +// +// Created by Aleksei Tiurnin on 31.01.2022. +// + +import Foundation + +@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) +public enum AsyncAwaitHelper { + public typealias ContentContinuation = CheckedContinuation + + public static func adaptToAsync(dataTaskClosure: (ContentContinuation) -> Progress) async throws -> T { + let progressWrapper = ProgressWrapper() + return try await withTaskCancellationHandler(handler: { + progressWrapper.cancel() + }, operation: { + try await withCheckedThrowingContinuation { (continuation: ContentContinuation) in + let progress = dataTaskClosure(continuation) + progressWrapper.progress = progress + } + }) + } +} diff --git a/Sources/Apexy/Client.swift b/Sources/Apexy/Client.swift index cdd405e..4e3aa51 100644 --- a/Sources/Apexy/Client.swift +++ b/Sources/Apexy/Client.swift @@ -37,3 +37,19 @@ public protocol Client: AnyObject { func upload(_ endpoint: T) async throws -> T.Content where T: UploadEndpoint } + +@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) +public extension Client { + + func request(_ endpoint: T) async throws -> T.Content where T: Endpoint { + try await AsyncAwaitHelper.adaptToAsync(dataTaskClosure: { continuation in + request(endpoint, completionHandler: continuation.resume) + }) + } + + func upload(_ endpoint: T) async throws -> T.Content where T: UploadEndpoint { + try await AsyncAwaitHelper.adaptToAsync(dataTaskClosure: { continuation in + upload(endpoint, completionHandler: continuation.resume) + }) + } +} diff --git a/Sources/ApexyAlamofire/AlamofireClient.swift b/Sources/ApexyAlamofire/AlamofireClient.swift index db4479c..4833f72 100755 --- a/Sources/ApexyAlamofire/AlamofireClient.swift +++ b/Sources/ApexyAlamofire/AlamofireClient.swift @@ -181,32 +181,7 @@ open class AlamofireClient: Client { progress.cancellationHandler = { [weak request] in request?.cancel() } return progress } - - @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) - public func request(_ endpoint: T) async throws -> T.Content where T : Endpoint { - typealias ContentContinuation = CheckedContinuation - let progressWrapper = ProgressWrapper() - return try await withTaskCancellationHandler(handler: { - progressWrapper.cancel() - }, operation: { - try await withCheckedThrowingContinuation { (continuation: ContentContinuation) in - progressWrapper.progress = request(endpoint) { continuation.resume(with: $0) } - } - }) - } - - @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) - public func upload(_ endpoint: T) async throws -> T.Content where T : UploadEndpoint { - typealias ContentContinuation = CheckedContinuation - let progressWrapper = ProgressWrapper() - return try await withTaskCancellationHandler(handler: { - progressWrapper.cancel() - }, operation: { - try await withCheckedThrowingContinuation { (continuation: ContentContinuation) in - progressWrapper.progress = upload(endpoint) { continuation.resume(with: $0) } - } - }) - } + } // MARK: - Helper diff --git a/Sources/ApexyURLSession/URLSession+AsyncAwait13.swift b/Sources/ApexyURLSession/URLSession+AsyncAwait13.swift index f95b5be..c69fc09 100644 --- a/Sources/ApexyURLSession/URLSession+AsyncAwait13.swift +++ b/Sources/ApexyURLSession/URLSession+AsyncAwait13.swift @@ -13,35 +13,20 @@ import Foundation @available(watchOS, introduced: 6, deprecated: 8, message: "Extension is no longer necessary. Use API built into SDK") @available(tvOS, introduced: 13, deprecated: 15, message: "Extension is no longer necessary. Use API built into SDK") extension URLSession { - - typealias ContentContinuation = CheckedContinuation<(Data, URLResponse), Error> - - private func adaptToAsync( - dataTaskClosure: (ContentContinuation) -> URLSessionDataTask) async throws -> (Data, URLResponse) { - let progressWrapper = ProgressWrapper() - return try await withTaskCancellationHandler(handler: { - progressWrapper.cancel() - }, operation: { - try await withCheckedThrowingContinuation { (continuation: ContentContinuation) in - let task = dataTaskClosure(continuation) - progressWrapper.progress = task.progress - - task.resume() - } - }) - } public func data( for request: URLRequest, delegate: URLSessionTaskDelegate? = nil) async throws -> (Data, URLResponse) { - return try await adaptToAsync(dataTaskClosure: { continuation in - return self.dataTask(with: request) { data, response, error in + return try await AsyncAwaitHelper.adaptToAsync(dataTaskClosure: { continuation in + let task = dataTask(with: request) { data, response, error in guard let data = data, let response = response else { let error = error ?? URLError(.badServerResponse) return continuation.resume(throwing: error) } continuation.resume(returning: (data, response)) } + task.resume() + return task.progress }) } @@ -49,14 +34,16 @@ extension URLSession { for request: URLRequest, fromFile fileURL: URL, delegate: URLSessionTaskDelegate? = nil) async throws -> (Data, URLResponse) { - return try await adaptToAsync(dataTaskClosure: { continuation in - return self.uploadTask(with: request, fromFile: fileURL) { data, response, error in + return try await AsyncAwaitHelper.adaptToAsync(dataTaskClosure: { continuation in + let task = uploadTask(with: request, fromFile: fileURL) { data, response, error in guard let data = data, let response = response else { let error = error ?? URLError(.badServerResponse) return continuation.resume(throwing: error) } continuation.resume(returning: (data, response)) } + task.resume() + return task.progress }) } @@ -64,14 +51,16 @@ extension URLSession { for request: URLRequest, from bodyData: Data, delegate: URLSessionTaskDelegate? = nil) async throws -> (Data, URLResponse) { - return try await adaptToAsync(dataTaskClosure: { continuation in - return self.uploadTask(with: request, from: bodyData) { data, response, error in + return try await AsyncAwaitHelper.adaptToAsync(dataTaskClosure: { continuation in + let task = uploadTask(with: request, from: bodyData) { data, response, error in guard let data = data, let response = response else { let error = error ?? URLError(.badServerResponse) return continuation.resume(throwing: error) } continuation.resume(returning: (data, response)) } + task.resume() + return task.progress }) } }