[core] Reimplement existing caching within an offline-capable database schema
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
#include <mbgl/storage/asset_file_source.hpp>
|
||||
#include <mbgl/storage/online_file_source.hpp>
|
||||
#include <mbgl/storage/sqlite_cache.hpp>
|
||||
#include <mbgl/storage/offline_database.hpp>
|
||||
|
||||
#include <mbgl/platform/platform.hpp>
|
||||
#include <mbgl/util/url.hpp>
|
||||
#include <mbgl/util/thread.hpp>
|
||||
#include <mbgl/util/work_request.hpp>
|
||||
|
||||
#include <cassert>
|
||||
@@ -23,76 +24,117 @@ namespace mbgl {
|
||||
|
||||
class DefaultFileSource::Impl {
|
||||
public:
|
||||
Impl(const std::string& cachePath, const std::string& assetRoot)
|
||||
: assetFileSource(assetRoot),
|
||||
cache(SQLiteCache::getShared(cachePath)) {
|
||||
class Task {
|
||||
public:
|
||||
Task(Resource resource, FileSource::Callback callback, DefaultFileSource::Impl* impl) {
|
||||
auto offlineResponse = impl->offlineDatabase.get(resource);
|
||||
|
||||
Resource revalidation = resource;
|
||||
|
||||
if (offlineResponse) {
|
||||
revalidation.priorModified = offlineResponse->modified;
|
||||
revalidation.priorExpires = offlineResponse->expires;
|
||||
revalidation.priorEtag = offlineResponse->etag;
|
||||
callback(*offlineResponse);
|
||||
}
|
||||
|
||||
if (!impl->offline) {
|
||||
onlineRequest = impl->onlineFileSource.request(revalidation, [=] (Response onlineResponse) {
|
||||
impl->offlineDatabase.put(revalidation, onlineResponse);
|
||||
callback(onlineResponse);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<FileRequest> onlineRequest;
|
||||
};
|
||||
|
||||
Impl(const std::string& cachePath)
|
||||
: offlineDatabase(cachePath) {
|
||||
}
|
||||
|
||||
AssetFileSource assetFileSource;
|
||||
std::shared_ptr<SQLiteCache> cache;
|
||||
void setAccessToken(const std::string& accessToken) {
|
||||
onlineFileSource.setAccessToken(accessToken);
|
||||
}
|
||||
|
||||
std::string getAccessToken() const {
|
||||
return onlineFileSource.getAccessToken();
|
||||
}
|
||||
|
||||
void add(FileRequest* req, Resource resource, Callback callback) {
|
||||
tasks[req] = std::make_unique<Task>(resource, callback, this);
|
||||
}
|
||||
|
||||
void cancel(FileRequest* req) {
|
||||
tasks.erase(req);
|
||||
}
|
||||
|
||||
void put(const Resource& resource, const Response& response) {
|
||||
offlineDatabase.put(resource, response);
|
||||
}
|
||||
|
||||
void goOffline() {
|
||||
offline = true;
|
||||
}
|
||||
|
||||
OfflineDatabase offlineDatabase;
|
||||
OnlineFileSource onlineFileSource;
|
||||
std::unordered_map<FileRequest*, std::unique_ptr<Task>> tasks;
|
||||
bool offline = false;
|
||||
};
|
||||
|
||||
class DefaultFileRequest : public FileRequest {
|
||||
public:
|
||||
DefaultFileRequest(Resource resource, FileSource::Callback callback, util::Thread<DefaultFileSource::Impl>& thread_)
|
||||
: thread(thread_),
|
||||
workRequest(thread.invokeWithCallback(&DefaultFileSource::Impl::add, callback, this, resource)) {
|
||||
}
|
||||
|
||||
~DefaultFileRequest() {
|
||||
thread.invoke(&DefaultFileSource::Impl::cancel, this);
|
||||
}
|
||||
|
||||
util::Thread<DefaultFileSource::Impl>& thread;
|
||||
std::unique_ptr<WorkRequest> workRequest;
|
||||
};
|
||||
|
||||
DefaultFileSource::DefaultFileSource(const std::string& cachePath, const std::string& assetRoot)
|
||||
: impl(std::make_unique<DefaultFileSource::Impl>(cachePath, assetRoot)) {
|
||||
: thread(std::make_unique<util::Thread<DefaultFileSource::Impl>>(util::ThreadContext{"DefaultFileSource", util::ThreadType::Unknown, util::ThreadPriority::Low}, cachePath)),
|
||||
assetFileSource(std::make_unique<AssetFileSource>(assetRoot)) {
|
||||
}
|
||||
|
||||
DefaultFileSource::~DefaultFileSource() = default;
|
||||
|
||||
void DefaultFileSource::setAccessToken(const std::string& accessToken) {
|
||||
impl->onlineFileSource.setAccessToken(accessToken);
|
||||
thread->invokeSync(&Impl::setAccessToken, accessToken);
|
||||
}
|
||||
|
||||
std::string DefaultFileSource::getAccessToken() const {
|
||||
return impl->onlineFileSource.getAccessToken();
|
||||
return thread->invokeSync<std::string>(&Impl::getAccessToken);
|
||||
}
|
||||
|
||||
void DefaultFileSource::setMaximumCacheSize(uint64_t size) {
|
||||
impl->cache->setMaximumCacheSize(size);
|
||||
void DefaultFileSource::setMaximumCacheSize(uint64_t) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void DefaultFileSource::setMaximumCacheEntrySize(uint64_t size) {
|
||||
impl->cache->setMaximumCacheEntrySize(size);
|
||||
void DefaultFileSource::setMaximumCacheEntrySize(uint64_t) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
SQLiteCache& DefaultFileSource::getCache() {
|
||||
return *impl->cache;
|
||||
}
|
||||
|
||||
class DefaultFileRequest : public FileRequest {
|
||||
public:
|
||||
DefaultFileRequest(Resource resource, FileSource::Callback callback, DefaultFileSource::Impl* impl) {
|
||||
cacheRequest = impl->cache->get(resource, [=](std::shared_ptr<Response> cacheResponse) mutable {
|
||||
cacheRequest.reset();
|
||||
|
||||
if (cacheResponse) {
|
||||
resource.priorModified = cacheResponse->modified;
|
||||
resource.priorExpires = cacheResponse->expires;
|
||||
resource.priorEtag = cacheResponse->etag;
|
||||
}
|
||||
|
||||
onlineRequest = impl->onlineFileSource.request(resource, [=] (Response onlineResponse) {
|
||||
impl->cache->put(resource, onlineResponse);
|
||||
callback(onlineResponse);
|
||||
});
|
||||
|
||||
// Do this last because it may result in deleting this DefaultFileRequest.
|
||||
if (cacheResponse) {
|
||||
callback(*cacheResponse);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
std::unique_ptr<WorkRequest> cacheRequest;
|
||||
std::unique_ptr<FileRequest> onlineRequest;
|
||||
};
|
||||
|
||||
std::unique_ptr<FileRequest> DefaultFileSource::request(const Resource& resource, Callback callback) {
|
||||
if (isAssetURL(resource.url)) {
|
||||
return impl->assetFileSource.request(resource, callback);
|
||||
return assetFileSource->request(resource, callback);
|
||||
} else {
|
||||
return std::make_unique<DefaultFileRequest>(resource, callback, impl.get());
|
||||
return std::make_unique<DefaultFileRequest>(resource, callback, *thread);
|
||||
}
|
||||
}
|
||||
|
||||
void DefaultFileSource::put(const Resource& resource, const Response& response) {
|
||||
thread->invokeSync(&Impl::put, resource, response);
|
||||
}
|
||||
|
||||
void DefaultFileSource::goOffline() {
|
||||
thread->invokeSync(&Impl::goOffline);
|
||||
}
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
Reference in New Issue
Block a user