Skip to content

Request Retrier

howardfuntek edited this page Feb 12, 2019 · 1 revision

Situation

If the token is expired or invalid, we provide a mechanism to enable request retry.

Reference: Alamofire request retrier

Solution

Here is a retrier examaple.

class IMRequestRetrier: RequestAdapter, RequestRetrier {
    
    private var isRefreshing = false
    private var requestsToRetry: [RequestRetryCompletion] = []
    
    func adapt(_ urlRequest: URLRequest) throws -> URLRequest {
        var urlRequest = urlRequest
        urlRequest.setValue(IMKit.clientKey, forHTTPHeaderField: "CLIENT_KEY")
        urlRequest.setValue(IMKit.token, forHTTPHeaderField: "Authorization")
        return urlRequest
    }
    
    func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion) {
        if let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401 {
            requestsToRetry.append(completion)
            if !isRefreshing {
                if (request.retryCount >= 3) { completion(false, 0.0) }
                isRefreshing = true
                fetchToken().done { token in
                    IMKit.token = token
                    IMSocketManager.shared.connect()
                    self.requestsToRetry.forEach { $0(true, 1.0) }
                    self.requestsToRetry.removeAll()
                    self.isRefreshing = false
                    }.catch { error in
                        print(error)
                        completion(true, 1.0)
                }
            }
        } else {
            completion(false, 0.0)
        }
    }
    
    // Todo: Implement your own auth logic, use IMFetchTokenTask by default
    private func fetchToken() -> Promise<String> {
        return IMFetchTokenTask().perform(uid: IMKit.uid)
    }
}

Then, set the request retrier before using IMKit. For instance, set it in AppDelegate.

class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
       
        let requestRetrier = IMRequestRetrier()
        IMSessionManager.shared.adapter = requestRetrier
        IMSessionManager.shared.retrier = requestRetrier

        return true
    }
}
Clone this wiki locally