杨锴
2025-03-11 90dc3329d1973fda691e357cf4523d5c7c67fa1d
Pods/Alamofire/Source/Features/RequestInterceptor.swift
@@ -25,7 +25,7 @@
import Foundation
/// Stores all state associated with a `URLRequest` being adapted.
public struct RequestAdapterState {
public struct RequestAdapterState: Sendable {
    /// The `UUID` of the `Request` associated with the `URLRequest` to adapt.
    public let requestID: UUID
@@ -36,14 +36,14 @@
// MARK: -
/// A type that can inspect and optionally adapt a `URLRequest` in some manner if necessary.
public protocol RequestAdapter {
public protocol RequestAdapter: Sendable {
    /// Inspects and adapts the specified `URLRequest` in some manner and calls the completion handler with the Result.
    ///
    /// - Parameters:
    ///   - urlRequest: The `URLRequest` to adapt.
    ///   - session:    The `Session` that will execute the `URLRequest`.
    ///   - completion: The completion handler that must be called when adaptation is complete.
    func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void)
    func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping @Sendable (_ result: Result<URLRequest, any Error>) -> Void)
    /// Inspects and adapts the specified `URLRequest` in some manner and calls the completion handler with the Result.
    ///
@@ -51,11 +51,12 @@
    ///   - urlRequest: The `URLRequest` to adapt.
    ///   - state:      The `RequestAdapterState` associated with the `URLRequest`.
    ///   - completion: The completion handler that must be called when adaptation is complete.
    func adapt(_ urlRequest: URLRequest, using state: RequestAdapterState, completion: @escaping (Result<URLRequest, Error>) -> Void)
    func adapt(_ urlRequest: URLRequest, using state: RequestAdapterState, completion: @escaping @Sendable (_ result: Result<URLRequest, any Error>) -> Void)
}
extension RequestAdapter {
    public func adapt(_ urlRequest: URLRequest, using state: RequestAdapterState, completion: @escaping (Result<URLRequest, Error>) -> Void) {
    @preconcurrency
    public func adapt(_ urlRequest: URLRequest, using state: RequestAdapterState, completion: @escaping @Sendable (_ result: Result<URLRequest, any Error>) -> Void) {
        adapt(urlRequest, for: state.session, completion: completion)
    }
}
@@ -63,7 +64,7 @@
// MARK: -
/// Outcome of determination whether retry is necessary.
public enum RetryResult {
public enum RetryResult: Sendable {
    /// Retry should be attempted immediately.
    case retry
    /// Retry should be attempted after the associated `TimeInterval`.
@@ -71,25 +72,25 @@
    /// Do not retry.
    case doNotRetry
    /// Do not retry due to the associated `Error`.
    case doNotRetryWithError(Error)
    case doNotRetryWithError(any Error)
}
extension RetryResult {
    var retryRequired: Bool {
        switch self {
        case .retry, .retryWithDelay: return true
        default: return false
        case .retry, .retryWithDelay: true
        default: false
        }
    }
    var delay: TimeInterval? {
        switch self {
        case let .retryWithDelay(delay): return delay
        default: return nil
        case let .retryWithDelay(delay): delay
        default: nil
        }
    }
    var error: Error? {
    var error: (any Error)? {
        guard case let .doNotRetryWithError(error) = self else { return nil }
        return error
    }
@@ -97,7 +98,7 @@
/// A type that determines whether a request should be retried after being executed by the specified session manager
/// and encountering an error.
public protocol RequestRetrier {
public protocol RequestRetrier: Sendable {
    /// Determines whether the `Request` should be retried by calling the `completion` closure.
    ///
    /// This operation is fully asynchronous. Any amount of time can be taken to determine whether the request needs
@@ -109,7 +110,7 @@
    ///   - session:    `Session` that produced the `Request`.
    ///   - error:      `Error` encountered while executing the `Request`.
    ///   - completion: Completion closure to be executed when a retry decision has been determined.
    func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void)
    func retry(_ request: Request, for session: Session, dueTo error: any Error, completion: @escaping @Sendable (RetryResult) -> Void)
}
// MARK: -
@@ -118,41 +119,53 @@
public protocol RequestInterceptor: RequestAdapter, RequestRetrier {}
extension RequestInterceptor {
    public func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
    @preconcurrency
    public func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping @Sendable (Result<URLRequest, any Error>) -> Void) {
        completion(.success(urlRequest))
    }
    @preconcurrency
    public func retry(_ request: Request,
                      for session: Session,
                      dueTo error: Error,
                      completion: @escaping (RetryResult) -> Void) {
                      dueTo error: any Error,
                      completion: @escaping @Sendable (RetryResult) -> Void) {
        completion(.doNotRetry)
    }
}
/// `RequestAdapter` closure definition.
public typealias AdaptHandler = (URLRequest, Session, _ completion: @escaping (Result<URLRequest, Error>) -> Void) -> Void
public typealias AdaptHandler = @Sendable (_ request: URLRequest,
                                           _ session: Session,
                                           _ completion: @escaping @Sendable (Result<URLRequest, any Error>) -> Void) -> Void
/// `RequestRetrier` closure definition.
public typealias RetryHandler = (Request, Session, Error, _ completion: @escaping (RetryResult) -> Void) -> Void
public typealias RetryHandler = @Sendable (_ request: Request,
                                           _ session: Session,
                                           _ error: any Error,
                                           _ completion: @escaping @Sendable (RetryResult) -> Void) -> Void
// MARK: -
/// Closure-based `RequestAdapter`.
open class Adapter: RequestInterceptor {
open class Adapter: @unchecked Sendable, RequestInterceptor {
    private let adaptHandler: AdaptHandler
    /// Creates an instance using the provided closure.
    ///
    /// - Parameter adaptHandler: `AdaptHandler` closure to be executed when handling request adaptation.
    ///
    @preconcurrency
    public init(_ adaptHandler: @escaping AdaptHandler) {
        self.adaptHandler = adaptHandler
    }
    open func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
    @preconcurrency
    open func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping @Sendable (Result<URLRequest, any Error>) -> Void) {
        adaptHandler(urlRequest, session, completion)
    }
    open func adapt(_ urlRequest: URLRequest, using state: RequestAdapterState, completion: @escaping (Result<URLRequest, Error>) -> Void) {
    @preconcurrency
    open func adapt(_ urlRequest: URLRequest, using state: RequestAdapterState, completion: @escaping @Sendable (Result<URLRequest, any Error>) -> Void) {
        adaptHandler(urlRequest, state.session, completion)
    }
}
@@ -162,6 +175,7 @@
    ///
    /// - Parameter closure: `AdaptHandler` to use to adapt the request.
    /// - Returns:           The `Adapter`.
    @preconcurrency
    public static func adapter(using closure: @escaping AdaptHandler) -> Adapter {
        Adapter(closure)
    }
@@ -170,20 +184,22 @@
// MARK: -
/// Closure-based `RequestRetrier`.
open class Retrier: RequestInterceptor {
open class Retrier: @unchecked Sendable, RequestInterceptor {
    private let retryHandler: RetryHandler
    /// Creates an instance using the provided closure.
    ///
    /// - Parameter retryHandler: `RetryHandler` closure to be executed when handling request retry.
    @preconcurrency
    public init(_ retryHandler: @escaping RetryHandler) {
        self.retryHandler = retryHandler
    }
    @preconcurrency
    open func retry(_ request: Request,
                    for session: Session,
                    dueTo error: Error,
                    completion: @escaping (RetryResult) -> Void) {
                    dueTo error: any Error,
                    completion: @escaping @Sendable (RetryResult) -> Void) {
        retryHandler(request, session, error, completion)
    }
}
@@ -193,6 +209,7 @@
    ///
    /// - Parameter closure: `RetryHandler` to use to retry the request.
    /// - Returns:           The `Retrier`.
    @preconcurrency
    public static func retrier(using closure: @escaping RetryHandler) -> Retrier {
        Retrier(closure)
    }
@@ -201,11 +218,11 @@
// MARK: -
/// `RequestInterceptor` which can use multiple `RequestAdapter` and `RequestRetrier` values.
open class Interceptor: RequestInterceptor {
open class Interceptor: @unchecked Sendable, RequestInterceptor {
    /// All `RequestAdapter`s associated with the instance. These adapters will be run until one fails.
    public let adapters: [RequestAdapter]
    public let adapters: [any RequestAdapter]
    /// All `RequestRetrier`s associated with the instance. These retriers will be run one at a time until one triggers retry.
    public let retriers: [RequestRetrier]
    public let retriers: [any RequestRetrier]
    /// Creates an instance from `AdaptHandler` and `RetryHandler` closures.
    ///
@@ -222,7 +239,7 @@
    /// - Parameters:
    ///   - adapter: `RequestAdapter` value to be used.
    ///   - retrier: `RequestRetrier` value to be used.
    public init(adapter: RequestAdapter, retrier: RequestRetrier) {
    public init(adapter: any RequestAdapter, retrier: any RequestRetrier) {
        adapters = [adapter]
        retriers = [retrier]
    }
@@ -233,26 +250,29 @@
    ///   - adapters:     `RequestAdapter` values to be used.
    ///   - retriers:     `RequestRetrier` values to be used.
    ///   - interceptors: `RequestInterceptor`s to be used.
    public init(adapters: [RequestAdapter] = [], retriers: [RequestRetrier] = [], interceptors: [RequestInterceptor] = []) {
    public init(adapters: [any RequestAdapter] = [],
                retriers: [any RequestRetrier] = [],
                interceptors: [any RequestInterceptor] = []) {
        self.adapters = adapters + interceptors
        self.retriers = retriers + interceptors
    }
    open func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
    @preconcurrency
    open func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping @Sendable (Result<URLRequest, any Error>) -> Void) {
        adapt(urlRequest, for: session, using: adapters, completion: completion)
    }
    private func adapt(_ urlRequest: URLRequest,
                       for session: Session,
                       using adapters: [RequestAdapter],
                       completion: @escaping (Result<URLRequest, Error>) -> Void) {
                       using adapters: [any RequestAdapter],
                       completion: @escaping @Sendable (Result<URLRequest, any Error>) -> Void) {
        var pendingAdapters = adapters
        guard !pendingAdapters.isEmpty else { completion(.success(urlRequest)); return }
        let adapter = pendingAdapters.removeFirst()
        adapter.adapt(urlRequest, for: session) { result in
        adapter.adapt(urlRequest, for: session) { [pendingAdapters] result in
            switch result {
            case let .success(urlRequest):
                self.adapt(urlRequest, for: session, using: pendingAdapters, completion: completion)
@@ -262,21 +282,22 @@
        }
    }
    open func adapt(_ urlRequest: URLRequest, using state: RequestAdapterState, completion: @escaping (Result<URLRequest, Error>) -> Void) {
    @preconcurrency
    open func adapt(_ urlRequest: URLRequest, using state: RequestAdapterState, completion: @escaping @Sendable (Result<URLRequest, any Error>) -> Void) {
        adapt(urlRequest, using: state, adapters: adapters, completion: completion)
    }
    private func adapt(_ urlRequest: URLRequest,
                       using state: RequestAdapterState,
                       adapters: [RequestAdapter],
                       completion: @escaping (Result<URLRequest, Error>) -> Void) {
                       adapters: [any RequestAdapter],
                       completion: @escaping @Sendable (Result<URLRequest, any Error>) -> Void) {
        var pendingAdapters = adapters
        guard !pendingAdapters.isEmpty else { completion(.success(urlRequest)); return }
        let adapter = pendingAdapters.removeFirst()
        adapter.adapt(urlRequest, using: state) { result in
        adapter.adapt(urlRequest, using: state) { [pendingAdapters] result in
            switch result {
            case let .success(urlRequest):
                self.adapt(urlRequest, using: state, adapters: pendingAdapters, completion: completion)
@@ -286,25 +307,26 @@
        }
    }
    @preconcurrency
    open func retry(_ request: Request,
                    for session: Session,
                    dueTo error: Error,
                    completion: @escaping (RetryResult) -> Void) {
                    dueTo error: any Error,
                    completion: @escaping @Sendable (RetryResult) -> Void) {
        retry(request, for: session, dueTo: error, using: retriers, completion: completion)
    }
    private func retry(_ request: Request,
                       for session: Session,
                       dueTo error: Error,
                       using retriers: [RequestRetrier],
                       completion: @escaping (RetryResult) -> Void) {
                       dueTo error: any Error,
                       using retriers: [any RequestRetrier],
                       completion: @escaping @Sendable (RetryResult) -> Void) {
        var pendingRetriers = retriers
        guard !pendingRetriers.isEmpty else { completion(.doNotRetry); return }
        let retrier = pendingRetriers.removeFirst()
        retrier.retry(request, for: session, dueTo: error) { result in
        retrier.retry(request, for: session, dueTo: error) { [pendingRetriers] result in
            switch result {
            case .retry, .retryWithDelay, .doNotRetryWithError:
                completion(result)
@@ -323,6 +345,7 @@
    ///   - adapter: `AdapterHandler`to use to adapt the request.
    ///   - retrier: `RetryHandler` to use to retry the request.
    /// - Returns:   The `Interceptor`.
    @preconcurrency
    public static func interceptor(adapter: @escaping AdaptHandler, retrier: @escaping RetryHandler) -> Interceptor {
        Interceptor(adaptHandler: adapter, retryHandler: retrier)
    }
@@ -332,7 +355,8 @@
    ///   - adapter: `RequestAdapter` to use to adapt the request
    ///   - retrier: `RequestRetrier` to use to retry the request.
    /// - Returns:   The `Interceptor`.
    public static func interceptor(adapter: RequestAdapter, retrier: RequestRetrier) -> Interceptor {
    @preconcurrency
    public static func interceptor(adapter: any RequestAdapter, retrier: any RequestRetrier) -> Interceptor {
        Interceptor(adapter: adapter, retrier: retrier)
    }
@@ -343,9 +367,10 @@
    ///                   a retry is triggered.
    ///   - interceptors: `RequestInterceptor`s to use to intercept the request.
    /// - Returns:        The `Interceptor`.
    public static func interceptor(adapters: [RequestAdapter] = [],
                                   retriers: [RequestRetrier] = [],
                                   interceptors: [RequestInterceptor] = []) -> Interceptor {
    @preconcurrency
    public static func interceptor(adapters: [any RequestAdapter] = [],
                                   retriers: [any RequestRetrier] = [],
                                   interceptors: [any RequestInterceptor] = []) -> Interceptor {
        Interceptor(adapters: adapters, retriers: retriers, interceptors: interceptors)
    }
}