Search code examples
iosswiftmultithreadinggrand-central-dispatchmoya

Make all endpoints to wait one exact endpoint


I am using Moya to handle HTTP operations and normally I have an refreshToken(). I am checking token if expired or not when a request is about happen but the problem is there can be a scenarios that more than one requests. If they are chained with nested types it is not a problem however, it is not likely all the time.

To be more clear lets say I have request1() and request2() and assume that they execute separate operations and can be triggered anytime(for instance one is called in a viewDidLoad(), other one is called in another viewDidLoad()). when this happens and if the token is expired, my refresh request fails. (statusCode: 400) So, my question is, how can I make provider to wait refresh() operation get done?I mean by provider is other endpoints. I want them to wait refresh() endpoint if it is on.

I will be very appreciated if you suggest a way that will make this easier.


Solution

  • I just set an variable called isTokenRefreshing true when i start the refresh() operation and checked it before making a request. If it was true I stored all the requests in an array and when the refresh() is finished I executed another function which basically makes all the stored requests in a for loop.

    If anyone wants to see the code I can share. Just let me know.

    EDIT

    This where I, NetworkManager, handle all my requests. It is in an Singleton class.

        private var awaitingRequests : [NetworkAPI] = []
    
        func makeRequest(_ request: NetworkAPI){
            if (Token.sharedInstance.isTokenRefreshing && request.requiresToken) {
                self.awaitingRequests.append(request)
                return
            }
            self.provider.request(){ result in ... }
        }
    
        func executeWaitedRequests(){
            for request in self.awaitingRequests {
                self.makeRequest(request)
            }
        }
    

    NetworkAPI is main enum that I hold my endpoint cases. See the Moya documents if you do not what I am talking about.

    And this is where I handle my Token operations.

    class Token {
    
        static let sharedInstance = Token()
    
        private init(){}
    
        var isTokenRefreshing: Bool = false
    
        func refresh(_ completion: @escaping ()->()){
    
            self.isTokenRefreshing = true
            print("refreshing token")
            let queue = DispatchQueue(label: "com.asd.ads.makeRequest", attributes: DispatchQueue.Attributes.concurrent)
            queue.sync(flags: .barrier, execute: {
                NetworkManager.shared.makeRequest(.refresh(), completionHandler: { (success, error) in
                    self.isTokenRefreshing = false
                    if success{
                        completion()
                        NetworkManager.shared.executeWaitedRequests()
                    }
    
                    print("refrehing ended!")
                })
            })
    
        }
    }