diff options
Diffstat (limited to 'platform/default/default_file_source.cpp')
-rw-r--r-- | platform/default/default_file_source.cpp | 89 |
1 files changed, 56 insertions, 33 deletions
diff --git a/platform/default/default_file_source.cpp b/platform/default/default_file_source.cpp index bf8d7b6348..608b782ab9 100644 --- a/platform/default/default_file_source.cpp +++ b/platform/default/default_file_source.cpp @@ -28,10 +28,15 @@ namespace mbgl { class DefaultFileSource::Impl { public: - Impl(ActorRef<Impl>, std::shared_ptr<FileSource> assetFileSource_, const std::string& cachePath, uint64_t maximumCacheSize) + Impl(ActorRef<Impl> self, std::shared_ptr<FileSource> assetFileSource_, const std::string& cachePath, uint64_t maximumCacheSize) : assetFileSource(assetFileSource_) - , localFileSource(std::make_unique<LocalFileSource>()) - , offlineDatabase(cachePath, maximumCacheSize) { + , localFileSource(std::make_unique<LocalFileSource>()) { + // Initialize the Database asynchronously so as to not block Actor creation. + self.invoke(&Impl::initializeOfflineDatabase, cachePath, maximumCacheSize); + } + + void initializeOfflineDatabase(std::string cachePath, uint64_t maximumCacheSize) { + offlineDatabase = std::make_unique<OfflineDatabase>(cachePath, maximumCacheSize); } void setAPIBaseURL(const std::string& url) { @@ -56,7 +61,7 @@ public: void listRegions(std::function<void (std::exception_ptr, optional<std::vector<OfflineRegion>>)> callback) { try { - callback({}, offlineDatabase.listRegions()); + callback({}, offlineDatabase->listRegions()); } catch (...) { callback(std::current_exception(), {}); } @@ -66,7 +71,7 @@ public: const OfflineRegionMetadata& metadata, std::function<void (std::exception_ptr, optional<OfflineRegion>)> callback) { try { - callback({}, offlineDatabase.createRegion(definition, metadata)); + callback({}, offlineDatabase->createRegion(definition, metadata)); } catch (...) { callback(std::current_exception(), {}); } @@ -76,7 +81,7 @@ public: const OfflineRegionMetadata& metadata, std::function<void (std::exception_ptr, optional<OfflineRegionMetadata>)> callback) { try { - callback({}, offlineDatabase.updateMetadata(regionID, metadata)); + callback({}, offlineDatabase->updateMetadata(regionID, metadata)); } catch (...) { callback(std::current_exception(), {}); } @@ -93,7 +98,7 @@ public: void deleteRegion(OfflineRegion&& region, std::function<void (std::exception_ptr)> callback) { try { downloads.erase(region.getID()); - offlineDatabase.deleteRegion(std::move(region)); + offlineDatabase->deleteRegion(std::move(region)); callback({}); } catch (...) { callback(std::current_exception()); @@ -121,33 +126,43 @@ public: tasks[req] = localFileSource->request(resource, callback); } else { // Try the offline database - Resource revalidation = resource; - - const bool hasPrior = resource.priorEtag || resource.priorModified || resource.priorExpires; - if (!hasPrior || resource.necessity == Resource::Optional) { - auto offlineResponse = offlineDatabase.get(resource); - - if (resource.necessity == Resource::Optional && !offlineResponse) { - // Ensure there's always a response that we can send, so the caller knows that - // there's no optional data available in the cache. - offlineResponse.emplace(); - offlineResponse->noContent = true; - offlineResponse->error = std::make_unique<Response::Error>( - Response::Error::Reason::NotFound, "Not found in offline database"); - } - - if (offlineResponse) { - revalidation.priorModified = offlineResponse->modified; - revalidation.priorExpires = offlineResponse->expires; - revalidation.priorEtag = offlineResponse->etag; + if (resource.hasLoadingMethod(Resource::LoadingMethod::Cache)) { + auto offlineResponse = offlineDatabase->get(resource); + + if (resource.loadingMethod == Resource::LoadingMethod::CacheOnly) { + if (!offlineResponse) { + // Ensure there's always a response that we can send, so the caller knows that + // there's no optional data available in the cache, when it's the only place + // we're supposed to load from. + offlineResponse.emplace(); + offlineResponse->noContent = true; + offlineResponse->error = std::make_unique<Response::Error>( + Response::Error::Reason::NotFound, "Not found in offline database"); + } else if (!offlineResponse->isUsable()) { + // Don't return resources the server requested not to show when they're stale. + // Even if we can't directly use the response, we may still use it to send a + // conditional HTTP request, which is why we're saving it above. + offlineResponse->error = std::make_unique<Response::Error>( + Response::Error::Reason::NotFound, "Cached resource is unusable"); + } callback(*offlineResponse); + } else if (offlineResponse) { + // Copy over the fields so that we can use them when making a refresh request. + resource.priorModified = offlineResponse->modified; + resource.priorExpires = offlineResponse->expires; + resource.priorEtag = offlineResponse->etag; + resource.priorData = offlineResponse->data; + + if (offlineResponse->isUsable()) { + callback(*offlineResponse); + } } } // Get from the online file source - if (resource.necessity == Resource::Required) { - tasks[req] = onlineFileSource.request(revalidation, [=] (Response onlineResponse) mutable { - this->offlineDatabase.put(revalidation, onlineResponse); + if (resource.hasLoadingMethod(Resource::LoadingMethod::Network)) { + tasks[req] = onlineFileSource.request(resource, [=] (Response onlineResponse) mutable { + this->offlineDatabase->put(resource, onlineResponse); callback(onlineResponse); }); } @@ -159,11 +174,15 @@ public: } void setOfflineMapboxTileCountLimit(uint64_t limit) { - offlineDatabase.setOfflineMapboxTileCountLimit(limit); + offlineDatabase->setOfflineMapboxTileCountLimit(limit); + } + + void setOnlineStatus(const bool status) { + onlineFileSource.setOnlineStatus(status); } void put(const Resource& resource, const Response& response) { - offlineDatabase.put(resource, response); + offlineDatabase->put(resource, response); } private: @@ -173,13 +192,13 @@ private: return *it->second; } return *downloads.emplace(regionID, - std::make_unique<OfflineDownload>(regionID, offlineDatabase.getRegionDefinition(regionID), offlineDatabase, onlineFileSource)).first->second; + std::make_unique<OfflineDownload>(regionID, offlineDatabase->getRegionDefinition(regionID), *offlineDatabase, onlineFileSource)).first->second; } // shared so that destruction is done on the creating thread const std::shared_ptr<FileSource> assetFileSource; const std::unique_ptr<FileSource> localFileSource; - OfflineDatabase offlineDatabase; + std::unique_ptr<OfflineDatabase> offlineDatabase; OnlineFileSource onlineFileSource; std::unordered_map<AsyncRequest*, std::unique_ptr<AsyncRequest>> tasks; std::unordered_map<int64_t, std::unique_ptr<OfflineDownload>> downloads; @@ -288,6 +307,10 @@ void DefaultFileSource::resume() { // For testing only: +void DefaultFileSource::setOnlineStatus(const bool status) { + impl->actor().invoke(&Impl::setOnlineStatus, status); +} + void DefaultFileSource::put(const Resource& resource, const Response& response) { impl->actor().invoke(&Impl::put, resource, response); } |