2
0
Эх сурвалжийг харах

Throwing an error in adapter now calls retrier to check whether or not to retry.

Christian Noon 9 жил өмнө
parent
commit
5564f6bbdc

+ 13 - 0
Source/AFError.swift

@@ -132,6 +132,19 @@ public enum AFError: Error {
     case responseSerializationFailed(reason: ResponseSerializationFailureReason)
 }
 
+// MARK: - Adapt Error
+
+struct AdaptError: Error {
+    let error: Error
+}
+
+extension Error {
+    var extractedAdaptError: Error {
+        guard let error = self as? AdaptError else { return self }
+        return error.error
+    }
+}
+
 // MARK: - Error Booleans
 
 extension AFError {

+ 6 - 2
Source/Request.swift

@@ -354,8 +354,12 @@ open class DataRequest: Request {
         let urlRequest: URLRequest
 
         func task(session: URLSession, adapter: RequestAdapter?, queue: DispatchQueue) throws -> URLSessionTask {
-            let urlRequest = try self.urlRequest.adapt(using: adapter)
-            return queue.syncResult { session.dataTask(with: urlRequest) }
+            do {
+                let urlRequest = try self.urlRequest.adapt(using: adapter)
+                return queue.syncResult { session.dataTask(with: urlRequest) }
+            } catch {
+                throw AdaptError(error: error)
+            }
         }
     }
 

+ 53 - 10
Source/SessionManager.swift

@@ -231,12 +231,14 @@ open class SessionManager {
         headers: HTTPHeaders? = nil)
         -> DataRequest
     {
+        var originalRequest: URLRequest?
+
         do {
-            let urlRequest = try URLRequest(url: url, method: method, headers: headers)
-            let encodedURLRequest = try encoding.encode(urlRequest, with: parameters)
+            originalRequest = try URLRequest(url: url, method: method, headers: headers)
+            let encodedURLRequest = try encoding.encode(originalRequest!, with: parameters)
             return request(encodedURLRequest)
         } catch {
-            return request(failedWith: error)
+            return request(originalRequest, failedWith: error)
         }
     }
 
@@ -248,9 +250,11 @@ open class SessionManager {
     ///
     /// - returns: The created `DataRequest`.
     open func request(_ urlRequest: URLRequestConvertible) -> DataRequest {
+        var originalRequest: URLRequest?
+
         do {
-            let originalRequest = try urlRequest.asURLRequest()
-            let originalTask = DataRequest.Requestable(urlRequest: originalRequest)
+            originalRequest = try urlRequest.asURLRequest()
+            let originalTask = DataRequest.Requestable(urlRequest: originalRequest!)
 
             let task = try originalTask.task(session: session, adapter: adapter, queue: queue)
             let request = DataRequest(session: session, requestTask: .data(originalTask, task))
@@ -261,15 +265,31 @@ open class SessionManager {
 
             return request
         } catch {
-            return request(failedWith: error)
+            return request(originalRequest, failedWith: error)
         }
     }
 
     // MARK: Private - Request Implementation
 
-    private func request(failedWith error: Error) -> DataRequest {
-        let request = DataRequest(session: session, requestTask: .data(nil, nil), error: error)
-        if startRequestsImmediately { request.resume() }
+    private func request(_ urlRequest: URLRequest?, failedWith error: Error) -> DataRequest {
+        var requestTask: Request.RequestTask = .data(nil, nil)
+
+        if let urlRequest = urlRequest {
+            let originalTask = DataRequest.Requestable(urlRequest: urlRequest)
+            requestTask = .data(originalTask, nil)
+        }
+
+        let isAdaptError = error is AdaptError
+        let error = error.extractedAdaptError
+
+        let request = DataRequest(session: session, requestTask: requestTask, error: error)
+
+        if let retrier = retrier, isAdaptError {
+            allowRetrier(retrier, toRetry: request, with: error)
+        } else {
+            if startRequestsImmediately { request.resume() }
+        }
+
         return request
     }
 
@@ -777,8 +797,31 @@ open class SessionManager {
 
             return true
         } catch {
-            request.delegate.error = error
+            request.delegate.error = error.extractedAdaptError
             return false
         }
     }
+
+    private func allowRetrier(_ retrier: RequestRetrier, toRetry request: Request, with error: Error) {
+        DispatchQueue.utility.async { [weak self] in
+            guard let strongSelf = self else { return }
+
+            retrier.should(strongSelf, retry: request, with: error) { [weak self] shouldRetry, timeDelay in
+                guard let strongSelf = self else { return }
+
+                guard shouldRetry else {
+                    if strongSelf.startRequestsImmediately { request.resume() }
+                    return
+                }
+
+                let retrySucceeded = strongSelf.retry(request)
+
+                if retrySucceeded, let task = request.task {
+                    strongSelf.delegate[task] = request
+                } else {
+                    if strongSelf.startRequestsImmediately { request.resume() }
+                }
+            }
+        }
+    }
 }