summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThiago Marcos P. Santos <tmpsantos@gmail.com>2017-07-11 15:33:45 +0300
committerThiago Marcos P. Santos <tmpsantos@gmail.com>2017-07-11 19:33:07 +0300
commitab86acec722c9e7f751b1f2b8c7d82ec7a36d34a (patch)
tree52513ce4bd2552b8110ac4feb3280cd32c18e51d
parent90c61c195622c8b3106ed4a3d5c6080dfa8a65e0 (diff)
downloadqtlocation-mapboxgl-ab86acec722c9e7f751b1f2b8c7d82ec7a36d34a.tar.gz
[node] Use the DefaultFileSource
We can remove a lot of code and make the bindings a lot simpler by reusing the DefaultFileSource that is backed by curl. This file source is widely tested by the [core] unit tests and used by all the SDKs. The curl backend is used by the Linux port and is known to be very stable. This will also simplify the request logic. Previously the flow for making a resource request was complicated to be implemented in the bindings and had issues regarding object lifecycle.
-rw-r--r--cmake/node.cmake2
-rw-r--r--platform/node/src/node_map.cpp97
-rw-r--r--platform/node/src/node_map.hpp17
-rw-r--r--platform/node/src/node_mapbox_gl_native.cpp37
-rw-r--r--platform/node/src/node_request.cpp157
-rw-r--r--platform/node/src/node_request.hpp49
6 files changed, 14 insertions, 345 deletions
diff --git a/cmake/node.cmake b/cmake/node.cmake
index 502edd8293..fcd99413fc 100644
--- a/cmake/node.cmake
+++ b/cmake/node.cmake
@@ -15,8 +15,6 @@ target_sources(mbgl-node
PRIVATE platform/node/src/node_logging.cpp
PRIVATE platform/node/src/node_map.hpp
PRIVATE platform/node/src/node_map.cpp
- PRIVATE platform/node/src/node_request.hpp
- PRIVATE platform/node/src/node_request.cpp
PRIVATE platform/node/src/node_feature.hpp
PRIVATE platform/node/src/node_feature.cpp
PRIVATE platform/node/src/node_thread_pool.hpp
diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp
index 9ba88193c9..8ebcebab5e 100644
--- a/platform/node/src/node_map.cpp
+++ b/platform/node/src/node_map.cpp
@@ -1,5 +1,4 @@
#include "node_map.hpp"
-#include "node_request.hpp"
#include "node_feature.hpp"
#include "node_conversion.hpp"
#include "node_geojson.hpp"
@@ -12,7 +11,9 @@
#include <mbgl/style/style.hpp>
#include <mbgl/style/image.hpp>
#include <mbgl/map/backend_scope.hpp>
+#include <mbgl/map/map.hpp>
#include <mbgl/map/query.hpp>
+#include <mbgl/storage/default_file_source.hpp>
#include <mbgl/util/premultiply.hpp>
#include <unistd.h>
@@ -59,7 +60,6 @@ void NodeMap::Init(v8::Local<v8::Object> target) {
Nan::SetPrototypeMethod(tpl, "loaded", Loaded);
Nan::SetPrototypeMethod(tpl, "render", Render);
Nan::SetPrototypeMethod(tpl, "release", Release);
- Nan::SetPrototypeMethod(tpl, "cancel", Cancel);
Nan::SetPrototypeMethod(tpl, "addSource", AddSource);
Nan::SetPrototypeMethod(tpl, "addLayer", AddLayer);
@@ -85,38 +85,17 @@ void NodeMap::Init(v8::Local<v8::Object> target) {
}
/**
- * A request object, given to the `request` handler of a map, is an
- * encapsulation of a URL and type of a resource that the map asks you to load.
- *
- * The `kind` property is one of
- *
- * "Unknown": 0,
- * "Style": 1,
- * "Source": 2,
- * "Tile": 3,
- * "Glyphs": 4,
- * "SpriteImage": 5,
- * "SpriteJSON": 6
- *
- * @typedef
- * @name Request
- * @property {string} url
- * @property {number} kind
- */
-
-/**
* Mapbox GL object: this object loads stylesheets and renders them into
* images.
*
* @class
* @name Map
* @param {Object} options
- * @param {Function} options.request a method used to request resources
* over the internet
* @param {Function} [options.cancel]
* @param {number} options.ratio pixel ratio
* @example
- * var map = new mbgl.Map({ request: function() {} });
+ * var map = new mbgl.Map({ ratio: 1 });
* map.load(require('./test/fixtures/style.json'));
* map.render({}, function(err, image) {
* if (err) throw err;
@@ -134,18 +113,6 @@ void NodeMap::New(const Nan::FunctionCallbackInfo<v8::Value>& info) {
auto options = Nan::To<v8::Object>(info[0]).ToLocalChecked();
- // Check that 'request' is set. If 'cancel' is set it must be a
- // function and if 'ratio' is set it must be a number.
- if (!Nan::Has(options, Nan::New("request").ToLocalChecked()).FromJust()
- || !Nan::Get(options, Nan::New("request").ToLocalChecked()).ToLocalChecked()->IsFunction()) {
- return Nan::ThrowError("Options object must have a 'request' method");
- }
-
- if (Nan::Has(options, Nan::New("cancel").ToLocalChecked()).FromJust()
- && !Nan::Get(options, Nan::New("cancel").ToLocalChecked()).ToLocalChecked()->IsFunction()) {
- return Nan::ThrowError("Options object 'cancel' property must be a function");
- }
-
if (Nan::Has(options, Nan::New("ratio").ToLocalChecked()).FromJust()
&& !Nan::Get(options, Nan::New("ratio").ToLocalChecked()).ToLocalChecked()->IsNumber()) {
return Nan::ThrowError("Options object 'ratio' property must be a number");
@@ -506,42 +473,6 @@ void NodeMap::release() {
map.reset();
}
-/**
- * Cancel an ongoing render request. The callback will be called with
- * the error set to "Canceled". Will throw if no rendering is in progress.
- * @name cancel
- * @returns {undefined}
- */
-void NodeMap::Cancel(const Nan::FunctionCallbackInfo<v8::Value>& info) {
- auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
-
- if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
- if (!nodeMap->callback) return Nan::ThrowError("No render in progress");
-
- try {
- nodeMap->cancel();
- } catch (const std::exception &ex) {
- return Nan::ThrowError(ex.what());
- }
-
- info.GetReturnValue().SetUndefined();
-}
-
-void NodeMap::cancel() {
- auto style = map->getStyle().getJSON();
-
- map = std::make_unique<mbgl::Map>(backend, mbgl::Size{ 256, 256 },
- pixelRatio, *this, threadpool, mbgl::MapMode::Still);
-
- // FIXME: Reload the style after recreating the map. We need to find
- // a better way of canceling an ongoing rendering on the core level
- // without resetting the map, which is way too expensive.
- map->getStyle().loadJSON(style);
-
- error = std::make_exception_ptr(std::runtime_error("Canceled"));
- renderFinished();
-}
-
void NodeMap::AddSource(const Nan::FunctionCallbackInfo<v8::Value>& info) {
using namespace mbgl::style;
using namespace mbgl::style::conversion;
@@ -982,10 +913,11 @@ NodeMap::NodeMap(v8::Local<v8::Object> options)
->NumberValue()
: 1.0;
}()),
+ fileSource(std::make_unique<mbgl::DefaultFileSource>(":memory:", ".")),
map(std::make_unique<mbgl::Map>(backend,
mbgl::Size{ 256, 256 },
pixelRatio,
- *this,
+ *fileSource,
threadpool,
mbgl::MapMode::Still)),
async(new uv_async_t) {
@@ -1003,23 +935,4 @@ NodeMap::~NodeMap() {
if (map) release();
}
-std::unique_ptr<mbgl::AsyncRequest> NodeMap::request(const mbgl::Resource& resource, mbgl::FileSource::Callback callback_) {
- Nan::HandleScope scope;
-
- v8::Local<v8::Value> argv[] = {
- Nan::New<v8::External>(this),
- Nan::New<v8::External>(&callback_)
- };
-
- auto instance = Nan::New(NodeRequest::constructor)->NewInstance(2, argv);
-
- Nan::Set(instance, Nan::New("url").ToLocalChecked(), Nan::New(resource.url).ToLocalChecked());
- Nan::Set(instance, Nan::New("kind").ToLocalChecked(), Nan::New<v8::Integer>(resource.kind));
-
- auto request = Nan::ObjectWrap::Unwrap<NodeRequest>(instance);
- request->Execute();
-
- return std::make_unique<NodeRequest::NodeAsyncRequest>(request);
-}
-
} // namespace node_mbgl
diff --git a/platform/node/src/node_map.hpp b/platform/node/src/node_map.hpp
index 7b81ecd894..230377d1a2 100644
--- a/platform/node/src/node_map.hpp
+++ b/platform/node/src/node_map.hpp
@@ -2,8 +2,6 @@
#include "node_thread_pool.hpp"
-#include <mbgl/map/map.hpp>
-#include <mbgl/storage/file_source.hpp>
#include <mbgl/gl/headless_backend.hpp>
#include <mbgl/gl/offscreen_view.hpp>
@@ -15,6 +13,13 @@
#include <nan.h>
#pragma GCC diagnostic pop
+namespace mbgl {
+
+class Map;
+class DefaultFileSource;
+
+}
+
namespace node_mbgl {
class NodeBackend : public mbgl::HeadlessBackend {
@@ -23,8 +28,7 @@ public:
void onDidFailLoadingMap(std::exception_ptr) final;
};
-class NodeMap : public Nan::ObjectWrap,
- public mbgl::FileSource {
+class NodeMap : public Nan::ObjectWrap {
public:
struct RenderOptions;
class RenderWorker;
@@ -61,16 +65,13 @@ public:
void renderFinished();
void release();
- void cancel();
-
static RenderOptions ParseOptions(v8::Local<v8::Object>);
- std::unique_ptr<mbgl::AsyncRequest> request(const mbgl::Resource&, mbgl::FileSource::Callback);
-
const float pixelRatio;
NodeBackend backend;
std::unique_ptr<mbgl::OffscreenView> view;
NodeThreadPool threadpool;
+ std::unique_ptr<mbgl::DefaultFileSource> fileSource;
std::unique_ptr<mbgl::Map> map;
std::exception_ptr error;
diff --git a/platform/node/src/node_mapbox_gl_native.cpp b/platform/node/src/node_mapbox_gl_native.cpp
index cdcc982220..b27898cde4 100644
--- a/platform/node/src/node_mapbox_gl_native.cpp
+++ b/platform/node/src/node_mapbox_gl_native.cpp
@@ -9,7 +9,6 @@
#include "node_map.hpp"
#include "node_logging.hpp"
-#include "node_request.hpp"
void RegisterModule(v8::Local<v8::Object> target, v8::Local<v8::Object> module) {
// This has the effect of:
@@ -19,42 +18,6 @@ void RegisterModule(v8::Local<v8::Object> target, v8::Local<v8::Object> module)
nodeRunLoop.stop();
node_mbgl::NodeMap::Init(target);
- node_mbgl::NodeRequest::Init();
-
- // Exports Resource constants.
- v8::Local<v8::Object> resource = Nan::New<v8::Object>();
-
- Nan::Set(resource,
- Nan::New("Unknown").ToLocalChecked(),
- Nan::New(mbgl::Resource::Unknown));
-
- Nan::Set(resource,
- Nan::New("Style").ToLocalChecked(),
- Nan::New(mbgl::Resource::Style));
-
- Nan::Set(resource,
- Nan::New("Source").ToLocalChecked(),
- Nan::New(mbgl::Resource::Source));
-
- Nan::Set(resource,
- Nan::New("Tile").ToLocalChecked(),
- Nan::New(mbgl::Resource::Tile));
-
- Nan::Set(resource,
- Nan::New("Glyphs").ToLocalChecked(),
- Nan::New(mbgl::Resource::Glyphs));
-
- Nan::Set(resource,
- Nan::New("SpriteImage").ToLocalChecked(),
- Nan::New(mbgl::Resource::SpriteImage));
-
- Nan::Set(resource,
- Nan::New("SpriteJSON").ToLocalChecked(),
- Nan::New(mbgl::Resource::SpriteJSON));
-
- Nan::Set(target,
- Nan::New("Resource").ToLocalChecked(),
- resource);
// Make the exported object inherit from EventEmitter
v8::Local<v8::Function> require = Nan::Get(module,
diff --git a/platform/node/src/node_request.cpp b/platform/node/src/node_request.cpp
deleted file mode 100644
index 09373b1779..0000000000
--- a/platform/node/src/node_request.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-#include "node_request.hpp"
-#include "node_map.hpp"
-#include <mbgl/storage/response.hpp>
-#include <mbgl/util/chrono.hpp>
-
-#include <cmath>
-
-namespace node_mbgl {
-
-NodeRequest::NodeRequest(
- NodeMap* target_,
- mbgl::FileSource::Callback callback_)
- : AsyncWorker(nullptr),
- target(target_),
- callback(std::move(callback_)) {
-}
-
-NodeRequest::~NodeRequest() {
- // When this object gets garbage collected, make sure that the
- // AsyncRequest can no longer attempt to remove the callback function
- // this object was holding (it can't be fired anymore).
- if (asyncRequest) {
- asyncRequest->request = nullptr;
- }
-}
-
-Nan::Persistent<v8::Function> NodeRequest::constructor;
-
-void NodeRequest::Init() {
- v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
-
- tpl->InstanceTemplate()->SetInternalFieldCount(1);
- tpl->SetClassName(Nan::New("Request").ToLocalChecked());
-
- Nan::SetPrototypeMethod(tpl, "respond", HandleCallback);
-
- constructor.Reset(tpl->GetFunction());
-}
-
-void NodeRequest::New(const Nan::FunctionCallbackInfo<v8::Value>& info) {
- auto target = reinterpret_cast<NodeMap*>(info[0].As<v8::External>()->Value());
- auto callback = reinterpret_cast<mbgl::FileSource::Callback*>(info[1].As<v8::External>()->Value());
-
- auto request = new NodeRequest(target, *callback);
-
- request->Wrap(info.This());
- info.GetReturnValue().Set(info.This());
-}
-
-void NodeRequest::HandleCallback(const Nan::FunctionCallbackInfo<v8::Value>& info) {
- auto request = Nan::ObjectWrap::Unwrap<NodeRequest>(info.Holder());
-
- // Move out of the object so callback() can only be fired once.
- auto callback = std::move(request->callback);
- if (!callback) {
- return info.GetReturnValue().SetUndefined();
- }
-
- mbgl::Response response;
-
- if (info.Length() < 1) {
- response.noContent = true;
- } else if (info[0]->IsObject()) {
- auto err = Nan::To<v8::Object>(info[0]).ToLocalChecked();
- auto msg = Nan::New("message").ToLocalChecked();
-
- if (Nan::Has(err, msg).FromJust()) {
- request->SetErrorMessage(*Nan::Utf8String(
- Nan::Get(err, msg).ToLocalChecked()));
- }
- } else if (info[0]->IsString()) {
- request->SetErrorMessage(*Nan::Utf8String(info[0]));
- } else if (info.Length() < 2 || !info[1]->IsObject()) {
- return Nan::ThrowTypeError("Second argument must be a response object");
- } else {
- auto res = Nan::To<v8::Object>(info[1]).ToLocalChecked();
-
- if (Nan::Has(res, Nan::New("modified").ToLocalChecked()).FromJust()) {
- const double modified = Nan::To<double>(Nan::Get(res, Nan::New("modified").ToLocalChecked()).ToLocalChecked()).FromJust();
- if (!std::isnan(modified)) {
- response.modified = mbgl::Timestamp{ mbgl::Seconds(
- static_cast<mbgl::Seconds::rep>(modified / 1000)) };
- }
- }
-
- if (Nan::Has(res, Nan::New("expires").ToLocalChecked()).FromJust()) {
- const double expires = Nan::To<double>(Nan::Get(res, Nan::New("expires").ToLocalChecked()).ToLocalChecked()).FromJust();
- if (!std::isnan(expires)) {
- response.expires = mbgl::Timestamp{ mbgl::Seconds(
- static_cast<mbgl::Seconds::rep>(expires / 1000)) };
- }
- }
-
- if (Nan::Has(res, Nan::New("etag").ToLocalChecked()).FromJust()) {
- const Nan::Utf8String etag(Nan::Get(res, Nan::New("etag").ToLocalChecked()).ToLocalChecked());
- response.etag = std::string { *etag, size_t(etag.length()) };
- }
-
- if (Nan::Has(res, Nan::New("data").ToLocalChecked()).FromJust()) {
- auto data = Nan::Get(res, Nan::New("data").ToLocalChecked()).ToLocalChecked();
- if (node::Buffer::HasInstance(data)) {
- response.data = std::make_shared<std::string>(
- node::Buffer::Data(data),
- node::Buffer::Length(data)
- );
- } else {
- return Nan::ThrowTypeError("Response data must be a Buffer");
- }
- }
- }
-
- if (request->ErrorMessage()) {
- response.error = std::make_unique<mbgl::Response::Error>(
- mbgl::Response::Error::Reason::Other,
- request->ErrorMessage()
- );
- }
-
- // Send the response object to the NodeFileSource object
- callback(response);
- info.GetReturnValue().SetUndefined();
-}
-
-void NodeRequest::Execute() {
- asyncExecute = std::make_unique<mbgl::util::AsyncTask>([this] { doExecute(); Unref(); });
- asyncExecute->send();
-
- Ref();
-}
-
-void NodeRequest::doExecute() {
- Nan::HandleScope scope;
-
- v8::Local<v8::Value> argv[] = { handle() };
-
- Nan::MakeCallback(Nan::To<v8::Object>(target->handle()->GetInternalField(1)).ToLocalChecked(), "request", 1, argv);
- asyncExecute.reset();
-}
-
-NodeRequest::NodeAsyncRequest::NodeAsyncRequest(NodeRequest* request_) : request(request_) {
- assert(request);
-
- // Make sure the JS object has a pointer to this so that it can remove
- // its pointer in the destructor
- request->asyncRequest = this;
-}
-
-NodeRequest::NodeAsyncRequest::~NodeAsyncRequest() {
- if (request) {
- // Remove the callback function because the AsyncRequest was
- // canceled and we are no longer interested in the result.
- request->callback = {};
- request->asyncRequest = nullptr;
- }
-}
-
-} // namespace node_mbgl
diff --git a/platform/node/src/node_request.hpp b/platform/node/src/node_request.hpp
deleted file mode 100644
index 356566132b..0000000000
--- a/platform/node/src/node_request.hpp
+++ /dev/null
@@ -1,49 +0,0 @@
-#pragma once
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-parameter"
-#pragma GCC diagnostic ignored "-Wshadow"
-#include <nan.h>
-#pragma GCC diagnostic pop
-
-#include <mbgl/storage/resource.hpp>
-#include <mbgl/storage/file_source.hpp>
-#include <mbgl/util/async_task.hpp>
-
-#include <memory>
-
-namespace node_mbgl {
-
-class NodeMap;
-
-class NodeRequest : public Nan::ObjectWrap,
- public Nan::AsyncWorker {
-public:
- struct NodeAsyncRequest : public mbgl::AsyncRequest {
- NodeAsyncRequest(NodeRequest*);
- ~NodeAsyncRequest() override;
- NodeRequest* request;
- };
-
- NodeRequest(NodeMap*, mbgl::FileSource::Callback);
- ~NodeRequest();
-
- static Nan::Persistent<v8::Function> constructor;
-
- static void Init();
-
- static void New(const Nan::FunctionCallbackInfo<v8::Value>&);
- static void HandleCallback(const Nan::FunctionCallbackInfo<v8::Value>&);
-
- void Execute();
-
-private:
- void doExecute();
-
- NodeMap* target;
- mbgl::FileSource::Callback callback;
- NodeAsyncRequest* asyncRequest = nullptr;
- std::unique_ptr<mbgl::util::AsyncTask> asyncExecute;
-};
-
-}