summaryrefslogtreecommitdiff
path: root/platform/node/src/node_file_source.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'platform/node/src/node_file_source.cpp')
-rw-r--r--platform/node/src/node_file_source.cpp139
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);
}
}