Централизованный токен для одновременных асинхронных сетевых задач - PullRequest
0 голосов
/ 05 февраля 2019

У меня есть приложение, которое извлекает данные API для нескольких задач внутри себя.

Основной запрос данных API заключается в получении назначений для данного поставщика или местоположения в нашей системе здравоохранения.Чтобы иметь правильные ключи, соответствующие идентификатору провайдера или идентификатору местоположения фактическому имени, я также извлекаю эти данные из API, чтобы убедиться, что они актуальны.

У меня это работает, поэтому сетевой вызовпроверяет, активен ли текущий токен API, а если нет, автоматически обновляет его и повторно вызывает сетевые данные.Как только токен подтверждается либо активным в настоящее время, либо соответствующим образом обновляется, он возвращает значение true.

Однако 3 различных сетевых извлечения вызывают данные асинхронно, и одно обновит токен API, в то время как другое пытаетсявыполните то же самое, и затем токен API будет обновляться повторно в той же последовательности без необходимости.

Чтобы исправить это, я пытаюсь переключиться на функцию локализованного токена, которая проверяет, активен ли текущий токен, и, если нет, обновляется.Это.Он также проверяет, выполняется ли уже обновление токена, и, если это так, не позволяет другим функциям также обновить его.Он также повторно вызывает исходную функцию, чтобы дождаться появления обновленного токена.

Проблема, с которой я сталкиваюсь, заключается в том, что я, кажется, создал цикл, который завершает работу моего приложения до появления нового токена,По сути, я думаю, что мне нужно решить эту проблему - дождаться ответа перед повторным вызовом цикла, но я не уверен, как лучше это сделать.

Вот моя проверка / обновление токенакод:

В моей модели также есть переменная tokenUpdateInProgress = 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
    }
...