summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2015-01-29 18:30:46 +0100
committerKonstantin Käfer <mail@kkaefer.com>2015-02-04 10:49:09 +0100
commit29baacf3a5bb773d94d08d16b81c3cda45a44eb6 (patch)
tree1dc3ca456151138ee5e8b7cf88b3afcecc3df1db /platform
parent3d51e116a84ee168975bcee8377e9156f77e2731 (diff)
downloadqtlocation-mapboxgl-29baacf3a5bb773d94d08d16b81c3cda45a44eb6.tar.gz
refactor makefile
Diffstat (limited to 'platform')
-rw-r--r--platform/android/asset_request_libzip.cpp202
-rw-r--r--platform/darwin/asset_root.mm18
-rw-r--r--platform/darwin/http_request_nsurl.mm (renamed from platform/darwin/http_request_cocoa.mm)20
-rw-r--r--platform/default/asset_request_fs.cpp (renamed from platform/default/asset_request_libuv.cpp)2
-rw-r--r--platform/default/asset_request_zip.cpp295
-rw-r--r--platform/default/asset_root.cpp28
-rw-r--r--platform/default/default_file_source.cpp239
-rw-r--r--platform/default/http_request_curl.cpp12
-rw-r--r--platform/default/uv_zip.c202
-rw-r--r--platform/default/uv_zip.h45
10 files changed, 609 insertions, 454 deletions
diff --git a/platform/android/asset_request_libzip.cpp b/platform/android/asset_request_libzip.cpp
deleted file mode 100644
index 77f9ae7da1..0000000000
--- a/platform/android/asset_request_libzip.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-#include <mbgl/android/jni.hpp>
-#include <mbgl/storage/asset_request.hpp>
-#include <mbgl/storage/response.hpp>
-#include <mbgl/util/uv_detail.hpp>
-#include <mbgl/util/std.hpp>
-
-#include <cerrno>
-// NOTE a bug in the Android NDK breaks std::errno
-// See https://code.google.com/p/android/issues/detail?id=72349
-// After this is fixed change usage errno to std::errno
-#include <zip.h>
-
-namespace mbgl {
-
-struct AssetRequestBaton {
- AssetRequestBaton(AssetRequest *request_, const std::string &path, uv_loop_t *loop);
- ~AssetRequestBaton();
-
- const std::thread::id threadId;
- AssetRequest *request = nullptr;
- std::unique_ptr<uv::async> asyncRun;
- std::string path;
- bool canceled = false;
-
- void cancel();
- static void notifyError(AssetRequestBaton *ptr, const int code, const char *message);
- static void notifySuccess(AssetRequestBaton *ptr, const std::string body);
- static void cleanup(AssetRequestBaton *ptr);
- static void run(AssetRequestBaton *ptr);
-};
-
-AssetRequestBaton::AssetRequestBaton(AssetRequest *request_, const std::string &path_, uv_loop_t *loop)
-: threadId(std::this_thread::get_id()),
-request(request_),
-path(path_) {
-
- asyncRun = mbgl::util::make_unique<uv::async>(loop, [this]() {
- run(this);
- });
-
- asyncRun->send();
-}
-
-AssetRequestBaton::~AssetRequestBaton() {
-}
-
-void AssetRequestBaton::cancel() {
- canceled = true;
-}
-
-void AssetRequestBaton::notifyError(AssetRequestBaton *ptr, const int code, const char *message) {
- assert(std::this_thread::get_id() == ptr->threadId);
-
- if (ptr->request && !ptr->canceled) {
- ptr->request->response = std::unique_ptr<Response>(new Response);
- ptr->request->response->code = code;
- ptr->request->response->message = message;
- ptr->request->notify();
- }
-}
-
-void AssetRequestBaton::notifySuccess(AssetRequestBaton *ptr, const std::string body) {
- assert(std::this_thread::get_id() == ptr->threadId);
-
- if (ptr->request && !ptr->canceled) {
- ptr->request->response = std::unique_ptr<Response>(new Response);
- ptr->request->response->code = 200;
- ptr->request->response->data = body;
- ptr->request->notify();
- }
-}
-
-void AssetRequestBaton::cleanup(AssetRequestBaton *ptr) {
- assert(std::this_thread::get_id() == ptr->threadId);
-
- if (ptr->request) {
- ptr->request->ptr = nullptr;
- }
-
- ptr->asyncRun.reset();
-
- delete ptr;
- ptr = nullptr;
-}
-
-void AssetRequestBaton::run(AssetRequestBaton *ptr) {
- assert(std::this_thread::get_id() == ptr->threadId);
-
- if (ptr->canceled || !ptr->request) {
- // Either the AssetRequest object has been destructed, or the
- // request was canceled.
- cleanup(ptr);
- return;
- }
-
- int error = 0;
- struct zip *apk = zip_open(mbgl::android::apkPath.c_str(), 0, &error);
- if ((apk == nullptr) || ptr->canceled || !ptr->request) {
- // Opening the APK failed or was canceled. There isn't much left we can do.
- const int messageSize = zip_error_to_str(nullptr, 0, error, errno);
- const std::unique_ptr<char[]> message = mbgl::util::make_unique<char[]>(messageSize);
- zip_error_to_str(message.get(), 0, error, errno);
- notifyError(ptr, 500, message.get());
- cleanup(ptr);
- return;
- }
-
- std::string apkFilePath = "assets/" + ptr->path;
- struct zip_file *apkFile = zip_fopen(apk, apkFilePath.c_str(), ZIP_FL_NOCASE);
- if ((apkFile == nullptr) || ptr->canceled || !ptr->request) {
- // Opening the asset failed or was canceled. We already have an open file handle
- // though, which we'll have to close.
- zip_error_get(apk, &error, nullptr);
- notifyError(ptr, error == ZIP_ER_NOENT ? 404 : 500, zip_strerror(apk));
- zip_close(apk);
- apk = nullptr;
- cleanup(ptr);
- return;
- }
-
- struct zip_stat stat;
- if ((zip_stat(apk, apkFilePath.c_str(), ZIP_FL_NOCASE, &stat) != 0) || ptr->canceled || !ptr->request) {
- // Stating failed or was canceled. We already have an open file handle
- // though, which we'll have to close.
- notifyError(ptr, 500, zip_strerror(apk));
- zip_fclose(apkFile);
- apkFile = nullptr;
- zip_close(apk);
- apk = nullptr;
- cleanup(ptr);
- return;
- }
-
- const std::unique_ptr<char[]> data = mbgl::util::make_unique<char[]>(stat.size);
-
- if (static_cast<zip_uint64_t>(zip_fread(apkFile, reinterpret_cast<void *>(data.get()), stat.size)) != stat.size || ptr->canceled || !ptr->request) {
- // Reading failed or was canceled. We already have an open file handle
- // though, which we'll have to close.
- notifyError(ptr, 500, zip_file_strerror(apkFile));
- zip_fclose(apkFile);
- apkFile = nullptr;
- zip_close(apk);
- apk = nullptr;
- cleanup(ptr);
- return;
- }
-
- std::string body(data.get(), stat.size);
- notifySuccess(ptr, body);
-
- if (zip_fclose(apkFile) != 0) {
- // Closing the asset failed. But there isn't anything we can do.
- }
- apkFile = nullptr;
-
- if (zip_close(apk) != 0) {
- // Closing the APK failed. But there isn't anything we can do.
- }
- apk = nullptr;
-
- cleanup(ptr);
-}
-
-AssetRequest::AssetRequest(const std::string &path_, uv_loop_t *loop)
-: BaseRequest(path_) {
- if (!path.empty() && path[0] == '/') {
- // This is an absolute path. We don't allow this. Note that this is not a way to absolutely
- // prevent access to resources outside the application bundle; e.g. there could be symlinks
- // in the application bundle that link to outside. We don't care about these.
- response = util::make_unique<Response>();
- response->code = 403;
- response->message = "Path is outside the application bundle";
- notify();
- } else {
- // Note: The AssetRequestBaton object is deleted in AssetRequestBaton::cleanup().
- ptr = new AssetRequestBaton(this, path, loop);
- }
-}
-
-void AssetRequest::cancel() {
- assert(std::this_thread::get_id() == threadId);
-
- if (ptr) {
- ptr->cancel();
-
- // When deleting a AssetRequest object with a uv_fs_* call is in progress, we are making sure
- // that the callback doesn't accidentally reference this object again.
- ptr->request = nullptr;
- ptr = nullptr;
- }
-
- notify();
-}
-
-AssetRequest::~AssetRequest() {
- assert(std::this_thread::get_id() == threadId);
- cancel();
-
- // Note: The AssetRequestBaton object is deleted in AssetRequestBaton::cleanup().
-}
-
-}
diff --git a/platform/darwin/asset_root.mm b/platform/darwin/asset_root.mm
new file mode 100644
index 0000000000..375975a84b
--- /dev/null
+++ b/platform/darwin/asset_root.mm
@@ -0,0 +1,18 @@
+#import <Foundation/Foundation.h>
+
+#include <mbgl/platform/platform.hpp>
+
+namespace mbgl {
+namespace platform {
+
+// Returns the path to the root folder of the application.
+const std::string &assetRoot() {
+ static const std::string root = []() -> std::string {
+ NSString *path = [[[NSBundle mainBundle] resourceURL] path];
+ return {[path cStringUsingEncoding : NSUTF8StringEncoding],
+ [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding]};
+ }();
+ return root;
+}
+}
+}
diff --git a/platform/darwin/http_request_cocoa.mm b/platform/darwin/http_request_nsurl.mm
index efcc910488..83c010f8b8 100644
--- a/platform/darwin/http_request_cocoa.mm
+++ b/platform/darwin/http_request_nsurl.mm
@@ -43,7 +43,7 @@ enum class ResponseStatus : uint8_t {
// -------------------------------------------------------------------------------------------------
-class HTTPCocoaContext;
+class HTTPNSURLContext;
class HTTPRequestImpl {
public:
@@ -62,7 +62,7 @@ public:
static void restart(uv_timer_t *timer, int);
private:
- HTTPCocoaContext *context = nullptr;
+ HTTPNSURLContext *context = nullptr;
HTTPRequest *request = nullptr;
NSURLSessionDataTask *task = nullptr;
std::unique_ptr<Response> response;
@@ -78,19 +78,19 @@ private:
// -------------------------------------------------------------------------------------------------
-class HTTPCocoaContext : public HTTPContext<HTTPCocoaContext> {
+class HTTPNSURLContext : public HTTPContext<HTTPNSURLContext> {
public:
- HTTPCocoaContext(uv_loop_t *loop);
- ~HTTPCocoaContext();
+ HTTPNSURLContext(uv_loop_t *loop);
+ ~HTTPNSURLContext();
NSURLSession *session = nil;
NSString *userAgent = nil;
};
-template<> pthread_key_t HTTPContext<HTTPCocoaContext>::key{};
-template<> pthread_once_t HTTPContext<HTTPCocoaContext>::once = PTHREAD_ONCE_INIT;
+template<> pthread_key_t ThreadContext<HTTPNSURLContext>::key{};
+template<> pthread_once_t ThreadContext<HTTPNSURLContext>::once = PTHREAD_ONCE_INIT;
-HTTPCocoaContext::HTTPCocoaContext(uv_loop_t *loop_) : HTTPContext(loop_) {
+HTTPNSURLContext::HTTPNSURLContext(uv_loop_t *loop_) : HTTPContext(loop_) {
@autoreleasepool {
NSURLSessionConfiguration *sessionConfig =
[NSURLSessionConfiguration defaultSessionConfiguration];
@@ -107,7 +107,7 @@ HTTPCocoaContext::HTTPCocoaContext(uv_loop_t *loop_) : HTTPContext(loop_) {
}
}
-HTTPCocoaContext::~HTTPCocoaContext() {
+HTTPNSURLContext::~HTTPNSURLContext() {
[session release];
session = nullptr;
@@ -119,7 +119,7 @@ HTTPCocoaContext::~HTTPCocoaContext() {
HTTPRequestImpl::HTTPRequestImpl(HTTPRequest *request_, uv_loop_t *loop,
std::unique_ptr<Response> existingResponse_)
- : context(HTTPCocoaContext::Get(loop)),
+ : context(HTTPNSURLContext::Get(loop)),
request(request_),
existingResponse(std::move(existingResponse_)),
async(new uv_async_t) {
diff --git a/platform/default/asset_request_libuv.cpp b/platform/default/asset_request_fs.cpp
index 4a6fc88eb6..e3875a08e8 100644
--- a/platform/default/asset_request_libuv.cpp
+++ b/platform/default/asset_request_fs.cpp
@@ -56,7 +56,7 @@ AssetRequestImpl::AssetRequestImpl(AssetRequest *request_, uv_loop_t *loop) : re
path = url.substr(8);
} else {
// This is a relative path. Prefix with the application root.
- path = platform::applicationRoot() + "/" + url.substr(8);
+ path = platform::assetRoot() + "/" + url.substr(8);
}
uv_fs_open(loop, &req, path.c_str(), O_RDONLY, S_IRUSR, fileOpened);
diff --git a/platform/default/asset_request_zip.cpp b/platform/default/asset_request_zip.cpp
new file mode 100644
index 0000000000..9c1093c5ed
--- /dev/null
+++ b/platform/default/asset_request_zip.cpp
@@ -0,0 +1,295 @@
+#include <mbgl/storage/default/asset_request.hpp>
+#include <mbgl/storage/default/thread_context.hpp>
+#include <mbgl/android/jni.hpp>
+#include <mbgl/storage/response.hpp>
+#include <mbgl/util/std.hpp>
+#include <mbgl/platform/platform.hpp>
+
+#include "uv_zip.h"
+
+#include <boost/algorithm/string.hpp>
+
+#include <forward_list>
+
+namespace algo = boost::algorithm;
+
+namespace mbgl {
+
+class AssetZipContext : public ThreadContext<AssetZipContext> {
+public:
+ AssetZipContext(uv_loop_t *loop);
+ ~AssetZipContext();
+
+ uv_zip_t *getHandle();
+ void returnHandle(uv_zip_t *zip);
+
+private:
+ // A list of resuable uv_zip handles to avoid creating and destroying them all the time.
+ std::forward_list<uv_zip_t *> handles;
+};
+
+// -------------------------------------------------------------------------------------------------
+
+template<> pthread_key_t ThreadContext<AssetZipContext>::key{};
+template<> pthread_once_t ThreadContext<AssetZipContext>::once = PTHREAD_ONCE_INIT;
+
+AssetZipContext::AssetZipContext(uv_loop_t *loop_) : ThreadContext(loop_) {
+}
+
+uv_zip_t *AssetZipContext::getHandle() {
+ if (!handles.empty()) {
+ auto zip = handles.front();
+ handles.pop_front();
+ return zip;
+ } else {
+ return nullptr;
+ }
+}
+
+void AssetZipContext::returnHandle(uv_zip_t *zip) {
+ uv_zip_cleanup(zip);
+ handles.push_front(zip);
+}
+
+AssetZipContext::~AssetZipContext() {
+ // Close all zip handles
+ for (auto zip : handles) {
+ uv_zip_discard(loop, zip, [](uv_zip_t *zip_) {
+ uv_zip_cleanup(zip_);
+ delete zip_;
+ });
+ }
+ handles.clear();
+}
+
+// -------------------------------------------------------------------------------------------------
+
+class AssetRequestImpl {
+ MBGL_STORE_THREAD(tid)
+
+public:
+ AssetRequestImpl(AssetRequest *request, uv_loop_t *loop);
+ ~AssetRequestImpl();
+
+ void cancel();
+
+private:
+ AssetZipContext &context;
+ AssetRequest *request = nullptr;
+ const std::string path;
+ std::unique_ptr<Response> response;
+ uv_buf_t buffer;
+
+private:
+ void openZipArchive();
+ void archiveOpened(uv_zip_t *zip);
+ void fileStated(uv_zip_t *zip);
+ void fileOpened(uv_zip_t *zip);
+ void fileRead(uv_zip_t *zip);
+ void fileClosed(uv_zip_t *zip);
+ void cleanup(uv_zip_t *zip);
+
+ void notifyError(const char *message);
+};
+
+// -------------------------------------------------------------------------------------------------
+
+AssetRequestImpl::~AssetRequestImpl() {
+ MBGL_VERIFY_THREAD(tid);
+
+ if (request) {
+ request->ptr = nullptr;
+ }
+}
+
+AssetRequestImpl::AssetRequestImpl(AssetRequest *request_, uv_loop_t *loop)
+ : context(*AssetZipContext::Get(loop)),
+ request(request_),
+ path(request->resource.url.substr(8)) {
+ auto zip = context.getHandle();
+ if (zip) {
+ archiveOpened(zip);
+ } else {
+ openZipArchive();
+ }
+}
+
+void AssetRequestImpl::openZipArchive() {
+ uv_fs_t *req = new uv_fs_t();
+ req->data = this;
+
+ // We're using uv_fs_open first to obtain a file descriptor. Then, uv_zip_fdopen will operate
+ // on a read-only file.
+ uv_fs_open(context.loop, req, platform::assetRoot().c_str(), O_RDONLY, S_IRUSR, [](uv_fs_t *fsReq) {
+ if (fsReq->result < 0) {
+ auto impl = reinterpret_cast<AssetRequestImpl *>(fsReq->data);
+ impl->notifyError(uv::getFileRequestError(fsReq));
+ delete impl;
+ } else {
+ uv_zip_t *zip = new uv_zip_t();
+ uv_zip_init(zip);
+ zip->data = fsReq->data;
+ uv_zip_fdopen(fsReq->loop, zip, uv_file(fsReq->result), 0, [](uv_zip_t *openZip) {
+ auto impl = reinterpret_cast<AssetRequestImpl *>(openZip->data);
+ if (openZip->result < 0) {
+ impl->notifyError(openZip->message);
+ delete openZip;
+ delete impl;
+ } else {
+ impl->archiveOpened(openZip);
+ }
+ });
+ }
+
+ uv_fs_req_cleanup(fsReq);
+ delete fsReq;
+ fsReq = nullptr;
+ });
+}
+
+#define INVOKE_MEMBER(name) \
+ [](uv_zip_t *zip_) { \
+ assert(zip_->data); \
+ reinterpret_cast<AssetRequestImpl *>(zip_->data)->name(zip_); \
+ }
+
+void AssetRequestImpl::archiveOpened(uv_zip_t *zip) {
+ MBGL_VERIFY_THREAD(tid);
+
+ zip->data = this;
+ uv_zip_stat(context.loop, zip, path.c_str(), 0, INVOKE_MEMBER(fileStated));
+}
+
+void AssetRequestImpl::fileStated(uv_zip_t *zip) {
+ MBGL_VERIFY_THREAD(tid);
+
+ if (!request || zip->result < 0) {
+ // Stat failed, probably because the file doesn't exist.
+ if (zip->result < 0) {
+ notifyError(zip->message);
+ }
+ cleanup(zip);
+ } else if (!(zip->stat->valid & ZIP_STAT_SIZE)) {
+ // We couldn't obtain the size of the file.
+ notifyError("Could not determine file size in zip file");
+ cleanup(zip);
+ } else {
+ response = util::make_unique<Response>();
+
+ // Allocate the space for reading the data.
+ response->data.resize(zip->stat->size);
+ buffer = uv_buf_init(const_cast<char *>(response->data.data()), zip->stat->size);
+
+ // Get the modification time in case we have one.
+ if (zip->stat->valid & ZIP_STAT_MTIME) {
+ response->modified = zip->stat->mtime;
+ }
+
+ uv_zip_fopen(context.loop, zip, path.c_str(), 0, INVOKE_MEMBER(fileOpened));
+ }
+}
+
+void AssetRequestImpl::fileOpened(uv_zip_t *zip) {
+ MBGL_VERIFY_THREAD(tid);
+
+ if (zip->result < 0) {
+ // Opening failed.
+ notifyError(zip->message);
+ cleanup(zip);
+ } else if (!request) {
+ // The request was canceled. Close the file again.
+ uv_zip_fclose(context.loop, zip, zip->file, INVOKE_MEMBER(fileClosed));
+ } else {
+ uv_zip_fread(context.loop, zip, zip->file, &buffer, INVOKE_MEMBER(fileRead));
+ }
+}
+
+void AssetRequestImpl::fileRead(uv_zip_t *zip) {
+ MBGL_VERIFY_THREAD(tid);
+
+ if (zip->result < 0) {
+ // Reading failed. We still have an open file handle though.
+ notifyError(zip->message);
+ } else if (request) {
+ response->status = Response::Successful;
+ request->notify(std::move(response), FileCache::Hint::No);
+ delete request;
+ assert(request == nullptr);
+ }
+
+ uv_zip_fclose(context.loop, zip, zip->file, INVOKE_MEMBER(fileClosed));
+}
+
+void AssetRequestImpl::fileClosed(uv_zip_t *zip) {
+ MBGL_VERIFY_THREAD(tid);
+
+ if (zip->result < 0) {
+ // Closing the file failed. But there isn't anything we can do.
+ }
+
+ cleanup(zip);
+}
+
+void AssetRequestImpl::cleanup(uv_zip_t *zip) {
+ MBGL_VERIFY_THREAD(tid);
+
+ context.returnHandle(zip);
+ delete this;
+}
+
+void AssetRequestImpl::notifyError(const char *message) {
+ MBGL_VERIFY_THREAD(tid);
+
+ if (request) {
+ response = util::make_unique<Response>();
+ response->status = Response::Error;
+ response->message = message;
+ request->notify(std::move(response), FileCache::Hint::No);
+ delete request;
+ assert(request == nullptr);
+ } else {
+ // The request was already canceled and deleted.
+ }
+}
+
+void AssetRequestImpl::cancel() {
+ request = nullptr;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+AssetRequest::AssetRequest(DefaultFileSource *source_, const Resource &resource_)
+ : SharedRequestBase(source_, resource_) {
+ assert(algo::starts_with(resource.url, "asset://"));
+}
+
+AssetRequest::~AssetRequest() {
+ MBGL_VERIFY_THREAD(tid);
+
+ if (ptr) {
+ reinterpret_cast<AssetRequestImpl *>(ptr)->cancel();
+ }
+}
+
+void AssetRequest::start(uv_loop_t *loop, std::unique_ptr<Response> response) {
+ MBGL_VERIFY_THREAD(tid);
+
+ // We're ignoring the existing response if any.
+ (void(response));
+
+ assert(!ptr);
+ ptr = new AssetRequestImpl(this, loop);
+ // Note: the AssetRequestImpl deletes itself.
+}
+
+void AssetRequest::cancel() {
+ MBGL_VERIFY_THREAD(tid);
+
+ if (ptr) {
+ reinterpret_cast<AssetRequestImpl *>(ptr)->cancel();
+ }
+
+ delete this;
+}
+
+}
diff --git a/platform/default/asset_root.cpp b/platform/default/asset_root.cpp
new file mode 100644
index 0000000000..2b20018c40
--- /dev/null
+++ b/platform/default/asset_root.cpp
@@ -0,0 +1,28 @@
+#include <mbgl/platform/platform.hpp>
+
+#include <uv.h>
+#include <libgen.h>
+
+namespace mbgl {
+namespace platform {
+
+// Returns the path to the root folder of the application.
+const std::string &assetRoot() {
+ static const std::string root = []() -> std::string {
+ size_t max = 0;
+ std::string dir;
+ do {
+ // Gradually increase the length of the string in case the path was truncated.
+ max += 256;
+ dir.resize(max);
+ uv_exepath(const_cast<char *>(dir.data()), &max);
+ } while (max == dir.size());
+ dir.resize(max - 1);
+ dir = dirname(const_cast<char *>(dir.c_str()));
+ return dir;
+ }();
+ return root;
+}
+
+}
+}
diff --git a/platform/default/default_file_source.cpp b/platform/default/default_file_source.cpp
deleted file mode 100644
index 60633c789e..0000000000
--- a/platform/default/default_file_source.cpp
+++ /dev/null
@@ -1,239 +0,0 @@
-#include <mbgl/storage/default/default_file_source.hpp>
-#include <mbgl/storage/default/request.hpp>
-#include <mbgl/storage/default/asset_request.hpp>
-#include <mbgl/storage/default/http_request.hpp>
-
-#include <mbgl/storage/response.hpp>
-
-#include <mbgl/util/async_queue.hpp>
-#include <mbgl/util/util.hpp>
-
-#include <mbgl/util/variant.hpp>
-
-#include <boost/algorithm/string.hpp>
-
-#include <thread>
-#include <algorithm>
-#include <cassert>
-
-
-namespace algo = boost::algorithm;
-
-namespace mbgl {
-
-struct DefaultFileSource::ActionDispatcher {
- DefaultFileSource &fileSource;
- template <typename T> void operator()(T &t) { fileSource.process(t); }
-};
-
-struct DefaultFileSource::AddRequestAction {
- Request *const request;
-};
-
-struct DefaultFileSource::RemoveRequestAction {
- Request *const request;
-};
-
-struct DefaultFileSource::ResultAction {
- const Resource resource;
- std::unique_ptr<Response> response;
-};
-
-struct DefaultFileSource::StopAction {
-};
-
-
-DefaultFileSource::DefaultFileSource(FileCache *cache_)
- : loop(uv_loop_new()),
- cache(cache_),
- queue(new Queue(loop, [this](Action &action) {
- mapbox::util::apply_visitor(ActionDispatcher{*this}, action);
- })),
- thread([this]() {
-#ifdef __APPLE__
- pthread_setname_np("FileSource");
-#endif
- uv_run(loop, UV_RUN_DEFAULT);
- }) {
-}
-
-DefaultFileSource::DefaultFileSource(FileCache *cache_, uv_loop_t *loop_)
- : loop(loop_),
- cache(cache_),
- queue(new Queue(loop, [this](Action &action) {
- mapbox::util::apply_visitor(ActionDispatcher{*this}, action);
- })) {
- // Make sure that the queue doesn't block the loop from exiting.
- queue->unref();
-}
-
-DefaultFileSource::~DefaultFileSource() {
- MBGL_VERIFY_THREAD(tid);
-
- if (thread.joinable()) {
- if (queue) {
- queue->send(StopAction{ });
- }
- thread.join();
- uv_loop_delete(loop);
- } else {
- // Assume that the loop we received is running in the current thread.
- StopAction action {};
- process(action);
- }
-}
-
-SharedRequestBase *DefaultFileSource::find(const Resource &resource) {
- // We're using a set of pointers here instead of a map between url and SharedRequestBase because
- // we need to find the requests both by pointer and by URL. Given that the number of requests
- // is generally very small (typically < 10 at a time), hashing by URL incurs too much overhead
- // anyway.
- const auto it = pending.find(resource);
- if (it != pending.end()) {
- return it->second;
- }
- return nullptr;
-}
-
-Request *DefaultFileSource::request(const Resource &resource, uv_loop_t *l, Callback callback) {
- auto req = new Request(resource, l, std::move(callback));
-
- // This function can be called from any thread. Make sure we're executing the actual call in the
- // file source loop by sending it over the queue. It will be processed in processAction().
- queue->send(AddRequestAction{ req });
- return req;
-}
-
-void DefaultFileSource::request(const Resource &resource, Callback callback) {
- auto req = new Request(resource, nullptr, std::move(callback));
-
- // This function can be called from any thread. Make sure we're executing the actual call in the
- // file source loop by sending it over the queue. It will be processed in processAction().
- queue->send(AddRequestAction{ req });
-}
-
-void DefaultFileSource::cancel(Request *req) {
- req->cancel();
-
- // This function can be called from any thread. Make sure we're executing the actual call in the
- // file source loop by sending it over the queue. It will be processed in processAction().
- queue->send(RemoveRequestAction{ req });
-}
-
-void DefaultFileSource::process(AddRequestAction &action) {
- const Resource &resource = action.request->resource;
-
- // We're adding a new Request.
- SharedRequestBase *sharedRequest = find(resource);
- if (!sharedRequest) {
- // There is no request for this URL yet. Create a new one and start it.
- if (algo::starts_with(resource.url, "asset://")) {
- sharedRequest = new AssetRequest(this, resource);
- } else {
- sharedRequest = new HTTPRequest(this, resource);
- }
-
- // Make sure the loop stays alive when we're not running the file source in it's own thread.
- if (!thread.joinable() && pending.empty()) {
- queue->ref();
- }
-
- const bool inserted = pending.emplace(resource, sharedRequest).second;
- assert(inserted);
- (void (inserted)); // silence unused variable warning on Release builds.
-
- // But first, we're going to start querying the database if it exists.
- if (!cache) {
- sharedRequest->start(loop);
- } else {
- // Otherwise, first check the cache for existing data so that we can potentially
- // revalidate the information without having to redownload everything.
- cache->get(resource, [this, resource](std::unique_ptr<Response> response) {
- queue->send(ResultAction { resource, std::move(response) });
- });
- }
- }
- sharedRequest->subscribe(action.request);
-}
-
-void DefaultFileSource::process(RemoveRequestAction &action) {
- SharedRequestBase *sharedRequest = find(action.request->resource);
- if (sharedRequest) {
- // If the number of dependent requests of the SharedRequestBase drops to zero, the
- // unsubscribe callback triggers the removal of the SharedRequestBase pointer from the list
- // of pending requests and initiates cancelation.
- sharedRequest->unsubscribe(action.request);
- } else {
- // There is no request for this URL anymore. Likely, the request already completed
- // before we got around to process the cancelation request.
- }
-
- // Send a message back to the requesting thread and notify it that this request has been
- // canceled and is now safe to be deleted.
- action.request->destruct();
-}
-
-void DefaultFileSource::process(ResultAction &action) {
- SharedRequestBase *sharedRequest = find(action.resource);
- if (sharedRequest) {
- if (action.response) {
- // This entry was stored in the cache. Now determine if we need to revalidate.
- const int64_t now = std::chrono::duration_cast<std::chrono::seconds>(
- std::chrono::system_clock::now().time_since_epoch()).count();
- if (action.response->expires > now) {
- // The response is fresh. We're good to notify the caller.
- sharedRequest->notify(std::move(action.response), FileCache::Hint::No);
- sharedRequest->cancel();
- return;
- } else {
- // The cached response is stale. Now run the real request.
- sharedRequest->start(loop, std::move(action.response));
- }
- } else {
- // There is no response. Now run the real request.
- sharedRequest->start(loop);
- }
- } else {
- // There is no request for this URL anymore. Likely, the request was canceled
- // before we got around to process the cache result.
- }
-}
-
-void DefaultFileSource::process(StopAction &) {
- // Cancel all remaining requests.
- for (auto it : pending) {
- it.second->unsubscribeAll();
- }
- pending.clear();
-
- assert(queue);
- queue->stop();
- queue = nullptr;
-}
-
-void DefaultFileSource::notify(SharedRequestBase *sharedRequest,
- const std::set<Request *> &observers,
- std::shared_ptr<const Response> response, FileCache::Hint hint) {
- // First, remove the request, since it might be destructed at any point now.
- assert(find(sharedRequest->resource) == sharedRequest);
- pending.erase(sharedRequest->resource);
-
- if (response) {
- if (cache) {
- // Store response in database
- cache->put(sharedRequest->resource, response, hint);
- }
-
- // Notify all observers.
- for (auto it : observers) {
- it->notify(response);
- }
- }
-
- if (!thread.joinable() && pending.empty()) {
- // When there are no pending requests, we're going to allow the queue to stop.
- queue->unref();
- }
-}
-
-}
diff --git a/platform/default/http_request_curl.cpp b/platform/default/http_request_curl.cpp
index 9218563ee4..411c5ee470 100644
--- a/platform/default/http_request_curl.cpp
+++ b/platform/default/http_request_curl.cpp
@@ -99,7 +99,11 @@ private:
static size_t writeCallback(void *const contents, const size_t size, const size_t nmemb, void *userp);
void retry(uint64_t timeout);
+#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
static void restart(uv_timer_t *timer, int);
+#else
+ static void restart(uv_timer_t *timer);
+#endif
void finish(ResponseStatus status);
void start();
@@ -161,8 +165,8 @@ private:
// -------------------------------------------------------------------------------------------------
-template<> pthread_key_t HTTPContext<HTTPCURLContext>::key{};
-template<> pthread_once_t HTTPContext<HTTPCURLContext>::once = PTHREAD_ONCE_INIT;
+template<> pthread_key_t ThreadContext<HTTPCURLContext>::key{};
+template<> pthread_once_t ThreadContext<HTTPCURLContext>::once = PTHREAD_ONCE_INIT;
HTTPCURLContext::HTTPCURLContext(uv_loop_t *loop_) : HTTPContext(loop_) {
if (curl_global_init(CURL_GLOBAL_ALL)) {
@@ -491,7 +495,11 @@ void HTTPRequestImpl::retryImmediately() {
}
}
+#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
void HTTPRequestImpl::restart(uv_timer_t *timer, int) {
+#else
+void HTTPRequestImpl::restart(uv_timer_t *timer) {
+#endif
// Restart the request.
auto baton = reinterpret_cast<HTTPRequestImpl *>(timer->data);
diff --git a/platform/default/uv_zip.c b/platform/default/uv_zip.c
new file mode 100644
index 0000000000..b6d2c2ebe0
--- /dev/null
+++ b/platform/default/uv_zip.c
@@ -0,0 +1,202 @@
+#include "uv_zip.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+
+void uv__zip_open_error(uv_zip_t *zip, int error) {
+ zip->result = -error;
+ if (zip->message) {
+ free((char *)zip->message);
+ zip->message = NULL;
+ }
+ const zip_uint64_t size = zip_error_to_str(NULL, 0, error, errno) + 1;
+ zip->message = malloc(size);
+ zip_error_to_str((char *)zip->message, size, error, errno);
+}
+
+void uv__zip_store_error(uv_zip_t *zip, const char *message) {
+ if (zip->message) {
+ free((char *)zip->message);
+ zip->message = NULL;
+ }
+ const unsigned long length = strlen(message);
+ zip->message = malloc(length);
+ strncpy((char *)zip->message, message, length);
+}
+
+void uv__zip_error(uv_zip_t *zip) {
+ int error;
+ zip_error_get(zip->archive, &error, NULL);
+ zip->result = -error;
+ uv__zip_store_error(zip, zip_strerror(zip->archive));
+}
+
+void uv__zip_file_error(uv_zip_t *zip) {
+ int error;
+ zip_file_error_get(zip->file, &error, NULL);
+ zip->result = -error;
+ uv__zip_store_error(zip, zip_file_strerror(zip->file));
+}
+
+void uv__zip_work_open(uv_work_t *req) {
+ uv_zip_t *zip = (uv_zip_t *)req->data;
+ assert(!zip->archive);
+
+ int error;
+ zip->archive = zip_open(zip->path, zip->flags, &error);
+ if (!zip->archive) {
+ uv__zip_open_error(zip, error);
+ } else {
+ zip->result = 0;
+ }
+}
+
+void uv__zip_work_fdopen(uv_work_t *req) {
+ uv_zip_t *zip = (uv_zip_t *)req->data;
+ assert(!zip->archive);
+
+ // extract the fd
+ uv_file fd = *(uv_file *)zip->path;
+ free((uv_file *)zip->path);
+ zip->path = NULL;
+
+ int error;
+ zip->archive = zip_fdopen(fd, zip->flags, &error);
+ if (!zip->archive) {
+ uv__zip_open_error(zip, error);
+ } else {
+ zip->result = 0;
+ }
+}
+
+void uv__zip_work_stat(uv_work_t *req) {
+ uv_zip_t *zip = (uv_zip_t *)req->data;
+ assert(zip->archive);
+ if (!zip->stat) {
+ zip->stat = malloc(sizeof(struct zip_stat));
+ zip_stat_init(zip->stat);
+ }
+ if (0 != zip_stat(zip->archive, zip->path, zip->flags, zip->stat)) {
+ uv__zip_error(zip);
+ }
+}
+
+void uv__zip_work_fopen(uv_work_t *req) {
+ uv_zip_t *zip = (uv_zip_t *)req->data;
+ assert(zip->archive);
+ zip->file = zip_fopen(zip->archive, zip->path, zip->flags);
+ if (!zip->file) {
+ uv__zip_error(zip);
+ }
+}
+
+void uv__zip_work_fread(uv_work_t *req) {
+ uv_zip_t *zip = (uv_zip_t *)req->data;
+ assert(zip->file);
+ assert(zip->buf);
+ zip->result = zip_fread(zip->file, zip->buf->base, zip->buf->len);
+ if (zip->result < 0) {
+ uv__zip_file_error(zip);
+ }
+}
+
+void uv__zip_work_fclose(uv_work_t *req) {
+ uv_zip_t *zip = (uv_zip_t *)req->data;
+ assert(zip->file);
+ zip->result = zip_fclose(zip->file);
+ if (zip->result != 0) {
+ uv__zip_file_error(zip);
+ }
+}
+
+void uv__zip_work_discard(uv_work_t *req) {
+ uv_zip_t *zip = (uv_zip_t *)req->data;
+ assert(zip->archive);
+ zip_discard(zip->archive);
+ zip->archive = NULL;
+ zip->result = 0;
+}
+
+void uv__zip_after_work(uv_work_t *req, int status) {
+ uv_zip_t *zip = (uv_zip_t *)req->data;
+ if (zip->cb) {
+ zip->cb(zip);
+ }
+}
+
+void uv_zip_init(uv_zip_t *zip) {
+ zip->work.data = zip;
+ zip->message = NULL;
+ zip->stat = NULL;
+ uv_zip_cleanup(zip);
+}
+
+void uv_zip_cleanup(uv_zip_t *zip) {
+ zip->data = NULL;
+ zip->flags = 0;
+ zip->result = 0;
+ zip->path = NULL;
+ zip->cb = NULL;
+ zip->archive = NULL;
+ zip->file = NULL;
+ zip->buf = NULL;
+
+ if (zip->message) {
+ free((char *)zip->message);
+ zip->message = NULL;
+ }
+
+ if (zip->stat) {
+ free(zip->stat);
+ zip->stat = NULL;
+ }
+}
+
+int uv_zip_open(uv_loop_t* loop, uv_zip_t *zip, const char *path, zip_flags_t flags, uv_zip_cb cb) {
+ zip->path = path;
+ zip->flags = flags;
+ zip->cb = cb;
+ return uv_queue_work(loop, &zip->work, uv__zip_work_open, uv__zip_after_work);
+}
+
+int uv_zip_fdopen(uv_loop_t* loop, uv_zip_t *zip, uv_file fd, int flags, uv_zip_cb cb) {
+ zip->path = malloc(sizeof(uv_file));
+ *(uv_file *)zip->path = fd;
+ zip->flags = flags;
+ zip->cb = cb;
+ return uv_queue_work(loop, &zip->work, uv__zip_work_fdopen, uv__zip_after_work);
+}
+
+int uv_zip_stat(uv_loop_t* loop, uv_zip_t *zip, const char *fname, zip_flags_t flags, uv_zip_cb cb) {
+ zip->path = fname;
+ zip->flags = flags;
+ zip->cb = cb;
+ return uv_queue_work(loop, &zip->work, uv__zip_work_stat, uv__zip_after_work);
+}
+
+int uv_zip_fopen(uv_loop_t* loop, uv_zip_t *zip, const char *fname, zip_flags_t flags, uv_zip_cb cb) {
+ zip->path = fname;
+ zip->flags = flags;
+ zip->cb = cb;
+ return uv_queue_work(loop, &zip->work, uv__zip_work_fopen, uv__zip_after_work);
+}
+
+int uv_zip_fclose(uv_loop_t* loop, uv_zip_t *zip, struct zip_file *file, uv_zip_cb cb) {
+ zip->file = file;
+ zip->cb = cb;
+ return uv_queue_work(loop, &zip->work, uv__zip_work_fclose, uv__zip_after_work);
+}
+
+int uv_zip_fread(uv_loop_t* loop, uv_zip_t *zip, struct zip_file *file, uv_buf_t *buf, uv_zip_cb cb) {
+ zip->file = file;
+ zip->buf = buf;
+ zip->cb = cb;
+ return uv_queue_work(loop, &zip->work, uv__zip_work_fread, uv__zip_after_work);
+}
+
+int uv_zip_discard(uv_loop_t* loop, uv_zip_t *zip, uv_zip_cb cb) {
+ zip->cb = cb;
+ return uv_queue_work(loop, &zip->work, uv__zip_work_discard, uv__zip_after_work);
+}
diff --git a/platform/default/uv_zip.h b/platform/default/uv_zip.h
new file mode 100644
index 0000000000..5908763f09
--- /dev/null
+++ b/platform/default/uv_zip.h
@@ -0,0 +1,45 @@
+#ifndef UV_ZIP
+#define UV_ZIP
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#include <uv.h>
+#include <zip.h>
+
+typedef struct uv_zip_s uv_zip_t;
+
+typedef void (*uv_zip_cb)(uv_zip_t* req);
+
+struct uv_zip_s {
+ uv_work_t work;
+ ssize_t result;
+ const char *message;
+ struct zip *archive;
+ struct zip_file *file;
+ struct zip_stat *stat;
+ void *data;
+ zip_flags_t flags;
+ const char *path;
+ uv_zip_cb cb;
+ uv_buf_t *buf;
+};
+
+void uv_zip_init(uv_zip_t *zip);
+void uv_zip_cleanup(uv_zip_t *zip);
+
+int uv_zip_open(uv_loop_t* loop, uv_zip_t *zip, const char *path, zip_flags_t flags, uv_zip_cb cb);
+int uv_zip_fdopen(uv_loop_t* loop, uv_zip_t *zip, uv_file fd, int flags, uv_zip_cb cb);
+int uv_zip_stat(uv_loop_t* loop, uv_zip_t *zip, const char *fname, zip_flags_t flags, uv_zip_cb cb);
+int uv_zip_fopen(uv_loop_t* loop, uv_zip_t *zip, const char *fname, zip_flags_t flags, uv_zip_cb cb);
+int uv_zip_fread(uv_loop_t* loop, uv_zip_t *zip, struct zip_file *file, uv_buf_t *buf, uv_zip_cb cb);
+int uv_zip_fclose(uv_loop_t* loop, uv_zip_t *zip, struct zip_file *file, uv_zip_cb cb);
+int uv_zip_discard(uv_loop_t* loop, uv_zip_t *zip, uv_zip_cb cb);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // UV_ZIP