void DefaultFileSource::Impl::update(DefaultFileRequest& request) { if (request.getResponse()) { // We've at least obtained a cache value, potentially we also got a final response. // The observers have been notified already; send what we have to the new one as well. // Before returning the existing response, make sure that it is still fresh, or update the // `stale` flag. request.checkResponseFreshness(); if (request.getResponse()->stale && !request.realRequest) { // We've returned a stale response; now make sure the requester also gets a fresh // response eventually. It's possible that there's already a request in progress. // Note that this will also trigger updates to all other existing listeners. // Since we already have data, we're going to verify startRealRequest(request); } else { // The response is still fresh (or there's already a request for refreshing the resource // in progress), so there's nothing we need to do. } } else if (!request.cacheRequest && !request.realRequest) { // There is no request in progress, and we don't have a response yet. This means we'll have // to start the request ourselves. if (cache) { startCacheRequest(request); } else { startRealRequest(request); } } else { // There is a request in progress. We just have to wait. } }
void DefaultFileSource::Impl::networkIsReachableAgain() { for (auto& req : pending) { auto& request = req.second; auto& response = request.getResponse(); if (!request.realRequest && response && response->error && response->error->reason == Response::Error::Reason::Connection) { // We need all requests to fail at least once before we are going to start retrying // them, and we only immediately restart request that failed due to connection issues. startRealRequest(request); } } }
void OnlineFileSource::Impl::reschedule(OnlineFileRequestImpl& request) { if (request.realRequest) { // There's already a request in progress; don't start another one. return; } const Seconds timeout = request.getRetryTimeout(); if (timeout == Seconds::zero()) { update(request); } else if (timeout > Seconds::zero()) { request.realRequestTimer.start(timeout, Duration::zero(), [this, &request] { assert(!request.realRequest); startRealRequest(request); }); } }
void OnlineFileSource::Impl::startCacheRequest(OnlineFileRequestImpl& request) { // Check the cache for existing data so that we can potentially // revalidate the information without having to redownload everything. request.cacheRequest = cache->get(request.resource, [this, &request](std::shared_ptr<Response> response) { request.cacheRequest = nullptr; if (response) { response->stale = response->isExpired(); request.setResponse(response); } if (!response || response->stale) { // No response or stale cache. Run the real request. startRealRequest(request); } reschedule(request); }); }
void DefaultFileSource::Impl::reschedule(DefaultFileRequest& request) { if (request.realRequest) { // There's already a request in progress; don't start another one. return; } const auto timeout = request.getRetryTimeout(); if (timeout == 0) { update(request); } else if (timeout > 0) { if (!request.timerRequest) { request.timerRequest = std::make_unique<uv::timer>(util::RunLoop::getLoop()); } // timeout is in seconds, but the timer takes milliseconds. request.timerRequest->start(1000 * timeout, 0, [this, &request] { assert(!request.realRequest); startRealRequest(request); }); } }
void DefaultFileSource::Impl::startCacheRequest(DefaultFileRequest& request) { // Check the cache for existing data so that we can potentially // revalidate the information without having to redownload everything. request.cacheRequest = cache->get(request.resource, [this, &request](std::shared_ptr<Response> response) { request.cacheRequest = nullptr; if (response) { response->stale = response->isExpired(); request.setResponse(response); } if (!response || response->stale) { // No response or stale cache. Run the real request. startRealRequest(request); } // Notify in all cases; requestors can decide whether they want to use stale responses. request.notify(); reschedule(request); }); }