并发异步网络任务的集中令牌

时间:2019-02-05 19:32:11

标签: ios swift rest networking token

我有一个应用程序,它在其内部为多个任务提取API数据。

主要API数据请求是为我们的卫生系统中的给定提供者或位置提取约会。 为了使密钥正确,以使提供商ID或位置ID与实际名称匹配,我还从API中提取了该数据,以确保它们是最新的。

我可以使用它,因此网络调用会检查当前的API令牌是否处于活动状态,如果没有激活,则会自动刷新它并重新调用网络数据。一旦确认令牌为当前处于活动状态或正确刷新后,它将返回true。

但是,这3个不同的网络请求异步调用数据,一个将更新API令牌,而另一个尝试这样做,然后API令牌将在不必要的顺序内重复更新。

要解决此问题,我尝试切换到本地化令牌功能,该功能会检查当前令牌是否处于活动状态,如果没有,则将其刷新。它还检查是否已在进行令牌更新,如果这样做,则其他功能也将停止更新。它还会重新调用原始函数,以等待更新的令牌出现。

我遇到的问题是我似乎创建了一个循环,该循环使我的应用程序崩溃,然后才能显示新令牌。本质上,我猜想我需要解决的问题是在重新调用循环之前等待响应,但是我不确定执行此操作的最佳方法。

这是我的令牌检查/刷新代码:

我的模型还具有一个var tokenUpdateUpdateInProgress = false,以便新函数可以在新的更新开始时发出警报。

func isTokenActiveAndRefreshIfNot(_ completion: @escaping (Bool) -> ()) {
    print("running tokenActive function")
    var returnBool = false
    print("tokenUpdateInProgressz: \(tokenUpdateInProgress)")

    if tokenUpdateInProgress == false {
        print("no other update in progress, start the check here")
        tokenUpdateInProgress = true
        let resourceListURL = "https://api.carecloud.com/v2/oauth2/token_info"
        var request = URLRequest(url:URL(string:resourceListURL)!)
        request.addValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
        request.httpMethod = "GET"
        var json = JSON()

        URLSession.shared.dataTask(with: request){ data, response, error in
            print("data pull called in isTokenActive")
            if let httpResponse = response as? HTTPURLResponse {
                print("status code: \(httpResponse.statusCode)")
                httpStatusCode = httpResponse.statusCode
            }
            if httpStatusCode == 200 {
                print("token is current, proceed")
                tokenUpdateInProgress = false
                returnBool = true
                json = try! JSON(data: data!)
                for (_, _) in json {
                    if let expiration = json["expires_in"].string {
                        if let double = Double(expiration) {
                            let dateTime = Date()
                            let newDateTime = dateTime.addingTimeInterval(double)
                            tokenExpiresDateTime = newDateTime
                        }
                    }
                }
            }
            if httpStatusCode == 403 || httpStatusCode == 401 { 
                let downloadGroup = DispatchGroup()
                print("token is expired, need to refresh it")
                tokenUpdate = false
                downloadGroup.enter()
                refreshToken({ (tokenRefreshed) in. //this function refreshes my token successfully
                    if tokenRefreshed == true {
                        //can do something here if token refresh works correctly
                        returnBool = true
                        tokenUpdateInProgress = false
                        downloadGroup.leave()
                        downloadGroup.notify(queue: DispatchQueue.main) {
                            //                        completion(returnItem)
                        }
                    }
                })
            }
            completion(returnBool)
            }.resume()
    } else if tokenUpdateInProgress == true {
        print("token update in progress, re-run check and wait for result")
        isTokenActiveAndRefreshIfNot { (result) in  //this creates a loop if network not working or token refresh not working for any reason.  This loops too fast and leads to a crash.
            returnBool = result
        }
        completion(returnBool)
    }

}

所有提取此数据的三个函数是: 1:

func monthSchedule(resourceID: String, locationID: String, page: Int, _ completion: @escaping ([appt]) -> ()){
    isTokenActiveAndRefreshIfNot { (tokenUpdated) in
        print("token update within monthschedule: \(tokenUpdated)")
    }
... runs network pull/API interpretation from token once confirmed ok
}

2:

func pullLocationsList(_ completion: @escaping ([Int: String]) -> ()){
    isTokenActiveAndRefreshIfNot { (tokenReady) in
        print("token ready for pull location list: \(tokenReady)")
    }
    ... runs network pull/API interpretation from token once confirmed ok
    }

3:

func pullResourceList(_ completion: @escaping ([Int: String]) -> ()){
    isTokenActiveAndRefreshIfNot { (tokenReady) in
        print("token ready for pull resource list: \(tokenReady)")
    }
        ... runs network pull/API interpretation from token once confirmed ok
    }

0 个答案:

没有答案