summaryrefslogtreecommitdiff
path: root/platform/default/default_file_source.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'platform/default/default_file_source.cpp')
-rw-r--r--platform/default/default_file_source.cpp89
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);
}