diff options
Diffstat (limited to 'platform/node/src/node_file_source.cpp')
-rw-r--r-- | platform/node/src/node_file_source.cpp | 139 |
1 files changed, 22 insertions, 117 deletions
diff --git a/platform/node/src/node_file_source.cpp b/platform/node/src/node_file_source.cpp index 8f88919638..9a1d7c055a 100644 --- a/platform/node/src/node_file_source.cpp +++ b/platform/node/src/node_file_source.cpp @@ -1,139 +1,44 @@ #include "node_file_source.hpp" #include "node_request.hpp" -#include "util/async_queue.hpp" - -#include <mbgl/storage/request.hpp> -#include <mbgl/util/run_loop.hpp> namespace node_mbgl { -struct NodeFileSource::Action { - const enum : bool { Add, Cancel } type; - mbgl::Resource const resource; +class NodeFileSourceRequest : public mbgl::FileRequest { +public: + std::unique_ptr<mbgl::WorkRequest> workRequest; }; -NodeFileSource::NodeFileSource(v8::Local<v8::Object> options_) : - queue(new Queue(uv_default_loop(), [this](Action &action) { - if (action.type == Action::Add) { - processAdd(action.resource); - } else if (action.type == Action::Cancel) { - processCancel(action.resource); - } - })) -{ +NodeFileSource::NodeFileSource(v8::Local<v8::Object> options_) + : nodeLoop(uv_default_loop()) { options.Reset(options_); - // Make sure that the queue doesn't block the loop from exiting. - queue->unref(); + // This has the effect of unreffing an async handle, which otherwise would keep the + // default loop running. You would think we could do this in the destructor instead, + // but in fact the destructor might not get called if there's no GC pressure which + // would cause the NodeMap object which owns us to get destroyed. + nodeLoop.stop(); } NodeFileSource::~NodeFileSource() { - queue->stop(); - queue = nullptr; - options.Reset(); } -mbgl::Request* NodeFileSource::request(const mbgl::Resource& resource, Callback callback) { - auto req = new mbgl::Request(resource, mbgl::util::RunLoop::getLoop(), std::move(callback)); - - std::lock_guard<std::mutex> lock(observersMutex); - - assert(observers.find(resource) == observers.end()); - observers[resource] = req; - - // 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(Action{ Action::Add, resource }); - - return req; -} - -void NodeFileSource::cancel(mbgl::Request* req) { - req->cancel(); - - std::lock_guard<std::mutex> lock(observersMutex); - - auto it = observers.find(req->resource); - if (it == observers.end()) { - return; - } - - observers.erase(it); - - // 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(Action{ Action::Cancel, req->resource }); - - req->destruct(); -} - -void NodeFileSource::processAdd(const mbgl::Resource& resource) { - Nan::HandleScope scope; - - // Make sure the loop stays alive as long as request is pending. - if (pending.empty()) { - queue->ref(); - } - - auto requestHandle = NodeRequest::Create(this, resource)->ToObject(); - pending.emplace(resource, requestHandle); - - auto callback = Nan::GetFunction(Nan::New<v8::FunctionTemplate>(NodeRequest::Respond, requestHandle)).ToLocalChecked(); - callback->SetName(Nan::New("respond").ToLocalChecked()); - - v8::Local<v8::Value> argv[] = { requestHandle, callback }; - Nan::MakeCallback(Nan::New(options), "request", 2, argv); -} - -void NodeFileSource::processCancel(const mbgl::Resource& resource) { - Nan::HandleScope scope; - - auto it = pending.find(resource); - if (it == pending.end()) { - // The response callback was already fired. There is no point in calling the cancelation - // callback because the request is already completed. - } else { - v8::Local<v8::Object> requestHandle = Nan::New(it->second); - it->second.Reset(); - pending.erase(it); - - // Make sure the the loop can exit when there are no pending requests. - if (pending.empty()) { - queue->unref(); - } - - if (Nan::Has(Nan::New(options), Nan::New("cancel").ToLocalChecked()).FromJust()) { - v8::Local<v8::Value> argv[] = { requestHandle }; - Nan::MakeCallback(Nan::New(options), "cancel", 1, argv); - } - - // Set the request handle in the request wrapper handle to null - Nan::ObjectWrap::Unwrap<NodeRequest>(requestHandle)->cancel(); - } -} - -void NodeFileSource::notify(const mbgl::Resource& resource, const std::shared_ptr<const mbgl::Response>& response) { - // First, remove the request, since it might be destructed at any point now. - auto it = pending.find(resource); - if (it != pending.end()) { - it->second.Reset(); - pending.erase(it); +std::unique_ptr<mbgl::FileRequest> NodeFileSource::request(const mbgl::Resource& resource, Callback callback) { + auto req = std::make_unique<NodeFileSourceRequest>(); - // Make sure the the loop can exit when there are no pending requests. - if (pending.empty()) { - queue->unref(); - } - } + // This function can be called from any thread. Make sure we're executing the + // JS implementation in the node event loop. + req->workRequest = nodeLoop.invokeWithCallback([this] (mbgl::Resource res, Callback cb) { + Nan::HandleScope scope; - std::lock_guard<std::mutex> lock(observersMutex); + auto requestHandle = NodeRequest::Create(res, cb)->ToObject(); + auto callbackHandle = Nan::GetFunction(Nan::New<v8::FunctionTemplate>(NodeRequest::Respond, requestHandle)).ToLocalChecked(); - auto observersIt = observers.find(resource); - if (observersIt == observers.end()) { - return; - } + v8::Local<v8::Value> argv[] = { requestHandle, callbackHandle }; + Nan::MakeCallback(Nan::New(options), "request", 2, argv); + }, callback, resource); - observersIt->second->notify(response); + return std::move(req); } } |