Как украсить запрос Siesta асинхронной задачей - PullRequest
0 голосов
/ 25 июня 2018

Как правильно изменить Request, выполняющее асинхронную задачу перед выполнением запроса?

Таким образом, любой запрос Rn должен стать прозрачно Tn, а затем Rn.

Немного предыстории здесь : Задача - это сторонний SDK, который отправляет токен, который мне нужно использовать в качестве заголовка для исходного запроса.

Моя идея - украсить Rn, но при этом мне нужно преобразовать мою задачу Tn в сиесту Request, которую я могу затем соединить.

Так что я завернул асинхронную задачу и приковал ее к исходному запросу.Таким образом, любой Rn превратится в Tn.chained { .passTo(Rn) } Таким образом, это новое поведение полностью прозрачно для всего приложения.

Проблема

При выполнении этого моего кода происходит сбой во внутреннем предварительном условии Siesta: precondition(completedValue == nil, "notifyOfCompletion() already called")

В моем пользовательском запросе AsyncTaskRequest я собираю обратные вызовыдля успеха, неудачи, прогресса и т. д., чтобы вызвать их в главной очереди, когда SDK доставляет токен.

Я заметил, что удаление всех сохраненных обратных вызовов после их выполнения, сбой исчезает, но, честно говоря, яне нашел причину почему.

Я надеюсь, что достаточно информации для некоторых подсказок или предложений.Заранее спасибо.

1 Ответ

0 голосов
/ 25 июня 2018

Да, реализация интерфейса Siesta Request - это не пикник.У других была точно такая же проблема - и, к счастью, версия Siesta 1.4 включает в себя решение .

Документация для новой функции все еще тонкая.Чтобы использовать новый API, вы внедрите новый протокол RequestDelegate и передадите свою реализацию в Resource.prepareRequest(using:).Это вернет запрос, который вы можете использовать в стандартной цепочке запросов Siesta.Результат будет выглядеть примерно так (ПРЕДУПРЕЖДЕНИЕ - непроверенный код):

struct MyTokenHandlerThingy: RequestDelegate {
  // 3rd party SDK glue goes here
}

...

service.configure(…) {
  if let authToken = self.authToken {
    $0.headers["X-Auth-Token"] = authToken  // authToken is an instance var or something
  }

  $0.decorateRequests {
    self.refreshTokenOnAuthFailure(request: $1)
  }
}

func refreshTokenOnAuthFailure(request: Request) -> Request {
  return request.chained {
    guard case .failure(let error) = $0.response,  // Did request fail…
      error.httpStatusCode == 401 else {           // …because of expired token?
        return .useThisResponse                    // If not, use the response we got.
    }

    return .passTo(
      self.refreshAuthToken().chained {            // If so, first request a new token, then:
        if case .failure = $0.response {           // If token request failed…
          return .useThisResponse                  // …report that error.
        } else {
          return .passTo(request.repeated())       // We have a new token! Repeat the original request.
        }
      }
    )
  }
}

func refreshAuthToken() -> Request {
  return Request.prepareRequest(using: MyTokenHandlerThingy())
    .onSuccess {
      self.authToken = $0.jsonDict["token"] as? String  // Store the new token, then…
      self.invalidateConfiguration()                    // …make future requests use it
    }
  }
}

Чтобы понять, как реализовать RequestDelegate, лучше всего сейчас взглянуть на новые документы API непосредственно вкод .

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

...