#include #include #include #include #include #include #include #include #include namespace { const std::string assetProtocol = "asset://"; bool isAssetURL(const std::string& url) { return std::equal(assetProtocol.begin(), assetProtocol.end(), url.begin()); } } // namespace namespace mbgl { class DefaultFileSource::Impl { public: 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 onlineRequest; }; Impl(const std::string& cachePath) : offlineDatabase(cachePath) { } 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(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> tasks; bool offline = false; }; class DefaultFileRequest : public FileRequest { public: DefaultFileRequest(Resource resource, FileSource::Callback callback, util::Thread& thread_) : thread(thread_), workRequest(thread.invokeWithCallback(&DefaultFileSource::Impl::add, callback, this, resource)) { } ~DefaultFileRequest() { thread.invoke(&DefaultFileSource::Impl::cancel, this); } util::Thread& thread; std::unique_ptr workRequest; }; DefaultFileSource::DefaultFileSource(const std::string& cachePath, const std::string& assetRoot) : thread(std::make_unique>(util::ThreadContext{"DefaultFileSource", util::ThreadType::Unknown, util::ThreadPriority::Low}, cachePath)), assetFileSource(std::make_unique(assetRoot)) { } DefaultFileSource::~DefaultFileSource() = default; void DefaultFileSource::setAccessToken(const std::string& accessToken) { thread->invokeSync(&Impl::setAccessToken, accessToken); } std::string DefaultFileSource::getAccessToken() const { return thread->invokeSync(&Impl::getAccessToken); } void DefaultFileSource::setMaximumCacheSize(uint64_t) { // TODO } void DefaultFileSource::setMaximumCacheEntrySize(uint64_t) { // TODO } std::unique_ptr DefaultFileSource::request(const Resource& resource, Callback callback) { if (isAssetURL(resource.url)) { return assetFileSource->request(resource, callback); } else { return std::make_unique(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