#include "node_request.hpp" #include "node_file_source.hpp" #include #include #include namespace mbgl { //////////////////////////////////////////////////////////////////////////////////////////////// // Static Node Methods Nan::Persistent NodeRequest::constructor; NAN_MODULE_INIT(NodeRequest::Init) { v8::Local tpl = Nan::New(New); tpl->InstanceTemplate()->SetInternalFieldCount(1); tpl->SetClassName(Nan::New("Request").ToLocalChecked()); constructor.Reset(tpl->GetFunction()); Nan::Set(target, Nan::New("Request").ToLocalChecked(), tpl->GetFunction()); } NAN_METHOD(NodeRequest::New) { // Extract the pointer from the first argument if (info.Length() < 2 || !info[0]->IsExternal() || !info[1]->IsExternal()) { return Nan::ThrowTypeError("Cannot create Request objects explicitly"); } auto source = reinterpret_cast(info[0].As()->Value()); auto resource = reinterpret_cast(info[1].As()->Value()); auto req = new NodeRequest(source, *resource); req->Wrap(info.This()); info.GetReturnValue().Set(info.This()); } v8::Handle NodeRequest::Create(NodeFileSource* source, const Resource& resource) { Nan::EscapableHandleScope scope; v8::Local argv[] = { Nan::New(const_cast(source)), Nan::New(const_cast(&resource)) }; auto instance = Nan::New(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(int(resource.kind))); return scope.Escape(instance); } NAN_METHOD(NodeRequest::Respond) { auto nodeRequest = Nan::ObjectWrap::Unwrap(info.Data().As()); // Request has already been responded to, or was canceled, fail silently. if (!nodeRequest->resource) { return info.GetReturnValue().SetUndefined(); } auto source = nodeRequest->source; auto resource = std::move(nodeRequest->resource); if (info.Length() < 1) { auto response = std::make_shared(); using Error = Response::Error; response->error = std::make_unique(Error::Reason::NotFound); source->notify(*resource, response); } else if (info[0]->BooleanValue()) { auto response = std::make_shared(); // Store the error string. const Nan::Utf8String message { info[0]->ToString() }; using Error = Response::Error; response->error = std::make_unique( Error::Reason::Other, std::string{ *message, size_t(message.length()) }); source->notify(*resource, response); } else if (info.Length() < 2 || !info[1]->IsObject()) { return Nan::ThrowTypeError("Second argument must be a response object"); } else { auto response = std::make_shared(); auto res = info[1]->ToObject(); if (Nan::Has(res, Nan::New("modified").ToLocalChecked()).FromJust()) { const double modified = Nan::Get(res, Nan::New("modified").ToLocalChecked()).ToLocalChecked()->ToNumber()->Value(); if (!std::isnan(modified)) { response->modified = modified / 1000; // JS timestamps are milliseconds } } if (Nan::Has(res, Nan::New("expires").ToLocalChecked()).FromJust()) { const double expires = Nan::Get(res, Nan::New("expires").ToLocalChecked()).ToLocalChecked()->ToNumber()->Value(); if (!std::isnan(expires)) { response->expires = expires / 1000; // JS timestamps are milliseconds } } if (Nan::Has(res, Nan::New("etag").ToLocalChecked()).FromJust()) { auto etagHandle = Nan::Get(res, Nan::New("etag").ToLocalChecked()).ToLocalChecked(); if (etagHandle->BooleanValue()) { const Nan::Utf8String etag { etagHandle->ToString() }; response->etag = std::string { *etag, size_t(etag.length()) }; } } if (Nan::Has(res, Nan::New("data").ToLocalChecked()).FromJust()) { auto dataHandle = Nan::Get(res, Nan::New("data").ToLocalChecked()).ToLocalChecked(); if (node::Buffer::HasInstance(dataHandle)) { response->data = std::make_shared( node::Buffer::Data(dataHandle), node::Buffer::Length(dataHandle) ); } else { return Nan::ThrowTypeError("Response data must be a Buffer"); } } // Send the response object to the NodeFileSource object source->notify(*resource, response); } info.GetReturnValue().SetUndefined(); } //////////////////////////////////////////////////////////////////////////////////////////////// // Instance NodeRequest::NodeRequest(NodeFileSource* source_, const Resource& resource_) : source(source_), resource(std::make_unique(resource_)) {} NodeRequest::~NodeRequest() { } void NodeRequest::cancel() { resource.reset(); } }