summaryrefslogtreecommitdiff
path: root/src/node_file_source.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/node_file_source.cpp')
-rw-r--r--src/node_file_source.cpp156
1 files changed, 156 insertions, 0 deletions
diff --git a/src/node_file_source.cpp b/src/node_file_source.cpp
new file mode 100644
index 0000000000..6ce81c0647
--- /dev/null
+++ b/src/node_file_source.cpp
@@ -0,0 +1,156 @@
+#include "node_file_source.hpp"
+#include "node_request.hpp"
+
+#include <mbgl/storage/default/request.hpp>
+#include <mbgl/util/async_queue.hpp>
+
+namespace node_mbgl {
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+// Static Node Methods
+
+v8::Persistent<v8::FunctionTemplate> NodeFileSource::constructorTemplate;
+
+void NodeFileSource::Init(v8::Handle<v8::Object> target) {
+ NanScope();
+
+ v8::Local<v8::FunctionTemplate> t = NanNew<v8::FunctionTemplate>(New);
+
+ t->InstanceTemplate()->SetInternalFieldCount(1);
+ t->SetClassName(NanNew("FileSource"));
+
+ NanAssignPersistent(constructorTemplate, t);
+
+ target->Set(NanNew("FileSource"), t->GetFunction());
+}
+
+NAN_METHOD(NodeFileSource::New) {
+ NanScope();
+
+ if (!args.IsConstructCall()) {
+ return NanThrowTypeError("Use the new operator to create new FileSource objects");
+ }
+
+ auto fs = new NodeFileSource();
+ fs->Wrap(args.This());
+
+ NanReturnValue(args.This());
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+// Instance
+
+struct NodeFileSource::Action {
+ const enum : bool { Add, Cancel } type;
+ mbgl::Request *const request;
+};
+
+NodeFileSource::NodeFileSource() :
+ queue(new Queue(uv_default_loop(), [this](Action &action) {
+ if (action.type == Action::Add) {
+ processAdd(action.request);
+ } else if (action.type == Action::Cancel) {
+ processCancel(action.request);
+ }
+ }))
+{
+ // Make sure that the queue doesn't block the loop from exiting.
+ queue->unref();
+}
+
+NodeFileSource::~NodeFileSource() {
+ queue->stop();
+ queue = nullptr;
+}
+
+mbgl::Request *NodeFileSource::request(const mbgl::Resource& resource, uv_loop_t *loop, Callback callback) {
+ auto request = new mbgl::Request(resource, loop, 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(Action{ Action::Add, request });
+ return request;
+}
+
+void NodeFileSource::request(const mbgl::Resource &resource, Callback callback) {
+ auto request = new mbgl::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(Action{ Action::Add, request });
+}
+
+
+void NodeFileSource::cancel(mbgl::Request *request) {
+ request->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(Action{ Action::Cancel, request });
+}
+
+
+void NodeFileSource::processAdd(mbgl::Request *request) {
+ NanScope();
+
+ // Make sure the loop stays alive as long as request is pending.
+ if (pending.empty()) {
+ queue->ref();
+ }
+
+ auto requestHandle = v8::Local<v8::Object>::New(NodeRequest::Create(handle_, request));
+ pending.emplace(request, std::move(v8::Persistent<v8::Object>::New(requestHandle)));
+
+ v8::Local<v8::Value> argv[] = { requestHandle };
+ NanMakeCallback(handle_, NanNew("request"), 1, argv);
+}
+
+void NodeFileSource::processCancel(mbgl::Request *request) {
+ NanScope();
+
+ auto it = pending.find(request);
+ 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 {
+ auto requestHandle = v8::Local<v8::Object>::New(it->second);
+
+ // Dispose and remove the persistent handle
+ it->second.Dispose();
+ pending.erase(it);
+
+ // Make sure the the loop can exit when there are no pending requests.
+ if (pending.empty()) {
+ queue->unref();
+ }
+
+ if (handle_->Has(NanNew("cancel"))) {
+ v8::Local<v8::Value> argv[] = { requestHandle };
+ NanMakeCallback(handle_, NanNew("cancel"), 1, argv);
+ }
+
+ // Set the request handle in the request wrapper handle to null
+ ObjectWrap::Unwrap<NodeRequest>(requestHandle)->cancel();
+ }
+
+ // Finally, destruct the request object
+ request->destruct();
+}
+
+void NodeFileSource::notify(mbgl::Request *request, 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(request);
+ if (it != pending.end()) {
+ it->second.Dispose();
+ pending.erase(it);
+
+ // Make sure the the loop can exit when there are no pending requests.
+ if (pending.empty()) {
+ queue->unref();
+ }
+ }
+
+ request->notify(response);
+}
+
+}