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.cpp194
1 files changed, 174 insertions, 20 deletions
diff --git a/platform/default/default_file_source.cpp b/platform/default/default_file_source.cpp
index a1f8bc2c48..bdf02ee69a 100644
--- a/platform/default/default_file_source.cpp
+++ b/platform/default/default_file_source.cpp
@@ -1,10 +1,15 @@
#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/storage/offline_download.hpp>
#include <mbgl/platform/platform.hpp>
#include <mbgl/util/url.hpp>
+#include <mbgl/util/thread.hpp>
+#include <mbgl/util/work_request.hpp>
+
+#include <cassert>
namespace {
@@ -20,45 +25,194 @@ namespace mbgl {
class DefaultFileSource::Impl {
public:
- Impl(const std::string& cachePath, const std::string& assetRoot)
- : assetFileSource(assetRoot),
- cache(SQLiteCache::getShared(cachePath)),
- onlineFileSource(cache.get()) {
+ 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, uint64_t maximumCacheSize)
+ : offlineDatabase(cachePath, maximumCacheSize) {
+ }
+
+ void setAccessToken(const std::string& accessToken) {
+ onlineFileSource.setAccessToken(accessToken);
+ }
+
+ std::string getAccessToken() const {
+ return onlineFileSource.getAccessToken();
+ }
+
+ void listRegions(std::function<void (std::exception_ptr, optional<std::vector<OfflineRegion>>)> callback) {
+ try {
+ callback({}, offlineDatabase.listRegions());
+ } catch (...) {
+ callback(std::current_exception(), {});
+ }
+ }
+
+ void createRegion(const OfflineRegionDefinition& definition,
+ const OfflineRegionMetadata& metadata,
+ std::function<void (std::exception_ptr, optional<OfflineRegion>)> callback) {
+ try {
+ callback({}, offlineDatabase.createRegion(definition, metadata));
+ } catch (...) {
+ callback(std::current_exception(), {});
+ }
+ }
+
+ void getRegionStatus(int64_t regionID, std::function<void (std::exception_ptr, optional<OfflineRegionStatus>)> callback) {
+ try {
+ callback({}, getDownload(regionID).getStatus());
+ } catch (...) {
+ callback(std::current_exception(), {});
+ }
+ }
+
+ void deleteRegion(OfflineRegion&& region, std::function<void (std::exception_ptr)> callback) {
+ try {
+ offlineDatabase.deleteRegion(std::move(region));
+ callback({});
+ } catch (...) {
+ callback(std::current_exception());
+ }
+ }
+
+ void setRegionObserver(int64_t regionID, std::unique_ptr<OfflineRegionObserver> observer) {
+ getDownload(regionID).setObserver(std::move(observer));
+ }
+
+ void setRegionDownloadState(int64_t regionID, OfflineRegionDownloadState state) {
+ getDownload(regionID).setState(state);
+ }
+
+ void request(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;
}
- AssetFileSource assetFileSource;
- std::shared_ptr<SQLiteCache> cache;
+private:
+ OfflineDownload& getDownload(int64_t regionID) {
+ auto it = downloads.find(regionID);
+ if (it != downloads.end()) {
+ return *it->second;
+ }
+ return *downloads.emplace(regionID,
+ std::make_unique<OfflineDownload>(regionID, offlineDatabase.getRegionDefinition(regionID), offlineDatabase, onlineFileSource)).first->second;
+ }
+
+ OfflineDatabase offlineDatabase;
OnlineFileSource onlineFileSource;
+ std::unordered_map<FileRequest*, std::unique_ptr<Task>> tasks;
+ std::unordered_map<int64_t, std::unique_ptr<OfflineDownload>> downloads;
+ bool offline = false;
};
-DefaultFileSource::DefaultFileSource(const std::string& cachePath, const std::string& assetRoot)
- : impl(std::make_unique<DefaultFileSource::Impl>(cachePath, assetRoot)) {
+DefaultFileSource::DefaultFileSource(const std::string& cachePath,
+ const std::string& assetRoot,
+ uint64_t maximumCacheSize)
+ : thread(std::make_unique<util::Thread<Impl>>(util::ThreadContext{"DefaultFileSource", util::ThreadType::Unknown, util::ThreadPriority::Low},
+ cachePath, maximumCacheSize)),
+ 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);
-}
+std::unique_ptr<FileRequest> DefaultFileSource::request(const Resource& resource, Callback callback) {
+ class DefaultFileRequest : public FileRequest {
+ public:
+ DefaultFileRequest(Resource resource_, FileSource::Callback callback_, util::Thread<DefaultFileSource::Impl>& thread_)
+ : thread(thread_),
+ workRequest(thread.invokeWithCallback(&DefaultFileSource::Impl::request, callback_, this, resource_)) {
+ }
-void DefaultFileSource::setMaximumCacheEntrySize(uint64_t size) {
- impl->cache->setMaximumCacheEntrySize(size);
-}
+ ~DefaultFileRequest() {
+ thread.invoke(&DefaultFileSource::Impl::cancel, this);
+ }
+
+ util::Thread<DefaultFileSource::Impl>& thread;
+ std::unique_ptr<WorkRequest> workRequest;
+ };
-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 impl->onlineFileSource.request(resource, callback);
+ return std::make_unique<DefaultFileRequest>(resource, callback, *thread);
}
}
+void DefaultFileSource::listOfflineRegions(std::function<void (std::exception_ptr, optional<std::vector<OfflineRegion>>)> callback) {
+ thread->invoke(&Impl::listRegions, callback);
+}
+
+void DefaultFileSource::createOfflineRegion(const OfflineRegionDefinition& definition,
+ const OfflineRegionMetadata& metadata,
+ std::function<void (std::exception_ptr, optional<OfflineRegion>)> callback) {
+ thread->invoke(&Impl::createRegion, definition, metadata, callback);
+}
+
+void DefaultFileSource::deleteOfflineRegion(OfflineRegion&& region, std::function<void (std::exception_ptr)> callback) {
+ thread->invoke(&Impl::deleteRegion, std::move(region), callback);
+}
+
+void DefaultFileSource::setOfflineRegionObserver(OfflineRegion& region, std::unique_ptr<OfflineRegionObserver> observer) {
+ thread->invoke(&Impl::setRegionObserver, region.getID(), std::move(observer));
+}
+
+void DefaultFileSource::setOfflineRegionDownloadState(OfflineRegion& region, OfflineRegionDownloadState state) {
+ thread->invoke(&Impl::setRegionDownloadState, region.getID(), state);
+}
+
+void DefaultFileSource::getOfflineRegionStatus(OfflineRegion& region, std::function<void (std::exception_ptr, optional<OfflineRegionStatus>)> callback) const {
+ thread->invoke(&Impl::getRegionStatus, region.getID(), callback);
+}
+
+// For testing only:
+
+void DefaultFileSource::put(const Resource& resource, const Response& response) {
+ thread->invokeSync(&Impl::put, resource, response);
+}
+
+void DefaultFileSource::goOffline() {
+ thread->invokeSync(&Impl::goOffline);
+}
+
} // namespace mbgl