From 24e5d3b0af35f0adf4e461babe35fdf4de1fbed7 Mon Sep 17 00:00:00 2001 From: Siarhei Fedartsou Date: Mon, 7 Nov 2022 17:28:14 +0100 Subject: [PATCH] wip --- include/nodejs/node_osrm.hpp | 1 + include/nodejs/node_osrm_support.hpp | 2818 ++++++++++---------------- src/nodejs/node_osrm.cpp | 696 +------ 3 files changed, 1147 insertions(+), 2368 deletions(-) diff --git a/include/nodejs/node_osrm.hpp b/include/nodejs/node_osrm.hpp index 10d2a0554..8e761f833 100644 --- a/include/nodejs/node_osrm.hpp +++ b/include/nodejs/node_osrm.hpp @@ -22,6 +22,7 @@ private: Napi::Value match(const Napi::CallbackInfo& info); Napi::Value trip(const Napi::CallbackInfo& info); + std::shared_ptr this_; // Napi::Value PlusOne(const Napi::CallbackInfo& info); // Napi::Value Multiply(const Napi::CallbackInfo& info); diff --git a/include/nodejs/node_osrm_support.hpp b/include/nodejs/node_osrm_support.hpp index 8fb95638f..8bdcf87a5 100644 --- a/include/nodejs/node_osrm_support.hpp +++ b/include/nodejs/node_osrm_support.hpp @@ -1,1724 +1,1094 @@ -// #ifndef OSRM_BINDINGS_NODE_SUPPORT_HPP -// #define OSRM_BINDINGS_NODE_SUPPORT_HPP - -// #include "nodejs/json_v8_renderer.hpp" -// #include "engine/api/flatbuffers/fbresult_generated.h" -// #include "osrm/approach.hpp" -// #include "osrm/bearing.hpp" -// #include "osrm/coordinate.hpp" -// #include "osrm/engine_config.hpp" -// #include "osrm/json_container.hpp" -// #include "osrm/match_parameters.hpp" -// #include "osrm/nearest_parameters.hpp" -// #include "osrm/osrm.hpp" -// #include "osrm/route_parameters.hpp" -// #include "osrm/status.hpp" -// #include "osrm/storage_config.hpp" -// #include "osrm/table_parameters.hpp" -// #include "osrm/tile_parameters.hpp" -// #include "osrm/trip_parameters.hpp" -// #include "util/json_renderer.hpp" - -// #include -// #include - -// #include -// #include -// #include -// #include -// #include -// #include -// #include - -// #include -// #include -// #include - -// namespace node_osrm -// { - -// using engine_config_ptr = std::unique_ptr; -// using route_parameters_ptr = std::unique_ptr; -// using trip_parameters_ptr = std::unique_ptr; -// using tile_parameters_ptr = std::unique_ptr; -// using match_parameters_ptr = std::unique_ptr; -// using nearest_parameters_ptr = std::unique_ptr; -// using table_parameters_ptr = std::unique_ptr; - -// struct PluginParameters -// { -// bool renderToBuffer = false; -// }; - -// using ObjectOrString = typename mapbox::util::variant; - -// template inline v8::Local render(const ResultT &result); - -// template <> v8::Local inline render(const std::string &result) -// { -// return Nan::CopyBuffer(result.data(), result.size()).ToLocalChecked(); -// } - -// template <> v8::Local inline render(const ObjectOrString &result) -// { -// if (result.is()) -// { -// // Convert osrm::json object tree into matching v8 object tree -// v8::Local value; -// renderToV8(value, result.get()); -// return value; -// } -// else -// { -// // Return the string object as a node Buffer -// return Nan::CopyBuffer(result.get().data(), result.get().size()) -// .ToLocalChecked(); -// } -// } - -// inline void ParseResult(const osrm::Status &result_status, osrm::json::Object &result) -// { -// const auto code_iter = result.values.find("code"); -// const auto end_iter = result.values.end(); - -// BOOST_ASSERT(code_iter != end_iter); - -// if (result_status == osrm::Status::Error) -// { -// throw std::logic_error(code_iter->second.get().value.c_str()); -// } - -// result.values.erase(code_iter); -// const auto message_iter = result.values.find("message"); -// if (message_iter != end_iter) -// { -// result.values.erase(message_iter); -// } -// } - -// inline void ParseResult(const osrm::Status & /*result_status*/, const std::string & /*unused*/) {} -// inline void ParseResult(const osrm::Status &result_status, -// const flatbuffers::FlatBufferBuilder &fbs_builder) -// { -// auto fbs_result = osrm::engine::api::fbresult::GetFBResult(fbs_builder.GetBufferPointer()); - -// if (result_status == osrm::Status::Error) -// { -// BOOST_ASSERT(fbs_result->code()); -// throw std::logic_error(fbs_result->code()->message()->c_str()); -// } -// } - -// inline engine_config_ptr argumentsToEngineConfig(const Nan::FunctionCallbackInfo &args) -// { -// Nan::HandleScope scope; -// auto engine_config = std::make_unique(); - -// if (args.Length() == 0) -// { -// return engine_config; -// } -// else if (args.Length() > 1) -// { -// Nan::ThrowError("Only accepts one parameter"); -// return engine_config_ptr(); -// } - -// BOOST_ASSERT(args.Length() == 1); - -// if (args[0]->IsString()) -// { -// engine_config->storage_config = -// osrm::StorageConfig(*Nan::Utf8String(Nan::To(args[0]).ToLocalChecked())); -// engine_config->use_shared_memory = false; -// return engine_config; -// } -// else if (!args[0]->IsObject()) -// { -// Nan::ThrowError("Parameter must be a path or options object"); -// return engine_config_ptr(); -// } - -// BOOST_ASSERT(args[0]->IsObject()); -// auto params = Nan::To(args[0]).ToLocalChecked(); - -// auto path = Nan::Get(params, Nan::New("path").ToLocalChecked()).ToLocalChecked(); -// if (path.IsEmpty()) -// return engine_config_ptr(); - -// auto memory_file = Nan::Get(params, Nan::New("memory_file").ToLocalChecked()).ToLocalChecked(); -// if (memory_file.IsEmpty()) -// return engine_config_ptr(); - -// auto shared_memory = -// Nan::Get(params, Nan::New("shared_memory").ToLocalChecked()).ToLocalChecked(); -// if (shared_memory.IsEmpty()) -// return engine_config_ptr(); - -// auto mmap_memory = Nan::Get(params, Nan::New("mmap_memory").ToLocalChecked()).ToLocalChecked(); -// if (mmap_memory.IsEmpty()) -// return engine_config_ptr(); - -// if (!memory_file->IsUndefined()) -// { -// if (path->IsUndefined()) -// { -// Nan::ThrowError("memory_file option requires a path to a file."); -// return engine_config_ptr(); -// } - -// engine_config->memory_file = -// *Nan::Utf8String(Nan::To(memory_file).ToLocalChecked()); -// } - -// auto dataset_name = -// Nan::Get(params, Nan::New("dataset_name").ToLocalChecked()).ToLocalChecked(); -// if (dataset_name.IsEmpty()) -// return engine_config_ptr(); -// if (!dataset_name->IsUndefined()) -// { -// if (dataset_name->IsString()) -// { -// engine_config->dataset_name = -// *Nan::Utf8String(Nan::To(dataset_name).ToLocalChecked()); -// } -// else -// { -// Nan::ThrowError("dataset_name needs to be a string"); -// return engine_config_ptr(); -// } -// } - -// if (!path->IsUndefined()) -// { -// engine_config->storage_config = -// osrm::StorageConfig(*Nan::Utf8String(Nan::To(path).ToLocalChecked())); - -// engine_config->use_shared_memory = false; -// } -// if (!shared_memory->IsUndefined()) -// { -// if (shared_memory->IsBoolean()) -// { -// engine_config->use_shared_memory = Nan::To(shared_memory).FromJust(); -// } -// else -// { -// Nan::ThrowError("Shared_memory option must be a boolean"); -// return engine_config_ptr(); -// } -// } -// if (!mmap_memory->IsUndefined()) -// { -// if (mmap_memory->IsBoolean()) -// { -// engine_config->use_mmap = Nan::To(mmap_memory).FromJust(); -// } -// else -// { -// Nan::ThrowError("mmap_memory option must be a boolean"); -// return engine_config_ptr(); -// } -// } - -// if (path->IsUndefined() && !engine_config->use_shared_memory) -// { -// Nan::ThrowError("Shared_memory must be enabled if no path is " -// "specified"); -// return engine_config_ptr(); -// } - -// auto algorithm = Nan::Get(params, Nan::New("algorithm").ToLocalChecked()).ToLocalChecked(); -// if (algorithm.IsEmpty()) -// return engine_config_ptr(); - -// if (algorithm->IsString()) -// { -// auto algorithm_str = Nan::To(algorithm).ToLocalChecked(); -// if (*Nan::Utf8String(algorithm_str) == std::string("CH")) -// { -// engine_config->algorithm = osrm::EngineConfig::Algorithm::CH; -// } -// else if (*Nan::Utf8String(algorithm_str) == std::string("CoreCH")) -// { -// engine_config->algorithm = osrm::EngineConfig::Algorithm::CH; -// } -// else if (*Nan::Utf8String(algorithm_str) == std::string("MLD")) -// { -// engine_config->algorithm = osrm::EngineConfig::Algorithm::MLD; -// } -// else -// { -// Nan::ThrowError("algorithm option must be one of 'CH', 'CoreCH', or 'MLD'."); -// return engine_config_ptr(); -// } -// } -// else if (!algorithm->IsUndefined()) -// { -// Nan::ThrowError("algorithm option must be a string and one of 'CH', 'CoreCH', or 'MLD'."); -// return engine_config_ptr(); -// } - -// // Set EngineConfig system-wide limits on construction, if requested - -// auto max_locations_trip = -// Nan::Get(params, Nan::New("max_locations_trip").ToLocalChecked()).ToLocalChecked(); -// auto max_locations_viaroute = -// Nan::Get(params, Nan::New("max_locations_viaroute").ToLocalChecked()).ToLocalChecked(); -// auto max_locations_distance_table = -// Nan::Get(params, Nan::New("max_locations_distance_table").ToLocalChecked()) -// .ToLocalChecked(); -// auto max_locations_map_matching = -// Nan::Get(params, Nan::New("max_locations_map_matching").ToLocalChecked()).ToLocalChecked(); -// auto max_results_nearest = -// Nan::Get(params, Nan::New("max_results_nearest").ToLocalChecked()).ToLocalChecked(); -// auto max_alternatives = -// Nan::Get(params, Nan::New("max_alternatives").ToLocalChecked()).ToLocalChecked(); -// auto max_radius_map_matching = -// Nan::Get(params, Nan::New("max_radius_map_matching").ToLocalChecked()).ToLocalChecked(); - -// if (!max_locations_trip->IsUndefined() && !max_locations_trip->IsNumber()) -// { -// Nan::ThrowError("max_locations_trip must be an integral number"); -// return engine_config_ptr(); -// } -// if (!max_locations_viaroute->IsUndefined() && !max_locations_viaroute->IsNumber()) -// { -// Nan::ThrowError("max_locations_viaroute must be an integral number"); -// return engine_config_ptr(); -// } -// if (!max_locations_distance_table->IsUndefined() && !max_locations_distance_table->IsNumber()) -// { -// Nan::ThrowError("max_locations_distance_table must be an integral number"); -// return engine_config_ptr(); -// } -// if (!max_locations_map_matching->IsUndefined() && !max_locations_map_matching->IsNumber()) -// { -// Nan::ThrowError("max_locations_map_matching must be an integral number"); -// return engine_config_ptr(); -// } -// if (!max_results_nearest->IsUndefined() && !max_results_nearest->IsNumber()) -// { -// Nan::ThrowError("max_results_nearest must be an integral number"); -// return engine_config_ptr(); -// } -// if (!max_alternatives->IsUndefined() && !max_alternatives->IsNumber()) -// { -// Nan::ThrowError("max_alternatives must be an integral number"); -// return engine_config_ptr(); -// } - -// if (max_locations_trip->IsNumber()) -// engine_config->max_locations_trip = Nan::To(max_locations_trip).FromJust(); -// if (max_locations_viaroute->IsNumber()) -// engine_config->max_locations_viaroute = Nan::To(max_locations_viaroute).FromJust(); -// if (max_locations_distance_table->IsNumber()) -// engine_config->max_locations_distance_table = -// Nan::To(max_locations_distance_table).FromJust(); -// if (max_locations_map_matching->IsNumber()) -// engine_config->max_locations_map_matching = -// Nan::To(max_locations_map_matching).FromJust(); -// if (max_results_nearest->IsNumber()) -// engine_config->max_results_nearest = Nan::To(max_results_nearest).FromJust(); -// if (max_alternatives->IsNumber()) -// engine_config->max_alternatives = Nan::To(max_alternatives).FromJust(); -// if (max_radius_map_matching->IsNumber()) -// engine_config->max_radius_map_matching = -// Nan::To(max_radius_map_matching).FromJust(); - -// return engine_config; -// } - -// inline boost::optional> -// parseCoordinateArray(const v8::Local &coordinates_array) -// { -// Nan::HandleScope scope; -// boost::optional> resulting_coordinates; -// std::vector temp_coordinates; - -// for (uint32_t i = 0; i < coordinates_array->Length(); ++i) -// { -// v8::Local coordinate = Nan::Get(coordinates_array, i).ToLocalChecked(); -// if (coordinate.IsEmpty()) -// return resulting_coordinates; - -// if (!coordinate->IsArray()) -// { -// Nan::ThrowError("Coordinates must be an array of (lon/lat) pairs"); -// return resulting_coordinates; -// } - -// v8::Local coordinate_pair = v8::Local::Cast(coordinate); -// if (coordinate_pair->Length() != 2) -// { -// Nan::ThrowError("Coordinates must be an array of (lon/lat) pairs"); -// return resulting_coordinates; -// } - -// if (!Nan::Get(coordinate_pair, 0).ToLocalChecked()->IsNumber() || -// !Nan::Get(coordinate_pair, 1).ToLocalChecked()->IsNumber()) -// { -// Nan::ThrowError("Each member of a coordinate pair must be a number"); -// return resulting_coordinates; -// } - -// double lon = Nan::To(Nan::Get(coordinate_pair, 0).ToLocalChecked()).FromJust(); -// double lat = Nan::To(Nan::Get(coordinate_pair, 1).ToLocalChecked()).FromJust(); - -// if (std::isnan(lon) || std::isnan(lat) || std::isinf(lon) || std::isinf(lat)) -// { -// Nan::ThrowError("Lng/Lat coordinates must be valid numbers"); -// return resulting_coordinates; -// } - -// if (lon > 180 || lon < -180 || lat > 90 || lat < -90) -// { -// Nan::ThrowError("Lng/Lat coordinates must be within world bounds " -// "(-180 < lng < 180, -90 < lat < 90)"); -// return resulting_coordinates; -// } - -// temp_coordinates.emplace_back(osrm::util::FloatLongitude{std::move(lon)}, -// osrm::util::FloatLatitude{std::move(lat)}); -// } - -// resulting_coordinates = boost::make_optional(std::move(temp_coordinates)); -// return resulting_coordinates; -// } - -// // Parses all the non-service specific parameters -// template -// inline bool argumentsToParameter(const Nan::FunctionCallbackInfo &args, -// ParamType ¶ms, -// bool requires_multiple_coordinates) -// { -// Nan::HandleScope scope; - -// if (args.Length() < 2) -// { -// Nan::ThrowTypeError("Two arguments required"); -// return false; -// } - -// if (!args[0]->IsObject()) -// { -// Nan::ThrowTypeError("First arg must be an object"); -// return false; -// } - -// v8::Local obj = Nan::To(args[0]).ToLocalChecked(); - -// v8::Local coordinates = -// Nan::Get(obj, Nan::New("coordinates").ToLocalChecked()).ToLocalChecked(); -// if (coordinates.IsEmpty()) -// return false; - -// if (coordinates->IsUndefined()) -// { -// Nan::ThrowError("Must provide a coordinates property"); -// return false; -// } -// else if (coordinates->IsArray()) -// { -// auto coordinates_array = v8::Local::Cast(coordinates); -// if (coordinates_array->Length() < 2 && requires_multiple_coordinates) -// { -// Nan::ThrowError("At least two coordinates must be provided"); -// return false; -// } -// else if (!requires_multiple_coordinates && coordinates_array->Length() != 1) -// { -// Nan::ThrowError("Exactly one coordinate pair must be provided"); -// return false; -// } -// auto maybe_coordinates = parseCoordinateArray(coordinates_array); -// if (maybe_coordinates) -// { -// std::copy(maybe_coordinates->begin(), -// maybe_coordinates->end(), -// std::back_inserter(params->coordinates)); -// } -// else -// { -// return false; -// } -// } -// else if (!coordinates->IsUndefined()) -// { -// BOOST_ASSERT(!coordinates->IsArray()); -// Nan::ThrowError("Coordinates must be an array of (lon/lat) pairs"); -// return false; -// } - -// if (Nan::Has(obj, Nan::New("approaches").ToLocalChecked()).FromJust()) -// { -// v8::Local approaches = -// Nan::Get(obj, Nan::New("approaches").ToLocalChecked()).ToLocalChecked(); -// if (approaches.IsEmpty()) -// return false; - -// if (!approaches->IsArray()) -// { -// Nan::ThrowError("Approaches must be an arrays of strings"); -// return false; -// } - -// auto approaches_array = v8::Local::Cast(approaches); - -// if (approaches_array->Length() != params->coordinates.size()) -// { -// Nan::ThrowError("Approaches array must have the same length as coordinates array"); -// return false; -// } - -// for (uint32_t i = 0; i < approaches_array->Length(); ++i) -// { -// v8::Local approach_raw = Nan::Get(approaches_array, i).ToLocalChecked(); -// if (approach_raw.IsEmpty()) -// return false; - -// if (approach_raw->IsNull()) -// { -// params->approaches.emplace_back(); -// } -// else if (approach_raw->IsString()) -// { -// const Nan::Utf8String approach_utf8str(approach_raw); -// std::string approach_str{*approach_utf8str, -// *approach_utf8str + approach_utf8str.length()}; -// if (approach_str == "curb") -// { -// params->approaches.push_back(osrm::Approach::CURB); -// } -// else if (approach_str == "unrestricted") -// { -// params->approaches.push_back(osrm::Approach::UNRESTRICTED); -// } -// else -// { -// Nan::ThrowError("'approaches' param must be one of [curb, unrestricted]"); -// return false; -// } -// } -// else -// { -// Nan::ThrowError("Approach must be a string: [curb, unrestricted] or null"); -// return false; -// } -// } -// } - -// if (Nan::Has(obj, Nan::New("bearings").ToLocalChecked()).FromJust()) -// { -// v8::Local bearings = -// Nan::Get(obj, Nan::New("bearings").ToLocalChecked()).ToLocalChecked(); -// if (bearings.IsEmpty()) -// return false; - -// if (!bearings->IsArray()) -// { -// Nan::ThrowError("Bearings must be an array of arrays of numbers"); -// return false; -// } - -// auto bearings_array = v8::Local::Cast(bearings); - -// if (bearings_array->Length() != params->coordinates.size()) -// { -// Nan::ThrowError("Bearings array must have the same length as coordinates array"); -// return false; -// } - -// for (uint32_t i = 0; i < bearings_array->Length(); ++i) -// { -// v8::Local bearing_raw = Nan::Get(bearings_array, i).ToLocalChecked(); -// if (bearing_raw.IsEmpty()) -// return false; - -// if (bearing_raw->IsNull()) -// { -// params->bearings.emplace_back(); -// } -// else if (bearing_raw->IsArray()) -// { -// auto bearing_pair = v8::Local::Cast(bearing_raw); -// if (bearing_pair->Length() == 2) -// { -// if (!Nan::Get(bearing_pair, 0).ToLocalChecked()->IsNumber() || -// !Nan::Get(bearing_pair, 1).ToLocalChecked()->IsNumber()) -// { -// Nan::ThrowError("Bearing values need to be numbers in range 0..360"); -// return false; -// } - -// const auto bearing = -// Nan::To(Nan::Get(bearing_pair, 0).ToLocalChecked()).FromJust(); -// const auto range = -// Nan::To(Nan::Get(bearing_pair, 1).ToLocalChecked()).FromJust(); - -// if (bearing < 0 || bearing > 360 || range < 0 || range > 180) -// { -// Nan::ThrowError("Bearing values need to be in range 0..360, 0..180"); -// return false; -// } - -// params->bearings.push_back( -// osrm::Bearing{static_cast(bearing), static_cast(range)}); -// } -// else -// { -// Nan::ThrowError("Bearing must be an array of [bearing, range] or null"); -// return false; -// } -// } -// else -// { -// Nan::ThrowError("Bearing must be an array of [bearing, range] or null"); -// return false; -// } -// } -// } - -// if (Nan::Has(obj, Nan::New("hints").ToLocalChecked()).FromJust()) -// { -// v8::Local hints = -// Nan::Get(obj, Nan::New("hints").ToLocalChecked()).ToLocalChecked(); -// if (hints.IsEmpty()) -// return false; - -// if (!hints->IsArray()) -// { -// Nan::ThrowError("Hints must be an array of strings/null"); -// return false; -// } - -// v8::Local hints_array = v8::Local::Cast(hints); - -// if (hints_array->Length() != params->coordinates.size()) -// { -// Nan::ThrowError("Hints array must have the same length as coordinates array"); -// return false; -// } - -// for (uint32_t i = 0; i < hints_array->Length(); ++i) -// { -// v8::Local hint = Nan::Get(hints_array, i).ToLocalChecked(); -// if (hint.IsEmpty()) -// return false; - -// if (hint->IsString()) -// { -// if (Nan::To(hint).ToLocalChecked()->Length() == 0) -// { -// Nan::ThrowError("Hint cannot be an empty string"); -// return false; -// } - -// params->hints.push_back(osrm::engine::Hint::FromBase64(*Nan::Utf8String(hint))); -// } -// else if (hint->IsNull()) -// { -// params->hints.emplace_back(); -// } -// else -// { -// Nan::ThrowError("Hint must be null or string"); -// return false; -// } -// } -// } - -// if (Nan::Has(obj, Nan::New("radiuses").ToLocalChecked()).FromJust()) -// { -// v8::Local radiuses = -// Nan::Get(obj, Nan::New("radiuses").ToLocalChecked()).ToLocalChecked(); -// if (radiuses.IsEmpty()) -// return false; - -// if (!radiuses->IsArray()) -// { -// Nan::ThrowError("Radiuses must be an array of non-negative doubles or null"); -// return false; -// } - -// v8::Local radiuses_array = v8::Local::Cast(radiuses); - -// if (radiuses_array->Length() != params->coordinates.size()) -// { -// Nan::ThrowError("Radiuses array must have the same length as coordinates array"); -// return false; -// } - -// for (uint32_t i = 0; i < radiuses_array->Length(); ++i) -// { -// v8::Local radius = Nan::Get(radiuses_array, i).ToLocalChecked(); -// if (radius.IsEmpty()) -// return false; - -// if (radius->IsNull()) -// { -// params->radiuses.emplace_back(); -// } -// else if (radius->IsNumber() && Nan::To(radius).FromJust() >= 0) -// { -// params->radiuses.push_back(Nan::To(radius).FromJust()); -// } -// else -// { -// Nan::ThrowError("Radius must be non-negative double or null"); -// return false; -// } -// } -// } - -// if (Nan::Has(obj, Nan::New("generate_hints").ToLocalChecked()).FromJust()) -// { -// v8::Local generate_hints = -// Nan::Get(obj, Nan::New("generate_hints").ToLocalChecked()).ToLocalChecked(); -// if (generate_hints.IsEmpty()) -// return false; - -// if (!generate_hints->IsBoolean()) -// { -// Nan::ThrowError("generate_hints must be of type Boolean"); -// return false; -// } - -// params->generate_hints = Nan::To(generate_hints).FromJust(); -// } - -// if (Nan::Has(obj, Nan::New("skip_waypoints").ToLocalChecked()).FromJust()) -// { -// v8::Local skip_waypoints = -// Nan::Get(obj, Nan::New("skip_waypoints").ToLocalChecked()).ToLocalChecked(); -// if (skip_waypoints.IsEmpty()) -// return false; - -// if (!skip_waypoints->IsBoolean()) -// { -// Nan::ThrowError("skip_waypoints must be of type Boolean"); -// return false; -// } - -// params->skip_waypoints = Nan::To(skip_waypoints).FromJust(); -// } - -// if (Nan::Has(obj, Nan::New("exclude").ToLocalChecked()).FromJust()) -// { -// v8::Local exclude = -// Nan::Get(obj, Nan::New("exclude").ToLocalChecked()).ToLocalChecked(); -// if (exclude.IsEmpty()) -// return false; - -// if (!exclude->IsArray()) -// { -// Nan::ThrowError("Exclude must be an array of strings or empty"); -// return false; -// } - -// v8::Local exclude_array = v8::Local::Cast(exclude); - -// for (uint32_t i = 0; i < exclude_array->Length(); ++i) -// { -// v8::Local class_name = Nan::Get(exclude_array, i).ToLocalChecked(); -// if (class_name.IsEmpty()) -// return false; - -// if (class_name->IsString()) -// { -// std::string class_name_str = *Nan::Utf8String(class_name); -// params->exclude.emplace_back(class_name_str); -// } -// else -// { -// Nan::ThrowError("Exclude must be an array of strings or empty"); -// return false; -// } -// } -// } - -// if (Nan::Has(obj, Nan::New("format").ToLocalChecked()).FromJust()) -// { -// v8::Local format = -// Nan::Get(obj, Nan::New("format").ToLocalChecked()).ToLocalChecked(); -// if (format.IsEmpty()) -// { -// return false; -// } - -// if (!format->IsString()) -// { -// Nan::ThrowError("format must be a string: \"json\" or \"flatbuffers\""); -// return false; -// } - -// std::string format_str = *Nan::Utf8String(format); -// if (format_str == "json") -// { -// params->format = osrm::engine::api::BaseParameters::OutputFormatType::JSON; -// } -// else if (format_str == "flatbuffers") -// { -// params->format = osrm::engine::api::BaseParameters::OutputFormatType::FLATBUFFERS; -// } -// else -// { -// Nan::ThrowError("format must be a string: \"json\" or \"flatbuffers\""); -// return false; -// } -// } - -// if (Nan::Has(obj, Nan::New("snapping").ToLocalChecked()).FromJust()) -// { -// v8::Local snapping = -// Nan::Get(obj, Nan::New("snapping").ToLocalChecked()).ToLocalChecked(); -// if (snapping.IsEmpty()) -// return false; - -// if (!snapping->IsString()) -// { -// Nan::ThrowError("Snapping must be a string: [default, any]"); -// return false; -// } -// const Nan::Utf8String snapping_utf8str(snapping); -// std::string snapping_str{*snapping_utf8str, *snapping_utf8str + snapping_utf8str.length()}; - -// if (snapping_str == "default") -// { -// params->snapping = osrm::RouteParameters::SnappingType::Default; -// } -// else if (snapping_str == "any") -// { -// params->snapping = osrm::RouteParameters::SnappingType::Any; -// } -// else -// { -// Nan::ThrowError("'snapping' param must be one of [default, any]"); -// return false; -// } -// } - -// return true; -// } - -// template -// inline bool parseCommonParameters(const v8::Local &obj, ParamType ¶ms) -// { -// if (Nan::Has(obj, Nan::New("steps").ToLocalChecked()).FromJust()) -// { -// auto steps = Nan::Get(obj, Nan::New("steps").ToLocalChecked()).ToLocalChecked(); -// if (steps.IsEmpty()) -// return false; - -// if (steps->IsBoolean()) -// { -// params->steps = Nan::To(steps).FromJust(); -// } -// else -// { -// Nan::ThrowError("'steps' param must be a boolean"); -// return false; -// } -// } - -// if (Nan::Has(obj, Nan::New("annotations").ToLocalChecked()).FromJust()) -// { -// auto annotations = Nan::Get(obj, Nan::New("annotations").ToLocalChecked()).ToLocalChecked(); -// if (annotations.IsEmpty()) -// return false; - -// if (annotations->IsBoolean()) -// { -// params->annotations = Nan::To(annotations).FromJust(); -// params->annotations_type = params->annotations -// ? osrm::RouteParameters::AnnotationsType::All -// : osrm::RouteParameters::AnnotationsType::None; -// } -// else if (annotations->IsArray()) -// { -// v8::Local annotations_array = v8::Local::Cast(annotations); -// for (std::size_t i = 0; i < annotations_array->Length(); i++) -// { -// const Nan::Utf8String annotations_utf8str( -// Nan::Get(annotations_array, i).ToLocalChecked()); -// std::string annotations_str{*annotations_utf8str, -// *annotations_utf8str + annotations_utf8str.length()}; - -// if (annotations_str == "duration") -// { -// params->annotations_type = -// params->annotations_type | osrm::RouteParameters::AnnotationsType::Duration; -// } -// else if (annotations_str == "nodes") -// { -// params->annotations_type = -// params->annotations_type | osrm::RouteParameters::AnnotationsType::Nodes; -// } -// else if (annotations_str == "distance") -// { -// params->annotations_type = -// params->annotations_type | osrm::RouteParameters::AnnotationsType::Distance; -// } -// else if (annotations_str == "weight") -// { -// params->annotations_type = -// params->annotations_type | osrm::RouteParameters::AnnotationsType::Weight; -// } -// else if (annotations_str == "datasources") -// { -// params->annotations_type = params->annotations_type | -// osrm::RouteParameters::AnnotationsType::Datasources; -// } -// else if (annotations_str == "speed") -// { -// params->annotations_type = -// params->annotations_type | osrm::RouteParameters::AnnotationsType::Speed; -// } -// else -// { -// Nan::ThrowError("this 'annotations' param is not supported"); -// return false; -// } - -// params->annotations = -// params->annotations_type != osrm::RouteParameters::AnnotationsType::None; -// } -// } -// else -// { -// Nan::ThrowError("this 'annotations' param is not supported"); -// return false; -// } -// } - -// if (Nan::Has(obj, Nan::New("geometries").ToLocalChecked()).FromJust()) -// { -// v8::Local geometries = -// Nan::Get(obj, Nan::New("geometries").ToLocalChecked()).ToLocalChecked(); -// if (geometries.IsEmpty()) -// return false; - -// if (!geometries->IsString()) -// { -// Nan::ThrowError("Geometries must be a string: [polyline, polyline6, geojson]"); -// return false; -// } -// const Nan::Utf8String geometries_utf8str(geometries); -// std::string geometries_str{*geometries_utf8str, -// *geometries_utf8str + geometries_utf8str.length()}; - -// if (geometries_str == "polyline") -// { -// params->geometries = osrm::RouteParameters::GeometriesType::Polyline; -// } -// else if (geometries_str == "polyline6") -// { -// params->geometries = osrm::RouteParameters::GeometriesType::Polyline6; -// } -// else if (geometries_str == "geojson") -// { -// params->geometries = osrm::RouteParameters::GeometriesType::GeoJSON; -// } -// else -// { -// Nan::ThrowError("'geometries' param must be one of [polyline, polyline6, geojson]"); -// return false; -// } -// } - -// if (Nan::Has(obj, Nan::New("overview").ToLocalChecked()).FromJust()) -// { -// v8::Local overview = -// Nan::Get(obj, Nan::New("overview").ToLocalChecked()).ToLocalChecked(); -// if (overview.IsEmpty()) -// return false; - -// if (!overview->IsString()) -// { -// Nan::ThrowError("Overview must be a string: [simplified, full, false]"); -// return false; -// } - -// const Nan::Utf8String overview_utf8str(overview); -// std::string overview_str{*overview_utf8str, *overview_utf8str + overview_utf8str.length()}; - -// if (overview_str == "simplified") -// { -// params->overview = osrm::RouteParameters::OverviewType::Simplified; -// } -// else if (overview_str == "full") -// { -// params->overview = osrm::RouteParameters::OverviewType::Full; -// } -// else if (overview_str == "false") -// { -// params->overview = osrm::RouteParameters::OverviewType::False; -// } -// else -// { -// Nan::ThrowError("'overview' param must be one of [simplified, full, false]"); -// return false; -// } -// } - -// return true; -// } - -// inline PluginParameters argumentsToPluginParameters( -// const Nan::FunctionCallbackInfo &args, -// const boost::optional &output_format = {}) -// { -// if (args.Length() < 3 || !args[1]->IsObject()) -// { -// // output to buffer by default for Flatbuffers -// return {output_format == osrm::engine::api::BaseParameters::OutputFormatType::FLATBUFFERS}; -// } -// v8::Local obj = Nan::To(args[1]).ToLocalChecked(); -// if (Nan::Has(obj, Nan::New("format").ToLocalChecked()).FromJust()) -// { -// v8::Local format = -// Nan::Get(obj, Nan::New("format").ToLocalChecked()).ToLocalChecked(); -// if (format.IsEmpty()) -// { -// return {}; -// } - -// if (!format->IsString()) -// { -// Nan::ThrowError("format must be a string: \"object\" or \"buffer\""); -// return {}; -// } - -// const Nan::Utf8String format_utf8str(format); -// std::string format_str{*format_utf8str, *format_utf8str + format_utf8str.length()}; - -// if (format_str == "object") -// { -// if (output_format == osrm::engine::api::BaseParameters::OutputFormatType::FLATBUFFERS) -// { -// Nan::ThrowError("Flatbuffers result can only output to buffer."); -// return {true}; -// } -// return {false}; -// } -// else if (format_str == "buffer") -// { -// return {true}; -// } -// else if (format_str == "json_buffer") -// { -// if (output_format && -// output_format != osrm::engine::api::BaseParameters::OutputFormatType::JSON) -// { -// Nan::ThrowError("Deprecated `json_buffer` can only be used with JSON format"); -// } -// return {true}; -// } -// else -// { -// Nan::ThrowError("format must be a string: \"object\" or \"buffer\""); -// return {}; -// } -// } - -// // output to buffer by default for Flatbuffers -// return {output_format == osrm::engine::api::BaseParameters::OutputFormatType::FLATBUFFERS}; -// } - -// inline route_parameters_ptr -// argumentsToRouteParameter(const Nan::FunctionCallbackInfo &args, -// bool requires_multiple_coordinates) -// { -// route_parameters_ptr params = std::make_unique(); -// bool has_base_params = argumentsToParameter(args, params, requires_multiple_coordinates); -// if (!has_base_params) -// return route_parameters_ptr(); - -// v8::Local obj = Nan::To(args[0]).ToLocalChecked(); - -// if (Nan::Has(obj, Nan::New("continue_straight").ToLocalChecked()).FromJust()) -// { -// auto value = Nan::Get(obj, Nan::New("continue_straight").ToLocalChecked()).ToLocalChecked(); -// if (value.IsEmpty()) -// return route_parameters_ptr(); - -// if (!value->IsBoolean() && !value->IsNull()) -// { -// Nan::ThrowError("'continue_straight' param must be boolean or null"); -// return route_parameters_ptr(); -// } -// if (value->IsBoolean()) -// { -// params->continue_straight = Nan::To(value).FromJust(); -// } -// } - -// if (Nan::Has(obj, Nan::New("alternatives").ToLocalChecked()).FromJust()) -// { -// auto value = Nan::Get(obj, Nan::New("alternatives").ToLocalChecked()).ToLocalChecked(); -// if (value.IsEmpty()) -// return route_parameters_ptr(); - -// if (value->IsBoolean()) -// { -// params->alternatives = Nan::To(value).FromJust(); -// params->number_of_alternatives = Nan::To(value).FromJust() ? 1u : 0u; -// } -// else if (value->IsNumber()) -// { -// params->alternatives = Nan::To(value).FromJust(); -// params->number_of_alternatives = Nan::To(value).FromJust(); -// } -// else -// { -// Nan::ThrowError("'alternatives' param must be boolean or number"); -// return route_parameters_ptr(); -// } -// } - -// if (Nan::Has(obj, Nan::New("waypoints").ToLocalChecked()).FromJust()) -// { -// v8::Local waypoints = -// Nan::Get(obj, Nan::New("waypoints").ToLocalChecked()).ToLocalChecked(); -// if (waypoints.IsEmpty()) -// return route_parameters_ptr(); - -// // must be array -// if (!waypoints->IsArray()) -// { -// Nan::ThrowError( -// "Waypoints must be an array of integers corresponding to the input coordinates."); -// return route_parameters_ptr(); -// } - -// auto waypoints_array = v8::Local::Cast(waypoints); -// // must have at least two elements -// if (waypoints_array->Length() < 2) -// { -// Nan::ThrowError("At least two waypoints must be provided"); -// return route_parameters_ptr(); -// } -// auto coords_size = params->coordinates.size(); -// auto waypoints_array_size = waypoints_array->Length(); - -// const auto first_index = -// Nan::To(Nan::Get(waypoints_array, 0).ToLocalChecked()).FromJust(); -// const auto last_index = -// Nan::To( -// Nan::Get(waypoints_array, waypoints_array_size - 1).ToLocalChecked()) -// .FromJust(); -// if (first_index != 0 || last_index != coords_size - 1) -// { -// Nan::ThrowError("First and last waypoints values must correspond to first and last " -// "coordinate indices"); -// return route_parameters_ptr(); -// } - -// for (uint32_t i = 0; i < waypoints_array_size; ++i) -// { -// v8::Local waypoint_value = Nan::Get(waypoints_array, i).ToLocalChecked(); -// // all elements must be numbers -// if (!waypoint_value->IsNumber()) -// { -// Nan::ThrowError("Waypoint values must be an array of integers"); -// return route_parameters_ptr(); -// } -// // check that the waypoint index corresponds with an inpute coordinate -// const auto index = Nan::To(waypoint_value).FromJust(); -// if (index >= coords_size) -// { -// Nan::ThrowError("Waypoints must correspond with the index of an input coordinate"); -// return route_parameters_ptr(); -// } -// params->waypoints.emplace_back(Nan::To(waypoint_value).FromJust()); -// } - -// if (!params->waypoints.empty()) -// { -// for (std::size_t i = 0; i < params->waypoints.size() - 1; i++) -// { -// if (params->waypoints[i] >= params->waypoints[i + 1]) -// { -// Nan::ThrowError("Waypoints must be supplied in increasing order"); -// return route_parameters_ptr(); -// } -// } -// } -// } - -// bool parsedSuccessfully = parseCommonParameters(obj, params); -// if (!parsedSuccessfully) -// { -// return route_parameters_ptr(); -// } - -// return params; -// } - -// inline tile_parameters_ptr -// argumentsToTileParameters(const Nan::FunctionCallbackInfo &args, bool /*unused*/) -// { -// tile_parameters_ptr params = std::make_unique(); - -// if (args.Length() < 2) -// { -// Nan::ThrowTypeError("Coordinate object and callback required"); -// return tile_parameters_ptr(); -// } - -// if (!args[0]->IsArray()) -// { -// Nan::ThrowTypeError("Parameter must be an array [x, y, z]"); -// return tile_parameters_ptr(); -// } - -// v8::Local array = v8::Local::Cast(args[0]); - -// if (array->Length() != 3) -// { -// Nan::ThrowTypeError("Parameter must be an array [x, y, z]"); -// return tile_parameters_ptr(); -// } - -// v8::Local x = Nan::Get(array, 0).ToLocalChecked(); -// v8::Local y = Nan::Get(array, 1).ToLocalChecked(); -// v8::Local z = Nan::Get(array, 2).ToLocalChecked(); -// if (x.IsEmpty() || y.IsEmpty() || z.IsEmpty()) -// return tile_parameters_ptr(); - -// if (!x->IsUint32() && !x->IsUndefined()) -// { -// Nan::ThrowError("Tile x coordinate must be unsigned interger"); -// return tile_parameters_ptr(); -// } -// if (!y->IsUint32() && !y->IsUndefined()) -// { -// Nan::ThrowError("Tile y coordinate must be unsigned interger"); -// return tile_parameters_ptr(); -// } -// if (!z->IsUint32() && !z->IsUndefined()) -// { -// Nan::ThrowError("Tile z coordinate must be unsigned interger"); -// return tile_parameters_ptr(); -// } - -// params->x = Nan::To(x).FromJust(); -// params->y = Nan::To(y).FromJust(); -// params->z = Nan::To(z).FromJust(); - -// if (!params->IsValid()) -// { -// Nan::ThrowError("Invalid tile coordinates"); -// return tile_parameters_ptr(); -// } - -// return params; -// } - -// inline nearest_parameters_ptr -// argumentsToNearestParameter(const Nan::FunctionCallbackInfo &args, -// bool requires_multiple_coordinates) -// { -// nearest_parameters_ptr params = std::make_unique(); -// bool has_base_params = argumentsToParameter(args, params, requires_multiple_coordinates); -// if (!has_base_params) -// return nearest_parameters_ptr(); - -// v8::Local obj = Nan::To(args[0]).ToLocalChecked(); -// if (obj.IsEmpty()) -// return nearest_parameters_ptr(); - -// if (Nan::Has(obj, Nan::New("number").ToLocalChecked()).FromJust()) -// { -// v8::Local number = -// Nan::Get(obj, Nan::New("number").ToLocalChecked()).ToLocalChecked(); - -// if (!number->IsUint32()) -// { -// Nan::ThrowError("Number must be an integer greater than or equal to 1"); -// return nearest_parameters_ptr(); -// } -// else -// { -// unsigned number_value = Nan::To(number).FromJust(); - -// if (number_value < 1) -// { -// Nan::ThrowError("Number must be an integer greater than or equal to 1"); -// return nearest_parameters_ptr(); -// } - -// params->number_of_results = Nan::To(number).FromJust(); -// } -// } - -// return params; -// } - -// inline table_parameters_ptr -// argumentsToTableParameter(const Nan::FunctionCallbackInfo &args, -// bool requires_multiple_coordinates) -// { -// table_parameters_ptr params = std::make_unique(); -// bool has_base_params = argumentsToParameter(args, params, requires_multiple_coordinates); -// if (!has_base_params) -// return table_parameters_ptr(); - -// v8::Local obj = Nan::To(args[0]).ToLocalChecked(); -// if (obj.IsEmpty()) -// return table_parameters_ptr(); - -// if (Nan::Has(obj, Nan::New("sources").ToLocalChecked()).FromJust()) -// { -// v8::Local sources = -// Nan::Get(obj, Nan::New("sources").ToLocalChecked()).ToLocalChecked(); -// if (sources.IsEmpty()) -// return table_parameters_ptr(); - -// if (!sources->IsArray()) -// { -// Nan::ThrowError("Sources must be an array of indices (or undefined)"); -// return table_parameters_ptr(); -// } - -// v8::Local sources_array = v8::Local::Cast(sources); -// for (uint32_t i = 0; i < sources_array->Length(); ++i) -// { -// v8::Local source = Nan::Get(sources_array, i).ToLocalChecked(); -// if (source.IsEmpty()) -// return table_parameters_ptr(); - -// if (source->IsUint32()) -// { -// size_t source_value = Nan::To(source).FromJust(); -// if (source_value >= params->coordinates.size()) -// { -// Nan::ThrowError("Source indices must be less than the number of coordinates"); -// return table_parameters_ptr(); -// } - -// params->sources.push_back(Nan::To(source).FromJust()); -// } -// else -// { -// Nan::ThrowError("Source must be an integer"); -// return table_parameters_ptr(); -// } -// } -// } - -// if (Nan::Has(obj, Nan::New("destinations").ToLocalChecked()).FromJust()) -// { -// v8::Local destinations = -// Nan::Get(obj, Nan::New("destinations").ToLocalChecked()).ToLocalChecked(); -// if (destinations.IsEmpty()) -// return table_parameters_ptr(); - -// if (!destinations->IsArray()) -// { -// Nan::ThrowError("Destinations must be an array of indices (or undefined)"); -// return table_parameters_ptr(); -// } - -// v8::Local destinations_array = v8::Local::Cast(destinations); -// for (uint32_t i = 0; i < destinations_array->Length(); ++i) -// { -// v8::Local destination = Nan::Get(destinations_array, i).ToLocalChecked(); -// if (destination.IsEmpty()) -// return table_parameters_ptr(); - -// if (destination->IsUint32()) -// { -// size_t destination_value = Nan::To(destination).FromJust(); -// if (destination_value >= params->coordinates.size()) -// { -// Nan::ThrowError("Destination indices must be less than the number " -// "of coordinates"); -// return table_parameters_ptr(); -// } - -// params->destinations.push_back(Nan::To(destination).FromJust()); -// } -// else -// { -// Nan::ThrowError("Destination must be an integer"); -// return table_parameters_ptr(); -// } -// } -// } - -// if (Nan::Has(obj, Nan::New("annotations").ToLocalChecked()).FromJust()) -// { -// v8::Local annotations = -// Nan::Get(obj, Nan::New("annotations").ToLocalChecked()).ToLocalChecked(); -// if (annotations.IsEmpty()) -// return table_parameters_ptr(); - -// if (!annotations->IsArray()) -// { -// Nan::ThrowError( -// "Annotations must an array containing 'duration' or 'distance', or both"); -// return table_parameters_ptr(); -// } - -// params->annotations = osrm::TableParameters::AnnotationsType::None; - -// v8::Local annotations_array = v8::Local::Cast(annotations); -// for (std::size_t i = 0; i < annotations_array->Length(); ++i) -// { -// const Nan::Utf8String annotations_utf8str( -// Nan::Get(annotations_array, i).ToLocalChecked()); -// std::string annotations_str{*annotations_utf8str, -// *annotations_utf8str + annotations_utf8str.length()}; - -// if (annotations_str == "duration") -// { -// params->annotations = -// params->annotations | osrm::TableParameters::AnnotationsType::Duration; -// } -// else if (annotations_str == "distance") -// { -// params->annotations = -// params->annotations | osrm::TableParameters::AnnotationsType::Distance; -// } -// else -// { -// Nan::ThrowError("this 'annotations' param is not supported"); -// return table_parameters_ptr(); -// } -// } -// } - -// if (Nan::Has(obj, Nan::New("fallback_speed").ToLocalChecked()).FromJust()) -// { -// auto fallback_speed = -// Nan::Get(obj, Nan::New("fallback_speed").ToLocalChecked()).ToLocalChecked(); - -// if (!fallback_speed->IsNumber()) -// { -// Nan::ThrowError("fallback_speed must be a number"); -// return table_parameters_ptr(); -// } -// else if (Nan::To(fallback_speed).FromJust() <= 0) -// { -// Nan::ThrowError("fallback_speed must be > 0"); -// return table_parameters_ptr(); -// } - -// params->fallback_speed = Nan::To(fallback_speed).FromJust(); -// } - -// if (Nan::Has(obj, Nan::New("fallback_coordinate").ToLocalChecked()).FromJust()) -// { -// auto fallback_coordinate = -// Nan::Get(obj, Nan::New("fallback_coordinate").ToLocalChecked()).ToLocalChecked(); - -// if (!fallback_coordinate->IsString()) -// { -// Nan::ThrowError("fallback_coordinate must be a string: [input, snapped]"); -// return table_parameters_ptr(); -// } - -// std::string fallback_coordinate_str = *Nan::Utf8String(fallback_coordinate); - -// if (fallback_coordinate_str == "snapped") -// { -// params->fallback_coordinate_type = -// osrm::TableParameters::FallbackCoordinateType::Snapped; -// } -// else if (fallback_coordinate_str == "input") -// { -// params->fallback_coordinate_type = osrm::TableParameters::FallbackCoordinateType::Input; -// } -// else -// { -// Nan::ThrowError("'fallback_coordinate' param must be one of [input, snapped]"); -// return table_parameters_ptr(); -// } -// } - -// if (Nan::Has(obj, Nan::New("scale_factor").ToLocalChecked()).FromJust()) -// { -// auto scale_factor = -// Nan::Get(obj, Nan::New("scale_factor").ToLocalChecked()).ToLocalChecked(); - -// if (!scale_factor->IsNumber()) -// { -// Nan::ThrowError("scale_factor must be a number"); -// return table_parameters_ptr(); -// } -// else if (Nan::To(scale_factor).FromJust() <= 0) -// { -// Nan::ThrowError("scale_factor must be > 0"); -// return table_parameters_ptr(); -// } - -// params->scale_factor = Nan::To(scale_factor).FromJust(); -// } - -// return params; -// } - -// inline trip_parameters_ptr -// argumentsToTripParameter(const Nan::FunctionCallbackInfo &args, -// bool requires_multiple_coordinates) -// { -// trip_parameters_ptr params = std::make_unique(); -// bool has_base_params = argumentsToParameter(args, params, requires_multiple_coordinates); -// if (!has_base_params) -// return trip_parameters_ptr(); - -// v8::Local obj = Nan::To(args[0]).ToLocalChecked(); - -// bool parsedSuccessfully = parseCommonParameters(obj, params); -// if (!parsedSuccessfully) -// { -// return trip_parameters_ptr(); -// } - -// if (Nan::Has(obj, Nan::New("roundtrip").ToLocalChecked()).FromJust()) -// { -// auto roundtrip = Nan::Get(obj, Nan::New("roundtrip").ToLocalChecked()).ToLocalChecked(); -// if (roundtrip.IsEmpty()) -// return trip_parameters_ptr(); - -// if (roundtrip->IsBoolean()) -// { -// params->roundtrip = Nan::To(roundtrip).FromJust(); -// } -// else -// { -// Nan::ThrowError("'roundtrip' param must be a boolean"); -// return trip_parameters_ptr(); -// } -// } - -// if (Nan::Has(obj, Nan::New("source").ToLocalChecked()).FromJust()) -// { -// v8::Local source = -// Nan::Get(obj, Nan::New("source").ToLocalChecked()).ToLocalChecked(); -// if (source.IsEmpty()) -// return trip_parameters_ptr(); - -// if (!source->IsString()) -// { -// Nan::ThrowError("Source must be a string: [any, first]"); -// return trip_parameters_ptr(); -// } - -// std::string source_str = *Nan::Utf8String(source); - -// if (source_str == "first") -// { -// params->source = osrm::TripParameters::SourceType::First; -// } -// else if (source_str == "any") -// { -// params->source = osrm::TripParameters::SourceType::Any; -// } -// else -// { -// Nan::ThrowError("'source' param must be one of [any, first]"); -// return trip_parameters_ptr(); -// } -// } - -// if (Nan::Has(obj, Nan::New("destination").ToLocalChecked()).FromJust()) -// { -// v8::Local destination = -// Nan::Get(obj, Nan::New("destination").ToLocalChecked()).ToLocalChecked(); -// if (destination.IsEmpty()) -// return trip_parameters_ptr(); - -// if (!destination->IsString()) -// { -// Nan::ThrowError("Destination must be a string: [any, last]"); -// return trip_parameters_ptr(); -// } - -// std::string destination_str = *Nan::Utf8String(destination); - -// if (destination_str == "last") -// { -// params->destination = osrm::TripParameters::DestinationType::Last; -// } -// else if (destination_str == "any") -// { -// params->destination = osrm::TripParameters::DestinationType::Any; -// } -// else -// { -// Nan::ThrowError("'destination' param must be one of [any, last]"); -// return trip_parameters_ptr(); -// } -// } - -// return params; -// } - -// inline match_parameters_ptr -// argumentsToMatchParameter(const Nan::FunctionCallbackInfo &args, -// bool requires_multiple_coordinates) -// { -// match_parameters_ptr params = std::make_unique(); -// bool has_base_params = argumentsToParameter(args, params, requires_multiple_coordinates); -// if (!has_base_params) -// return match_parameters_ptr(); - -// v8::Local obj = Nan::To(args[0]).ToLocalChecked(); - -// if (Nan::Has(obj, Nan::New("timestamps").ToLocalChecked()).FromJust()) -// { -// v8::Local timestamps = -// Nan::Get(obj, Nan::New("timestamps").ToLocalChecked()).ToLocalChecked(); -// if (timestamps.IsEmpty()) -// return match_parameters_ptr(); - -// if (!timestamps->IsArray()) -// { -// Nan::ThrowError("Timestamps must be an array of integers (or undefined)"); -// return match_parameters_ptr(); -// } - -// v8::Local timestamps_array = v8::Local::Cast(timestamps); - -// if (params->coordinates.size() != timestamps_array->Length()) -// { -// Nan::ThrowError("Timestamp array must have the same size as the coordinates " -// "array"); -// return match_parameters_ptr(); -// } - -// for (uint32_t i = 0; i < timestamps_array->Length(); ++i) -// { -// v8::Local timestamp = Nan::Get(timestamps_array, i).ToLocalChecked(); -// if (timestamp.IsEmpty()) -// return match_parameters_ptr(); - -// if (!timestamp->IsNumber()) -// { -// Nan::ThrowError("Timestamps array items must be numbers"); -// return match_parameters_ptr(); -// } -// params->timestamps.emplace_back(Nan::To(timestamp).FromJust()); -// } -// } - -// if (Nan::Has(obj, Nan::New("gaps").ToLocalChecked()).FromJust()) -// { -// v8::Local gaps = -// Nan::Get(obj, Nan::New("gaps").ToLocalChecked()).ToLocalChecked(); -// if (gaps.IsEmpty()) -// return match_parameters_ptr(); - -// if (!gaps->IsString()) -// { -// Nan::ThrowError("Gaps must be a string: [split, ignore]"); -// return match_parameters_ptr(); -// } - -// const Nan::Utf8String gaps_utf8str(gaps); -// std::string gaps_str{*gaps_utf8str, *gaps_utf8str + gaps_utf8str.length()}; - -// if (gaps_str == "split") -// { -// params->gaps = osrm::MatchParameters::GapsType::Split; -// } -// else if (gaps_str == "ignore") -// { -// params->gaps = osrm::MatchParameters::GapsType::Ignore; -// } -// else -// { -// Nan::ThrowError("'gaps' param must be one of [split, ignore]"); -// return match_parameters_ptr(); -// } -// } - -// if (Nan::Has(obj, Nan::New("tidy").ToLocalChecked()).FromJust()) -// { -// v8::Local tidy = -// Nan::Get(obj, Nan::New("tidy").ToLocalChecked()).ToLocalChecked(); -// if (tidy.IsEmpty()) -// return match_parameters_ptr(); - -// if (!tidy->IsBoolean()) -// { -// Nan::ThrowError("tidy must be of type Boolean"); -// return match_parameters_ptr(); -// } - -// params->tidy = Nan::To(tidy).FromJust(); -// } - -// if (Nan::Has(obj, Nan::New("waypoints").ToLocalChecked()).FromJust()) -// { -// v8::Local waypoints = -// Nan::Get(obj, Nan::New("waypoints").ToLocalChecked()).ToLocalChecked(); -// if (waypoints.IsEmpty()) -// return match_parameters_ptr(); - -// // must be array -// if (!waypoints->IsArray()) -// { -// Nan::ThrowError( -// "Waypoints must be an array of integers corresponding to the input coordinates."); -// return match_parameters_ptr(); -// } - -// auto waypoints_array = v8::Local::Cast(waypoints); -// // must have at least two elements -// if (waypoints_array->Length() < 2) -// { -// Nan::ThrowError("At least two waypoints must be provided"); -// return match_parameters_ptr(); -// } -// auto coords_size = params->coordinates.size(); -// auto waypoints_array_size = waypoints_array->Length(); - -// const auto first_index = -// Nan::To(Nan::Get(waypoints_array, 0).ToLocalChecked()).FromJust(); -// const auto last_index = -// Nan::To( -// Nan::Get(waypoints_array, waypoints_array_size - 1).ToLocalChecked()) -// .FromJust(); -// if (first_index != 0 || last_index != coords_size - 1) -// { -// Nan::ThrowError("First and last waypoints values must correspond to first and last " -// "coordinate indices"); -// return match_parameters_ptr(); -// } - -// for (uint32_t i = 0; i < waypoints_array_size; ++i) -// { -// v8::Local waypoint_value = Nan::Get(waypoints_array, i).ToLocalChecked(); -// // all elements must be numbers -// if (!waypoint_value->IsNumber()) -// { -// Nan::ThrowError("Waypoint values must be an array of integers"); -// return match_parameters_ptr(); -// } -// // check that the waypoint index corresponds with an inpute coordinate -// const auto index = Nan::To(waypoint_value).FromJust(); -// if (index >= coords_size) -// { -// Nan::ThrowError("Waypoints must correspond with the index of an input coordinate"); -// return match_parameters_ptr(); -// } -// params->waypoints.emplace_back( -// static_cast(Nan::To(waypoint_value).FromJust())); -// } -// } - -// bool parsedSuccessfully = parseCommonParameters(obj, params); -// if (!parsedSuccessfully) -// { -// return match_parameters_ptr(); -// } - -// return params; -// } - -// } // namespace node_osrm - -// #endif +#ifndef OSRM_BINDINGS_NODE_SUPPORT_HPP +#define OSRM_BINDINGS_NODE_SUPPORT_HPP + +#include +#include "nodejs/json_v8_renderer.hpp" +#include "engine/api/flatbuffers/fbresult_generated.h" +#include "osrm/approach.hpp" +#include "osrm/bearing.hpp" +#include "osrm/coordinate.hpp" +#include "osrm/engine_config.hpp" +#include "osrm/json_container.hpp" +#include "osrm/match_parameters.hpp" +#include "osrm/nearest_parameters.hpp" +#include "osrm/osrm.hpp" +#include "osrm/route_parameters.hpp" +#include "osrm/status.hpp" +#include "osrm/storage_config.hpp" +#include "osrm/table_parameters.hpp" +#include "osrm/tile_parameters.hpp" +#include "osrm/trip_parameters.hpp" +#include "util/json_renderer.hpp" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace node_osrm +{ + +using engine_config_ptr = std::unique_ptr; +using route_parameters_ptr = std::unique_ptr; +using trip_parameters_ptr = std::unique_ptr; +using tile_parameters_ptr = std::unique_ptr; +using match_parameters_ptr = std::unique_ptr; +using nearest_parameters_ptr = std::unique_ptr; +using table_parameters_ptr = std::unique_ptr; + +struct PluginParameters +{ + bool renderToBuffer = false; +}; + +using ObjectOrString = typename mapbox::util::variant; + + +inline void ThrowError(const Napi::Env& env, const char* message) +{ + Napi::Error::New(env, message).ThrowAsJavaScriptException(); +} + + +inline void ThrowTypeError(const Napi::Env& env, const char* message) +{ + Napi::TypeError::New(env, message).ThrowAsJavaScriptException(); +} + + +inline engine_config_ptr argumentsToEngineConfig(const Napi::CallbackInfo &args) +{ + Napi::HandleScope scope(args.Env()); + auto engine_config = std::make_unique(); + + if (args.Length() == 0) + { + return engine_config; + } + else if (args.Length() > 1) + { + ThrowError(args.Env(), "Only accepts one parameter"); + return engine_config_ptr(); + } + + BOOST_ASSERT(args.Length() == 1); + + if (args[0].IsString()) + { + engine_config->storage_config = + osrm::StorageConfig(args[0].ToString().Utf8Value()); + engine_config->use_shared_memory = false; + return engine_config; + } + else if (!args[0].IsObject()) + { + ThrowError(args.Env(), "Parameter must be a path or options object"); + return engine_config_ptr(); + } + + BOOST_ASSERT(args[0].IsObject()); + auto params = args[0].As(); + + auto path = params.Get("path"); + if (path.IsEmpty()) + return engine_config_ptr(); + + auto memory_file = params.Get("memory_file"); + if (memory_file.IsEmpty()) + return engine_config_ptr(); + + auto shared_memory = + params.Get("shared_memory"); + if (shared_memory.IsEmpty()) + return engine_config_ptr(); + + auto mmap_memory = params.Get("mmap_memory"); + if (mmap_memory.IsEmpty()) + return engine_config_ptr(); + + if (!memory_file.IsUndefined()) + { + if (path.IsUndefined()) + { + ThrowError(args.Env(), "memory_file option requires a path to a file."); + return engine_config_ptr(); + } + + engine_config->memory_file = memory_file.ToString().Utf8Value(); + } + + auto dataset_name = + params.Get("dataset_name"); + if (dataset_name.IsEmpty()) + return engine_config_ptr(); + if (!dataset_name.IsUndefined()) + { + if (dataset_name.IsString()) + { + engine_config->dataset_name = dataset_name.ToString().Utf8Value(); + } + else + { + ThrowError(args.Env(), "dataset_name needs to be a string"); + return engine_config_ptr(); + } + } + + if (!path.IsUndefined()) + { + engine_config->storage_config = + osrm::StorageConfig(path.ToString().Utf8Value()); + + engine_config->use_shared_memory = false; + } + if (!shared_memory.IsUndefined()) + { + if (shared_memory.IsBoolean()) + { + engine_config->use_shared_memory = shared_memory.ToBoolean().Value(); + } + else + { + ThrowError(args.Env(), "Shared_memory option must be a boolean"); + return engine_config_ptr(); + } + } + if (!mmap_memory.IsUndefined()) + { + if (mmap_memory.IsBoolean()) + { + engine_config->use_mmap = mmap_memory.ToBoolean().Value(); + } + else + { + ThrowError(args.Env(), "mmap_memory option must be a boolean"); + return engine_config_ptr(); + } + } + + if (path.IsUndefined() && !engine_config->use_shared_memory) + { + ThrowError(args.Env(), "Shared_memory must be enabled if no path is " + "specified"); + return engine_config_ptr(); + } + + auto algorithm = params.Get("algorithm"); + if (algorithm.IsEmpty()) + return engine_config_ptr(); + + if (algorithm.IsString()) + { + auto algorithm_str = algorithm.ToString().Utf8Value(); + if (algorithm_str == "CH") + { + engine_config->algorithm = osrm::EngineConfig::Algorithm::CH; + } + else if (algorithm_str == "CoreCH") + { + engine_config->algorithm = osrm::EngineConfig::Algorithm::CH; + } + else if (algorithm_str == "MLD") + { + engine_config->algorithm = osrm::EngineConfig::Algorithm::MLD; + } + else + { + ThrowError(args.Env(), "algorithm option must be one of 'CH', 'CoreCH', or 'MLD'."); + return engine_config_ptr(); + } + } + else if (!algorithm.IsUndefined()) + { + ThrowError(args.Env(), "algorithm option must be a string and one of 'CH', 'CoreCH', or 'MLD'."); + return engine_config_ptr(); + } + + // Set EngineConfig system-wide limits on construction, if requested + + auto max_locations_trip = + params.Get("max_locations_trip"); + auto max_locations_viaroute = + params.Get("max_locations_viaroute"); + auto max_locations_distance_table = + params.Get("max_locations_distance_table"); + auto max_locations_map_matching = + params.Get("max_locations_map_matching"); + auto max_results_nearest = + params.Get("max_results_nearest"); + auto max_alternatives = + params.Get("max_alternatives"); + auto max_radius_map_matching = + params.Get("max_radius_map_matching"); + + if (!max_locations_trip.IsUndefined() && !max_locations_trip.IsNumber()) + { + ThrowError(args.Env(), "max_locations_trip must be an integral number"); + return engine_config_ptr(); + } + if (!max_locations_viaroute.IsUndefined() && !max_locations_viaroute.IsNumber()) + { + ThrowError(args.Env(), "max_locations_viaroute must be an integral number"); + return engine_config_ptr(); + } + if (!max_locations_distance_table.IsUndefined() && !max_locations_distance_table.IsNumber()) + { + ThrowError(args.Env(), "max_locations_distance_table must be an integral number"); + return engine_config_ptr(); + } + if (!max_locations_map_matching.IsUndefined() && !max_locations_map_matching.IsNumber()) + { + ThrowError(args.Env(), "max_locations_map_matching must be an integral number"); + return engine_config_ptr(); + } + if (!max_results_nearest.IsUndefined() && !max_results_nearest.IsNumber()) + { + ThrowError(args.Env(), "max_results_nearest must be an integral number"); + return engine_config_ptr(); + } + if (!max_alternatives.IsUndefined() && !max_alternatives.IsNumber()) + { + ThrowError(args.Env(), "max_alternatives must be an integral number"); + return engine_config_ptr(); + } + + if (max_locations_trip.IsNumber()) + engine_config->max_locations_trip = max_locations_trip.ToNumber().Int32Value(); + if (max_locations_viaroute.IsNumber()) + engine_config->max_locations_viaroute = max_locations_viaroute.ToNumber().Int32Value(); + if (max_locations_distance_table.IsNumber()) + engine_config->max_locations_distance_table = max_locations_distance_table.ToNumber().Int32Value(); + if (max_locations_map_matching.IsNumber()) + engine_config->max_locations_map_matching = max_locations_map_matching.ToNumber().Int32Value(); + if (max_results_nearest.IsNumber()) + engine_config->max_results_nearest = max_results_nearest.ToNumber().Int32Value(); + if (max_alternatives.IsNumber()) + engine_config->max_alternatives = max_alternatives.ToNumber().Int32Value(); + if (max_radius_map_matching.IsNumber()) + engine_config->max_radius_map_matching = max_radius_map_matching.ToNumber().DoubleValue(); + + return engine_config; +} + +inline boost::optional> +parseCoordinateArray(const Napi::Array &coordinates_array) +{ + Napi::HandleScope scope(coordinates_array.Env()); + boost::optional> resulting_coordinates; + std::vector temp_coordinates; + + for (uint32_t i = 0; i < coordinates_array.Length(); ++i) + { + Napi::Value coordinate = coordinates_array.Get(i); + if (coordinate.IsEmpty()) + return resulting_coordinates; + + if (!coordinate.IsArray()) + { + ThrowError(coordinates_array.Env(), "Coordinates must be an array of (lon/lat) pairs"); + return resulting_coordinates; + } + + Napi::Array coordinate_pair = coordinate.As(); + if (coordinate_pair.Length() != 2) + { + ThrowError(coordinates_array.Env(), "Coordinates must be an array of (lon/lat) pairs"); + return resulting_coordinates; + } + + if (!coordinate_pair.Get(static_cast(0)).IsNumber() || + !coordinate_pair.Get(static_cast(1)).IsNumber()) + { + ThrowError(coordinates_array.Env(), "Each member of a coordinate pair must be a number"); + return resulting_coordinates; + } + + double lon = coordinate_pair.Get(static_cast(0)).As().DoubleValue(); + double lat = coordinate_pair.Get(static_cast(1)).As().DoubleValue(); + + if (std::isnan(lon) || std::isnan(lat) || std::isinf(lon) || std::isinf(lat)) + { + ThrowError(coordinates_array.Env(), "Lng/Lat coordinates must be valid numbers"); + return resulting_coordinates; + } + + if (lon > 180 || lon < -180 || lat > 90 || lat < -90) + { + ThrowError(coordinates_array.Env(), "Lng/Lat coordinates must be within world bounds " + "(-180 < lng < 180, -90 < lat < 90)"); + return resulting_coordinates; + } + + temp_coordinates.emplace_back(osrm::util::FloatLongitude{std::move(lon)}, + osrm::util::FloatLatitude{std::move(lat)}); + } + + resulting_coordinates = boost::make_optional(std::move(temp_coordinates)); + return resulting_coordinates; +} + +// Parses all the non-service specific parameters +template +inline bool argumentsToParameter(const Napi::CallbackInfo &args, + ParamType ¶ms, + bool requires_multiple_coordinates) +{ + Napi::HandleScope scope(args.Env()); + + if (args.Length() < 2) + { + ThrowTypeError(args.Env(), "Two arguments required"); + return false; + } + + if (!args[0].IsObject()) + { + ThrowTypeError(args.Env(), "First arg must be an object"); + return false; + } + + Napi::Object obj = args[0].As(); + + Napi::Value coordinates = obj.Get("coordinates"); + if (coordinates.IsEmpty()) + return false; + + if (coordinates.IsUndefined()) + { + ThrowError(args.Env(), "Must provide a coordinates property"); + return false; + } + else if (coordinates.IsArray()) + { + auto coordinates_array = coordinates.As(); + if (coordinates_array.Length() < 2 && requires_multiple_coordinates) + { + ThrowError(args.Env(), "At least two coordinates must be provided"); + return false; + } + else if (!requires_multiple_coordinates && coordinates_array.Length() != 1) + { + ThrowError(args.Env(), "Exactly one coordinate pair must be provided"); + return false; + } + auto maybe_coordinates = parseCoordinateArray(coordinates_array); + if (maybe_coordinates) + { + std::copy(maybe_coordinates->begin(), + maybe_coordinates->end(), + std::back_inserter(params->coordinates)); + } + else + { + return false; + } + } + else if (!coordinates.IsUndefined()) + { + BOOST_ASSERT(!coordinates.IsArray()); + ThrowError(args.Env(), "Coordinates must be an array of (lon/lat) pairs"); + return false; + } + + if (obj.Has("approaches")) + { + Napi::Value approaches = obj.Get("approaches"); + if (approaches.IsEmpty()) + return false; + + if (!approaches.IsArray()) + { + ThrowError(args.Env(), "Approaches must be an arrays of strings"); + return false; + } + + auto approaches_array = approaches.As(); + + if (approaches_array.Length() != params->coordinates.size()) + { + ThrowError(args.Env(), "Approaches array must have the same length as coordinates array"); + return false; + } + + for (uint32_t i = 0; i < approaches_array.Length(); ++i) + { + Napi::Value approach_raw = approaches_array.Get(i); + if (approach_raw.IsEmpty()) + return false; + + if (approach_raw.IsNull()) + { + params->approaches.emplace_back(); + } + else if (approach_raw.IsString()) + { + std::string approach_str = approach_raw.ToString().Utf8Value(); + if (approach_str == "curb") + { + params->approaches.push_back(osrm::Approach::CURB); + } + else if (approach_str == "unrestricted") + { + params->approaches.push_back(osrm::Approach::UNRESTRICTED); + } + else + { + ThrowError(args.Env(), "'approaches' param must be one of [curb, unrestricted]"); + return false; + } + } + else + { + ThrowError(args.Env(), "Approach must be a string: [curb, unrestricted] or null"); + return false; + } + } + } + + if (obj.Has("bearings")) + { + Napi::Value bearings = + obj.Get("bearings"); + if (bearings.IsEmpty()) + return false; + + if (!bearings.IsArray()) + { + ThrowError(args.Env(), "Bearings must be an array of arrays of numbers"); + return false; + } + + auto bearings_array = bearings.As(); + + if (bearings_array.Length() != params->coordinates.size()) + { + ThrowError(args.Env(), "Bearings array must have the same length as coordinates array"); + return false; + } + + for (uint32_t i = 0; i < bearings_array.Length(); ++i) + { + Napi::Value bearing_raw = bearings_array.Get(i); + if (bearing_raw.IsEmpty()) + return false; + + if (bearing_raw.IsNull()) + { + params->bearings.emplace_back(); + } + else if (bearing_raw.IsArray()) + { + auto bearing_pair = bearing_raw.As(); + if (bearing_pair.Length() == 2) + { + if (!bearing_pair.Get(static_cast(0)).IsNumber() || + !bearing_pair.Get(static_cast(1)).IsNumber()) + { + ThrowError(args.Env(), "Bearing values need to be numbers in range 0..360"); + return false; + } + + const auto bearing = bearing_pair.Get(static_cast(0)).ToNumber().Int32Value(); + const auto range = bearing_pair.Get(static_cast(1)).ToNumber().Int32Value(); + + if (bearing < 0 || bearing > 360 || range < 0 || range > 180) + { + ThrowError(args.Env(), "Bearing values need to be in range 0..360, 0..180"); + return false; + } + + params->bearings.push_back( + osrm::Bearing{static_cast(bearing), static_cast(range)}); + } + else + { + ThrowError(args.Env(), "Bearing must be an array of [bearing, range] or null"); + return false; + } + } + else + { + ThrowError(args.Env(), "Bearing must be an array of [bearing, range] or null"); + return false; + } + } + } + + if (obj.Has("hints")) + { + Napi::Value hints = + obj.Get("hints"); + if (hints.IsEmpty()) + return false; + + if (!hints.IsArray()) + { + ThrowError(args.Env(), "Hints must be an array of strings/null"); + return false; + } + + Napi::Array hints_array = hints.As(); + + if (hints_array.Length() != params->coordinates.size()) + { + ThrowError(args.Env(), "Hints array must have the same length as coordinates array"); + return false; + } + + for (uint32_t i = 0; i < hints_array.Length(); ++i) + { + Napi::Value hint = hints_array.Get(i); + if (hint.IsEmpty()) + return false; + + if (hint.IsString()) + { + if (hint.ToString().Utf8Value().length() == 0) + { + ThrowError(args.Env(), "Hint cannot be an empty string"); + return false; + } + + params->hints.emplace_back(osrm::engine::Hint::FromBase64(hint.ToString().Utf8Value())); + } + else if (hint.IsNull()) + { + params->hints.emplace_back(); + } + else + { + ThrowError(args.Env(), "Hint must be null or string"); + return false; + } + } + } + + if (obj.Has("radiuses")) + { + Napi::Value radiuses = + obj.Get("radiuses"); + if (radiuses.IsEmpty()) + return false; + + if (!radiuses.IsArray()) + { + ThrowError(args.Env(), "Radiuses must be an array of non-negative doubles or null"); + return false; + } + + Napi::Array radiuses_array = radiuses.As(); + + if (radiuses_array.Length() != params->coordinates.size()) + { + ThrowError(args.Env(), "Radiuses array must have the same length as coordinates array"); + return false; + } + + for (uint32_t i = 0; i < radiuses_array.Length(); ++i) + { + Napi::Value radius = radiuses_array.Get(i); + if (radius.IsEmpty()) + return false; + + if (radius.IsNull()) + { + params->radiuses.emplace_back(); + } + else if (radius.IsNumber() && radius.ToNumber().DoubleValue() >= 0) + { + params->radiuses.push_back(radius.ToNumber().DoubleValue()); + } + else + { + ThrowError(args.Env(), "Radius must be non-negative double or null"); + return false; + } + } + } + + if (obj.Has("generate_hints")) + { + Napi::Value generate_hints = + obj.Get("generate_hints"); + if (generate_hints.IsEmpty()) + return false; + + if (!generate_hints.IsBoolean()) + { + ThrowError(args.Env(), "generate_hints must be of type Boolean"); + return false; + } + + params->generate_hints = generate_hints.ToBoolean().Value(); + } + + if (obj.Has("skip_waypoints")) + { + Napi::Value skip_waypoints = + obj.Get("skip_waypoints"); + if (skip_waypoints.IsEmpty()) + return false; + + if (!skip_waypoints.IsBoolean()) + { + ThrowError(args.Env(), "skip_waypoints must be of type Boolean"); + return false; + } + + params->skip_waypoints = skip_waypoints.ToBoolean().Value(); + } + + if (obj.Has("exclude")) + { + Napi::Value exclude = + obj.Get("exclude"); + if (exclude.IsEmpty()) + return false; + + if (!exclude.IsArray()) + { + ThrowError(args.Env(), "Exclude must be an array of strings or empty"); + return false; + } + + Napi::Array exclude_array = exclude.As(); + + for (uint32_t i = 0; i < exclude_array.Length(); ++i) + { + Napi::Value class_name = exclude_array.Get(i); + if (class_name.IsEmpty()) + return false; + + if (class_name.IsString()) + { + std::string class_name_str = class_name.ToString().Utf8Value(); + params->exclude.emplace_back(std::move(class_name_str)); + } + else + { + ThrowError(args.Env(), "Exclude must be an array of strings or empty"); + return false; + } + } + } + + if (obj.Has("format")) + { + Napi::Value format = + obj.Get("format"); + if (format.IsEmpty()) + { + return false; + } + + if (!format.IsString()) + { + ThrowError(args.Env(), "format must be a string: \"json\" or \"flatbuffers\""); + return false; + } + + std::string format_str = format.ToString().Utf8Value(); + if (format_str == "json") + { + params->format = osrm::engine::api::BaseParameters::OutputFormatType::JSON; + } + else if (format_str == "flatbuffers") + { + params->format = osrm::engine::api::BaseParameters::OutputFormatType::FLATBUFFERS; + } + else + { + ThrowError(args.Env(), "format must be a string: \"json\" or \"flatbuffers\""); + return false; + } + } + + if (obj.Has("snapping")) + { + Napi::Value snapping = obj.Get("snapping"); + if (snapping.IsEmpty()) + return false; + + if (!snapping.IsString()) + { + ThrowError(args.Env(), "Snapping must be a string: [default, any]"); + return false; + } + + std::string snapping_str = snapping.ToString().Utf8Value(); + + if (snapping_str == "default") + { + params->snapping = osrm::RouteParameters::SnappingType::Default; + } + else if (snapping_str == "any") + { + params->snapping = osrm::RouteParameters::SnappingType::Any; + } + else + { + ThrowError(args.Env(), "'snapping' param must be one of [default, any]"); + return false; + } + } + + return true; +} + +template +inline bool parseCommonParameters(const Napi::Object &obj, ParamType ¶ms) +{ + if (obj.Has("steps")) + { + auto steps = obj.Get("steps"); + if (steps.IsEmpty()) + return false; + + if (steps.IsBoolean()) + { + params->steps = steps.ToBoolean().Value(); + } + else + { + ThrowError(obj.Env(), "'steps' param must be a boolean"); + return false; + } + } + + if (obj.Has("annotations")) + { + auto annotations = obj.Get("annotations"); + if (annotations.IsEmpty()) + return false; + + if (annotations.IsBoolean()) + { + params->annotations = annotations.ToBoolean().Value(); + params->annotations_type = params->annotations + ? osrm::RouteParameters::AnnotationsType::All + : osrm::RouteParameters::AnnotationsType::None; + } + else if (annotations.IsArray()) + { + Napi::Array annotations_array = annotations.As(); + for (std::size_t i = 0; i < annotations_array.Length(); i++) + { + std::string annotations_str = annotations_array.Get(i).ToString().Utf8Value(); + + if (annotations_str == "duration") + { + params->annotations_type = + params->annotations_type | osrm::RouteParameters::AnnotationsType::Duration; + } + else if (annotations_str == "nodes") + { + params->annotations_type = + params->annotations_type | osrm::RouteParameters::AnnotationsType::Nodes; + } + else if (annotations_str == "distance") + { + params->annotations_type = + params->annotations_type | osrm::RouteParameters::AnnotationsType::Distance; + } + else if (annotations_str == "weight") + { + params->annotations_type = + params->annotations_type | osrm::RouteParameters::AnnotationsType::Weight; + } + else if (annotations_str == "datasources") + { + params->annotations_type = params->annotations_type | + osrm::RouteParameters::AnnotationsType::Datasources; + } + else if (annotations_str == "speed") + { + params->annotations_type = + params->annotations_type | osrm::RouteParameters::AnnotationsType::Speed; + } + else + { + ThrowError(obj.Env(), "this 'annotations' param is not supported"); + return false; + } + + params->annotations = + params->annotations_type != osrm::RouteParameters::AnnotationsType::None; + } + } + else + { + ThrowError(obj.Env(), "this 'annotations' param is not supported"); + return false; + } + } + + if (obj.Has("geometries")) + { + Napi::Value geometries = + obj.Get("geometries"); + if (geometries.IsEmpty()) + return false; + + if (!geometries.IsString()) + { + ThrowError(obj.Env(), "Geometries must be a string: [polyline, polyline6, geojson]"); + return false; + } + std::string geometries_str = geometries.ToString().Utf8Value(); + + if (geometries_str == "polyline") + { + params->geometries = osrm::RouteParameters::GeometriesType::Polyline; + } + else if (geometries_str == "polyline6") + { + params->geometries = osrm::RouteParameters::GeometriesType::Polyline6; + } + else if (geometries_str == "geojson") + { + params->geometries = osrm::RouteParameters::GeometriesType::GeoJSON; + } + else + { + ThrowError(obj.Env(), "'geometries' param must be one of [polyline, polyline6, geojson]"); + return false; + } + } + + if (obj.Has("overview")) + { + Napi::Value overview = + obj.Get("overview"); + if (overview.IsEmpty()) + return false; + + if (!overview.IsString()) + { + ThrowError(obj.Env(), "Overview must be a string: [simplified, full, false]"); + return false; + } + + std::string overview_str = overview.ToString().Utf8Value(); + + if (overview_str == "simplified") + { + params->overview = osrm::RouteParameters::OverviewType::Simplified; + } + else if (overview_str == "full") + { + params->overview = osrm::RouteParameters::OverviewType::Full; + } + else if (overview_str == "false") + { + params->overview = osrm::RouteParameters::OverviewType::False; + } + else + { + ThrowError(obj.Env(), "'overview' param must be one of [simplified, full, false]"); + return false; + } + } + + return true; +} + + +inline PluginParameters argumentsToPluginParameters( + const Napi::CallbackInfo &args, + const boost::optional &output_format = {}) +{ + if (args.Length() < 3 || !args[1].IsObject()) + { + // output to buffer by default for Flatbuffers + return {output_format == osrm::engine::api::BaseParameters::OutputFormatType::FLATBUFFERS}; + } + Napi::Object obj = args[1].As(); + if (obj.Has("format")) + { + Napi::Value format = + obj.Get("format"); + if (format.IsEmpty()) + { + return {}; + } + + if (!format.IsString()) + { + ThrowError(args.Env(), "format must be a string: \"object\" or \"buffer\""); + return {}; + } + + std::string format_str = format.ToString().Utf8Value(); + + if (format_str == "object") + { + if (output_format == osrm::engine::api::BaseParameters::OutputFormatType::FLATBUFFERS) + { + ThrowError(args.Env(), "Flatbuffers result can only output to buffer."); + return {true}; + } + return {false}; + } + else if (format_str == "buffer") + { + return {true}; + } + else if (format_str == "json_buffer") + { + if (output_format && + output_format != osrm::engine::api::BaseParameters::OutputFormatType::JSON) + { + ThrowError(args.Env(), "Deprecated `json_buffer` can only be used with JSON format"); + } + return {true}; + } + else + { + ThrowError(args.Env(), "format must be a string: \"object\" or \"buffer\""); + return {}; + } + } + + // output to buffer by default for Flatbuffers + return {output_format == osrm::engine::api::BaseParameters::OutputFormatType::FLATBUFFERS}; +} + +inline route_parameters_ptr +argumentsToRouteParameter(const Napi::CallbackInfo &args, + bool requires_multiple_coordinates) +{ + route_parameters_ptr params = std::make_unique(); + bool has_base_params = argumentsToParameter(args, params, requires_multiple_coordinates); + if (!has_base_params) + return route_parameters_ptr(); + + Napi::Object obj = args[0].As(); + + if (obj.Has("continue_straight")) + { + auto value = obj.Get("continue_straight"); + if (value.IsEmpty()) + return route_parameters_ptr(); + + if (!value.IsBoolean() && !value.IsNull()) + { + ThrowError(args.Env(), "'continue_straight' param must be boolean or null"); + return route_parameters_ptr(); + } + if (value.IsBoolean()) + { + params->continue_straight = value.ToBoolean().Value(); + } + } + + if (obj.Has("alternatives")) + { + auto value = obj.Get("alternatives"); + if (value.IsEmpty()) + return route_parameters_ptr(); + + if (value.IsBoolean()) + { + params->alternatives = value.ToBoolean().Value(); + params->number_of_alternatives = value.ToBoolean().Value() ? 1u : 0u; + } + else if (value.IsNumber()) + { + params->alternatives = value.ToBoolean().Value(); + params->number_of_alternatives = value.ToNumber().Int32Value(); + } + else + { + ThrowError(args.Env(), "'alternatives' param must be boolean or number"); + return route_parameters_ptr(); + } + } + + if (obj.Has("waypoints")) + { + Napi::Value waypoints = + obj.Get("waypoints"); + if (waypoints.IsEmpty()) + return route_parameters_ptr(); + + // must be array + if (!waypoints.IsArray()) + { + ThrowError(args.Env(), + "Waypoints must be an array of integers corresponding to the input coordinates."); + return route_parameters_ptr(); + } + + auto waypoints_array = waypoints.As(); + // must have at least two elements + if (waypoints_array.Length() < 2) + { + ThrowError(args.Env(), "At least two waypoints must be provided"); + return route_parameters_ptr(); + } + auto coords_size = params->coordinates.size(); + auto waypoints_array_size = waypoints_array.Length(); + + const auto first_index = waypoints_array.Get(static_cast(0)).ToNumber().Uint32Value(); + const auto last_index = waypoints_array.Get(waypoints_array_size - 1).ToNumber().Uint32Value(); + if (first_index != 0 || last_index != coords_size - 1) + { + ThrowError(args.Env(), "First and last waypoints values must correspond to first and last " + "coordinate indices"); + return route_parameters_ptr(); + } + + for (uint32_t i = 0; i < waypoints_array_size; ++i) + { + Napi::Value waypoint_value = waypoints_array.Get(i); + // all elements must be numbers + if (!waypoint_value.IsNumber()) + { + ThrowError(args.Env(), "Waypoint values must be an array of integers"); + return route_parameters_ptr(); + } + // check that the waypoint index corresponds with an inpute coordinate + const auto index = waypoint_value.ToNumber().Uint32Value(); + if (index >= coords_size) + { + ThrowError(args.Env(), "Waypoints must correspond with the index of an input coordinate"); + return route_parameters_ptr(); + } + params->waypoints.emplace_back(index); + } + + if (!params->waypoints.empty()) + { + for (std::size_t i = 0; i < params->waypoints.size() - 1; i++) + { + if (params->waypoints[i] >= params->waypoints[i + 1]) + { + ThrowError(args.Env(), "Waypoints must be supplied in increasing order"); + return route_parameters_ptr(); + } + } + } + } + + bool parsedSuccessfully = parseCommonParameters(obj, params); + if (!parsedSuccessfully) + { + return route_parameters_ptr(); + } + + return params; +} + +} // namespace node_osrm + +#endif diff --git a/src/nodejs/node_osrm.cpp b/src/nodejs/node_osrm.cpp index 1dfc4e639..af255f4ed 100644 --- a/src/nodejs/node_osrm.cpp +++ b/src/nodejs/node_osrm.cpp @@ -1,4 +1,25 @@ + + +#include "osrm/engine_config.hpp" +#include "osrm/osrm.hpp" + +#include "osrm/match_parameters.hpp" +#include "osrm/nearest_parameters.hpp" +#include "osrm/route_parameters.hpp" +#include "osrm/table_parameters.hpp" +#include "osrm/tile_parameters.hpp" +#include "osrm/trip_parameters.hpp" + +#include +#include +#include +#include +#include + #include "nodejs/node_osrm.hpp" +#include "nodejs/node_osrm_support.hpp" + +#include "util/json_renderer.hpp" namespace node_osrm { Napi::Object Engine::Init(Napi::Env env, Napi::Object exports) { @@ -17,21 +38,23 @@ Napi::Object Engine::Init(Napi::Env env, Napi::Object exports) { Engine::Engine(const Napi::CallbackInfo& info) : Napi::ObjectWrap(info) { - //Napi::Env env = info.Env(); -// int length = info.Length(); + try + { + auto config = argumentsToEngineConfig(info); + if (!config) + return; -// if (length <= 0 || !info[0].IsNumber()) { -// Napi::TypeError::New(env, "Number expected").ThrowAsJavaScriptException(); -// return; -// } - -// Napi::Number value = info[0].As(); -// this->value_ = value.DoubleValue(); + this_ = std::make_shared(std::move(*config)); + } + catch (const std::exception &ex) + { + return ThrowTypeError(info.Env(), ex.what()); + } } template -inline void async(const Nan::FunctionCallbackInfo &info, +inline void async(const Napi::CallbackInfo& info, ParameterParser argsToParams, ServiceMemFn service, bool requires_multiple_coordinates) @@ -43,20 +66,20 @@ inline void async(const Nan::FunctionCallbackInfo &info, BOOST_ASSERT(params->IsValid()); - if (!info[info.Length() - 1]->IsFunction()) - return Nan::ThrowTypeError("last argument must be a callback function"); + if (!info[info.Length() - 1].IsFunction()) + return ThrowTypeError(info.Env(), "last argument must be a callback function"); - auto *const self = Nan::ObjectWrap::Unwrap(info.Holder()); + auto *const self = Napi::ObjectWrap::Unwrap(info.Holder()); using ParamPtr = decltype(params); - struct Worker final : Nan::AsyncWorker + struct Worker final : Napi::AsyncWorker { Worker(std::shared_ptr osrm_, ParamPtr params_, ServiceMemFn service, - Nan::Callback *callback, + Napi::Function callback, PluginParameters pluginParams_) - : Nan::AsyncWorker(callback, "osrm:async"), osrm{std::move(osrm_)}, + : Napi::AsyncWorker(callback), osrm{std::move(osrm_)}, service{std::move(service)}, params{std::move(params_)}, pluginParams{ std::move(pluginParams_)} { @@ -104,17 +127,14 @@ inline void async(const Nan::FunctionCallbackInfo &info, } catch (const std::exception &e) { - SetErrorMessage(e.what()); + SetError(e.what()); } - void HandleOKCallback() override + void OnOK() override { - Nan::HandleScope scope; + Napi::HandleScope scope(Napi::Env()); - const constexpr auto argc = 2u; - v8::Local argv[argc] = {Nan::Null(), render(result)}; - - callback->Call(argc, argv, async_resource); + Callback().Call({Env().Null(), render(result)}); } // Keeps the OSRM object alive even after shutdown until we're done with callback @@ -126,16 +146,17 @@ inline void async(const Nan::FunctionCallbackInfo &info, ObjectOrString result; }; - auto *callback = new Nan::Callback{info[info.Length() - 1].As()}; - Nan::AsyncQueueWorker( - new Worker{self->this_, std::move(params), service, callback, std::move(pluginParams)}); + Napi::Function callback = info[info.Length() - 1].As(); + auto worker = new Worker(self->this_, std::move(params), service, callback, std::move(pluginParams)); + worker->Queue(); } Napi::Value Engine::route(const Napi::CallbackInfo& info) { - Napi::Env env = info.Env(); - Napi::HandleScope scope(env); - - return Napi::Number::New(env, 0); + osrm::Status (osrm::OSRM::*route_fn)(const osrm::RouteParameters ¶ms, + osrm::engine::api::ResultT &result) const = + &osrm::OSRM::Route; + async(info, &argumentsToRouteParameter, route_fn, true); + return info.Env().Undefined(); } } // namespace node_osrm @@ -144,618 +165,5 @@ Napi::Object InitAll(Napi::Env env, Napi::Object exports) { return node_osrm::Engine::Init(env, exports); } -NODE_API_MODULE(addon, InitAll) +NODE_API_MODULE(addon, InitAll); -// #include "osrm/engine_config.hpp" -// #include "osrm/osrm.hpp" - -// #include "osrm/match_parameters.hpp" -// #include "osrm/nearest_parameters.hpp" -// #include "osrm/route_parameters.hpp" -// #include "osrm/table_parameters.hpp" -// #include "osrm/tile_parameters.hpp" -// #include "osrm/trip_parameters.hpp" - -// #include -// #include -// #include -// #include -// #include - -// #include "nodejs/node_osrm.hpp" -// #include "nodejs/node_osrm_support.hpp" - -// #include "util/json_renderer.hpp" - -// namespace node_osrm -// { - -// Engine::Engine(osrm::EngineConfig &config) : Base(), this_(std::make_shared(config)) {} - -// Nan::Persistent &Engine::constructor() -// { -// static Nan::Persistent init; -// return init; -// } - -// NAN_MODULE_INIT(Engine::Init) -// { -// const auto whoami = Nan::New("OSRM").ToLocalChecked(); - -// auto fnTp = Nan::New(New); -// fnTp->InstanceTemplate()->SetInternalFieldCount(1); -// fnTp->SetClassName(whoami); - -// SetPrototypeMethod(fnTp, "route", route); -// SetPrototypeMethod(fnTp, "nearest", nearest); -// SetPrototypeMethod(fnTp, "table", table); -// SetPrototypeMethod(fnTp, "tile", tile); -// SetPrototypeMethod(fnTp, "match", match); -// SetPrototypeMethod(fnTp, "trip", trip); - -// const auto fn = Nan::GetFunction(fnTp).ToLocalChecked(); - -// constructor().Reset(fn); - -// Nan::Set(target, whoami, fn); -// } - -// // clang-format off -// /** -// * The `OSRM` method is the main constructor for creating an OSRM instance. -// * An OSRM instance requires a `.osrm.*` dataset(`.osrm.*` because it contains several files), which is prepared by the OSRM toolchain. -// * You can create such a `.osrm.*` dataset by running the OSRM binaries we ship in `node_modules/osrm/lib/binding/` and default -// * profiles (e.g. for setting speeds and determining road types to route on) in `node_modules/osrm/profiles/`: -// * -// * node_modules/osrm/lib/binding/osrm-extract data.osm.pbf -p node_modules/osrm/profiles/car.lua -// * node_modules/osrm/lib/binding/osrm-contract data.osrm -// * -// * Consult the [osrm-backend](https://github.com/Project-OSRM/osrm-backend) documentation for further details. -// * -// * Once you have a complete `network.osrm.*` dataset, you can calculate routes in javascript with this object. -// * -// * ```javascript -// * var osrm = new OSRM('network.osrm'); -// * ``` -// * -// * @param {Object|String} [options={shared_memory: true}] Options for creating an OSRM object or string to the `.osrm` file. -// * @param {String} [options.algorithm] The algorithm to use for routing. Can be 'CH', 'CoreCH' or 'MLD'. Default is 'CH'. -// * Make sure you prepared the dataset with the correct toolchain. -// * @param {Boolean} [options.shared_memory] Connects to the persistent shared memory datastore. -// * This requires you to run `osrm-datastore` prior to creating an `OSRM` object. -// * @param {String} [options.dataset_name] Connects to the persistent shared memory datastore defined by `--dataset_name` option when running `osrm-datastore`. -// * This requires you to run `osrm-datastore --dataset_name` prior to creating an `OSRM` object. -// * @param {String} [options.memory_file] **DEPRECATED** -// * Old behaviour: Path to a file on disk to store the memory using mmap. Current behaviour: setting this value is the same as setting `mmap_memory: true`. -// * @param {Boolean} [options.mmap_memory] Map on-disk files to virtual memory addresses (mmap), rather than loading into RAM. -// * @param {String} [options.path] The path to the `.osrm` files. This is mutually exclusive with setting {options.shared_memory} to true. -// * @param {Number} [options.max_locations_trip] Max. locations supported in trip query (default: unlimited). -// * @param {Number} [options.max_locations_viaroute] Max. locations supported in viaroute query (default: unlimited). -// * @param {Number} [options.max_locations_distance_table] Max. locations supported in distance table query (default: unlimited). -// * @param {Number} [options.max_locations_map_matching] Max. locations supported in map-matching query (default: unlimited). -// * @param {Number} [options.max_radius_map_matching] Max. radius size supported in map matching query (default: 5). -// * @param {Number} [options.max_results_nearest] Max. results supported in nearest query (default: unlimited). -// * @param {Number} [options.max_alternatives] Max. number of alternatives supported in alternative routes query (default: 3). -// * -// * @class OSRM -// * -// */ -// // clang-format on -// NAN_METHOD(Engine::New) -// { -// if (info.IsConstructCall()) -// { -// try -// { -// auto config = argumentsToEngineConfig(info); -// if (!config) -// return; - -// auto *const self = new Engine(*config); -// self->Wrap(info.This()); -// } -// catch (const std::exception &ex) -// { -// return Nan::ThrowTypeError(ex.what()); -// } - -// info.GetReturnValue().Set(info.This()); -// } -// else -// { -// return Nan::ThrowTypeError( -// "Cannot call constructor as function, you need to use 'new' keyword"); -// } -// } - - - -// template -// inline void asyncForTiles(const Nan::FunctionCallbackInfo &info, -// ParameterParser argsToParams, -// ServiceMemFn service, -// bool requires_multiple_coordinates) -// { -// auto params = argsToParams(info, requires_multiple_coordinates); -// if (!params) -// return; - -// auto pluginParams = argumentsToPluginParameters(info); - -// BOOST_ASSERT(params->IsValid()); - -// if (!info[info.Length() - 1]->IsFunction()) -// return Nan::ThrowTypeError("last argument must be a callback function"); - -// auto *const self = Nan::ObjectWrap::Unwrap(info.Holder()); -// using ParamPtr = decltype(params); - -// struct Worker final : Nan::AsyncWorker -// { -// Worker(std::shared_ptr osrm_, -// ParamPtr params_, -// ServiceMemFn service, -// Nan::Callback *callback, -// PluginParameters pluginParams_) -// : Nan::AsyncWorker(callback, "osrm:asyncForTiles"), osrm{std::move(osrm_)}, -// service{std::move(service)}, params{std::move(params_)}, pluginParams{ -// std::move(pluginParams_)} -// { -// } - -// void Execute() override -// try -// { -// result = std::string(); -// const auto status = ((*osrm).*(service))(*params, result); -// auto str_result = result.get(); -// ParseResult(status, str_result); -// } -// catch (const std::exception &e) -// { -// SetErrorMessage(e.what()); -// } - -// void HandleOKCallback() override -// { -// Nan::HandleScope scope; - -// const constexpr auto argc = 2u; -// auto str_result = result.get(); -// v8::Local argv[argc] = {Nan::Null(), render(str_result)}; - -// callback->Call(argc, argv, async_resource); -// } - -// // Keeps the OSRM object alive even after shutdown until we're done with callback -// std::shared_ptr osrm; -// ServiceMemFn service; -// const ParamPtr params; -// const PluginParameters pluginParams; - -// osrm::engine::api::ResultT result; -// }; - -// auto *callback = new Nan::Callback{info[info.Length() - 1].As()}; -// Nan::AsyncQueueWorker( -// new Worker{self->this_, std::move(params), service, callback, std::move(pluginParams)}); -// } - -// // clang-format off -// /** -// * Returns the fastest route between two or more coordinates while visiting the waypoints in order. -// * -// * @name route -// * @memberof OSRM -// * @param {Object} options Object literal containing parameters for the route query. -// * @param {Array} [options.coordinates] The coordinates this request will use, coordinates as `[{lon},{lat}]` values, in decimal degrees. -// * @param {Array} [options.bearings] Limits the search to segments with given bearing in degrees towards true north in clockwise direction. -// * Can be `null` or an array of `[{value},{range}]` with `integer 0 .. 360,integer 0 .. 180`. -// * @param {Array} [options.radiuses] Limits the coordinate snapping to streets in the given radius in meters. Can be `null` (unlimited, default) or `double >= 0`. -// * @param {Array} [options.hints] Hints for the coordinate snapping. Array of base64 encoded strings. -// * @param {Array} [options.exclude] List of classes to avoid, order does not matter. -// * @param {Boolean} [options.generate_hints=true] Whether or not adds a Hint to the response which can be used in subsequent requests. -// * @param {Boolean} [options.alternatives=false] Search for alternative routes. -// * @param {Number} [options.alternatives=0] Search for up to this many alternative routes. -// * *Please note that even if alternative routes are requested, a result cannot be guaranteed.* -// * @param {Boolean} [options.steps=false] Return route steps for each route leg. -// * @param {Array|Boolean} [options.annotations=false] An array with strings of `duration`, `nodes`, `distance`, `weight`, `datasources`, `speed` or boolean for enabling/disabling all. -// * @param {String} [options.geometries=polyline] Returned route geometry format (influences overview and per step). Can also be `geojson`. -// * @param {String} [options.overview=simplified] Add overview geometry either `full`, `simplified` according to highest zoom level it could be display on, or not at all (`false`). -// * @param {Boolean} [options.continue_straight] Forces the route to keep going straight at waypoints and don't do a uturn even if it would be faster. Default value depends on the profile. -// * @param {Array} [options.approaches] Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`. -// * `null`/`true`/`false` -// * @param {Array} [options.waypoints] Indices to coordinates to treat as waypoints. If not supplied, all coordinates are waypoints. Must include first and last coordinate index. -// * @param {String} [options.format] Which output format to use, either `json`, or [`flatbuffers`](https://github.com/Project-OSRM/osrm-backend/tree/master/include/engine/api/flatbuffers). -// * @param {String} [options.snapping] Which edges can be snapped to, either `default`, or `any`. `default` only snaps to edges marked by the profile as `is_startpoint`, `any` will allow snapping to any edge in the routing graph. -// * @param {Boolean} [options.skip_waypoints=false] Removes waypoints from the response. Waypoints are still calculated, but not serialized. Could be useful in case you are interested in some other part of response and do not want to transfer waste data. -// * @param {Function} callback -// * -// * @returns {Object} An array of [Waypoint](#waypoint) objects representing all waypoints in order AND an array of [`Route`](#route) objects ordered by descending recommendation rank. -// * -// * @example -// * var osrm = new OSRM("berlin-latest.osrm"); -// * osrm.route({coordinates: [[52.519930,13.438640], [52.513191,13.415852]]}, function(err, result) { -// * if(err) throw err; -// * console.log(result.waypoints); // array of Waypoint objects representing all waypoints in order -// * console.log(result.routes); // array of Route objects ordered by descending recommendation rank -// * }); -// */ -// // clang-format on -// NAN_METHOD(Engine::route) // -// { -// osrm::Status (osrm::OSRM::*route_fn)(const osrm::RouteParameters ¶ms, -// osrm::engine::api::ResultT &result) const = -// &osrm::OSRM::Route; -// async(info, &argumentsToRouteParameter, route_fn, true); -// } - -// // clang-format off -// /** -// * Snaps a coordinate to the street network and returns the nearest n matches. -// * -// * Note: `coordinates` in the general options only supports a single `{longitude},{latitude}` entry. -// * -// * @name nearest -// * @memberof OSRM -// * @param {Object} options - Object literal containing parameters for the nearest query. -// * @param {Array} [options.coordinates] The coordinates this request will use, coordinates as `[{lon},{lat}]` values, in decimal degrees. -// * @param {Array} [options.bearings] Limits the search to segments with given bearing in degrees towards true north in clockwise direction. -// * Can be `null` or an array of `[{value},{range}]` with `integer 0 .. 360,integer 0 .. 180`. -// * @param {Array} [options.radiuses] Limits the coordinate snapping to streets in the given radius in meters. Can be `null` (unlimited, default) or `double >= 0`. -// * @param {Array} [options.hints] Hints for the coordinate snapping. Array of base64 encoded strings. -// * @param {Boolean} [options.generate_hints=true] Whether or not adds a Hint to the response which can be used in subsequent requests. -// * @param {Number} [options.number=1] Number of nearest segments that should be returned. -// * Must be an integer greater than or equal to `1`. -// * @param {Array} [options.approaches] Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`. -// * @param {String} [options.format] Which output format to use, either `json`, or [`flatbuffers`](https://github.com/Project-OSRM/osrm-backend/tree/master/include/engine/api/flatbuffers). -// * @param {String} [options.snapping] Which edges can be snapped to, either `default`, or `any`. `default` only snaps to edges marked by the profile as `is_startpoint`, `any` will allow snapping to any edge in the routing graph. -// * @param {Function} callback -// * -// * @returns {Object} containing `waypoints`. -// * **`waypoints`**: array of [`Ẁaypoint`](#waypoint) objects sorted by distance to the input coordinate. -// * Each object has an additional `distance` property, which is the distance in meters to the supplied input coordinate. -// * -// * @example -// * var osrm = new OSRM('network.osrm'); -// * var options = { -// * coordinates: [[13.388860,52.517037]], -// * number: 3, -// * bearings: [[0,20]] -// * }; -// * osrm.nearest(options, function(err, response) { -// * console.log(response.waypoints); // array of Waypoint objects -// * }); -// */ -// // clang-format on -// NAN_METHOD(Engine::nearest) // -// { -// osrm::Status (osrm::OSRM::*nearest_fn)(const osrm::NearestParameters ¶ms, -// osrm::engine::api::ResultT &result) const = -// &osrm::OSRM::Nearest; -// async(info, &argumentsToNearestParameter, nearest_fn, false); -// } - -// // clang-format off -// /** -// * Computes duration table for the given locations. Allows for both symmetric and asymmetric tables. -// * Optionally returns distance table. -// * -// * @name table -// * @memberof OSRM -// * @param {Object} options - Object literal containing parameters for the table query. -// * @param {Array} [options.coordinates] The coordinates this request will use, coordinates as `[{lon},{lat}]` values, in decimal degrees. -// * @param {Array} [options.bearings] Limits the search to segments with given bearing in degrees towards true north in clockwise direction. -// * Can be `null` or an array of `[{value},{range}]` with `integer 0 .. 360,integer 0 .. 180`. -// * @param {Array} [options.radiuses] Limits the coordinate snapping to streets in the given radius in meters. Can be `null` (unlimited, default) or `double >= 0`. -// * @param {Array} [options.hints] Hints for the coordinate snapping. Array of base64 encoded strings. -// * @param {Boolean} [options.generate_hints=true] Whether or not adds a Hint to the response which can be used in subsequent requests. -// * @param {Array} [options.sources] An array of `index` elements (`0 <= integer < #coordinates`) to use -// * location with given index as source. Default is to use all. -// * @param {Array} [options.destinations] An array of `index` elements (`0 <= integer < #coordinates`) to use location with given index as destination. Default is to use all. -// * @param {Array} [options.approaches] Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`. -// * @param {Number} [options.fallback_speed] Replace `null` responses in result with as-the-crow-flies estimates based on `fallback_speed`. Value is in metres/second. -// * @param {String} [options.fallback_coordinate] Either `input` (default) or `snapped`. If using a `fallback_speed`, use either the user-supplied coordinate (`input`), or the snapped coordinate (`snapped`) for calculating the as-the-crow-flies distance between two points. -// * @param {Number} [options.scale_factor] Multiply the table duration values in the table by this number for more controlled input into a route optimization solver. -// * @param {String} [options.snapping] Which edges can be snapped to, either `default`, or `any`. `default` only snaps to edges marked by the profile as `is_startpoint`, `any` will allow snapping to any edge in the routing graph. -// * @param {Array} [options.annotations] Return the requested table or tables in response. Can be `['duration']` (return the duration matrix, default), `[distance']` (return the distance matrix), or `['duration', distance']` (return both the duration matrix and the distance matrix). - -// * @param {Function} callback -// * -// * @returns {Object} containing `durations`, `distances`, `sources`, and `destinations`. -// * **`durations`**: array of arrays that stores the matrix in row-major order. `durations[i][j]` gives the travel time from the i-th waypoint to the j-th waypoint. -// * Values are given in seconds. -// * **`distances`**: array of arrays that stores the matrix in row-major order. `distances[i][j]` gives the travel time from the i-th waypoint to the j-th waypoint. -// * Values are given in meters. -// * **`sources`**: array of [`Ẁaypoint`](#waypoint) objects describing all sources in order. -// * **`destinations`**: array of [`Ẁaypoint`](#waypoint) objects describing all destinations in order. -// * **`fallback_speed_cells`**: (optional) if `fallback_speed` is used, will be an array of arrays of `row,column` values, indicating which cells contain estimated values. -// * -// * @example -// * var osrm = new OSRM('network.osrm'); -// * var options = { -// * coordinates: [ -// * [13.388860,52.517037], -// * [13.397634,52.529407], -// * [13.428555,52.523219] -// * ] -// * }; -// * osrm.table(options, function(err, response) { -// * console.log(response.durations); // array of arrays, matrix in row-major order -// * console.log(response.distances); // array of arrays, matrix in row-major order -// * console.log(response.sources); // array of Waypoint objects -// * console.log(response.destinations); // array of Waypoint objects -// * }); -// */ -// // clang-format on -// NAN_METHOD(Engine::table) // -// { -// osrm::Status (osrm::OSRM::*table_fn)(const osrm::TableParameters ¶ms, -// osrm::engine::api::ResultT &result) const = -// &osrm::OSRM::Table; -// async(info, &argumentsToTableParameter, table_fn, true); -// } - -// // clang-format off -// /** -// * This generates [Mapbox Vector Tiles](https://mapbox.com/vector-tiles) that can be viewed with a -// * vector-tile capable slippy-map viewer. The tiles contain road geometries and metadata that can -// * be used to examine the routing graph. The tiles are generated directly from the data in-memory, -// * so are in sync with actual routing results, and let you examine which roads are actually -// * routable, -// * and what weights they have applied. -// * -// * @name tile -// * @memberof OSRM -// * @param {Array} ZXY - an array consisting of `x`, `y`, and `z` values representing tile coordinates like -// * [wiki.openstreetmap.org/wiki/Slippy_map_tilenames](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames) -// * and are supported by vector tile viewers like [Mapbox GL JS](https://www.mapbox.com/mapbox-gl-js/api/). -// * @param {Function} callback -// * -// * @returns {Buffer} contains a Protocol Buffer encoded vector tile. -// * -// * @example -// * var osrm = new OSRM('network.osrm'); -// * osrm.tile([0, 0, 0], function(err, response) { -// * if (err) throw err; -// * fs.writeFileSync('./tile.vector.pbf', response); // write the buffer to a file -// * }); -// */ -// // clang-format on -// NAN_METHOD(Engine::tile) -// { -// osrm::Status (osrm::OSRM::*tile_fn)(const osrm::TileParameters ¶ms, -// osrm::engine::api::ResultT &result) const = -// &osrm::OSRM::Tile; -// asyncForTiles(info, &argumentsToTileParameters, tile_fn, {/*unused*/}); -// } - -// // clang-format off -// /** -// * Map matching matches given GPS points to the road network in the most plausible way. -// * Please note the request might result multiple sub-traces. Large jumps in the timestamps -// * (>60s) or improbable transitions lead to trace splits if a complete matching could -// * not be found. The algorithm might not be able to match all points. Outliers are removed -// * if they can not be matched successfully. -// * -// * @name match -// * @memberof OSRM -// * @param {Object} options - Object literal containing parameters for the match query. -// * @param {Array} [options.coordinates] The coordinates this request will use, coordinates as `[{lon},{lat}]` values, in decimal degrees. -// * @param {Array} [options.bearings] Limits the search to segments with given bearing in degrees towards true north in clockwise direction. -// * Can be `null` or an array of `[{value},{range}]` with `integer 0 .. 360,integer 0 .. 180`. -// * @param {Array} [options.hints] Hints for the coordinate snapping. Array of base64 encoded strings. -// * @param {Boolean} [options.generate_hints=true] Whether or not adds a Hint to the response which can be used in subsequent requests. -// * @param {Boolean} [options.steps=false] Return route steps for each route. -// * @param {Array|Boolean} [options.annotations=false] An array with strings of `duration`, `nodes`, `distance`, `weight`, `datasources`, `speed` or boolean for enabling/disabling all. -// * @param {String} [options.geometries=polyline] Returned route geometry format (influences overview and per step). Can also be `geojson`. -// * @param {String} [options.overview=simplified] Add overview geometry either `full`, `simplified` according to highest zoom level it could be display on, or not at all (`false`). -// * @param {Array} [options.timestamps] Timestamp of the input location (integers, UNIX-like timestamp). -// * @param {Array} [options.radiuses] Standard deviation of GPS precision used for map matching. If applicable use GPS accuracy. Can be `null` for default value `5` meters or `double >= 0`. -// * @param {String} [options.gaps=split] Allows the input track splitting based on huge timestamp gaps between points. Either `split` or `ignore`. -// * @param {Boolean} [options.tidy=false] Allows the input track modification to obtain better matching quality for noisy tracks. -// * @param {Array} [options.waypoints] Indices to coordinates to treat as waypoints. If not supplied, all coordinates are waypoints. Must include first and last coordinate index. -// * @param {String} [options.snapping] Which edges can be snapped to, either `default`, or `any`. `default` only snaps to edges marked by the profile as `is_startpoint`, `any` will allow snapping to any edge in the routing graph. -// * -// * @param {Function} callback -// * -// * @returns {Object} containing `tracepoints` and `matchings`. -// * **`tracepoints`** Array of [`Ẁaypoint`](#waypoint) objects representing all points of the trace in order. -// * If the trace point was ommited by map matching because it is an outlier, the entry will be null. -// * Each `Waypoint` object has the following additional properties, -// * 1) `matchings_index`: Index to the -// * [`Route`](#route) object in matchings the sub-trace was matched to, -// * 2) `waypoint_index`: Index of -// * the waypoint inside the matched route. -// * 3) `alternatives_count`: Number of probable alternative matchings for this trace point. A value of zero indicate that this point was matched unambiguously. Split the trace at these points for incremental map matching. -// * **`matchings`** is an array of [`Route`](#route) objects that assemble the trace. Each `Route` object has an additional `confidence` property, -// * which is the confidence of the matching. float value between `0` and `1`. `1` is very confident that the matching is correct. -// * -// * @example -// * var osrm = new OSRM('network.osrm'); -// * var options = { -// * coordinates: [[13.393252,52.542648],[13.39478,52.543079],[13.397389,52.542107]], -// * timestamps: [1424684612, 1424684616, 1424684620] -// * }; -// * osrm.match(options, function(err, response) { -// * if (err) throw err; -// * console.log(response.tracepoints); // array of Waypoint objects -// * console.log(response.matchings); // array of Route objects -// * }); -// * -// */ -// // clang-format on -// NAN_METHOD(Engine::match) // -// { -// osrm::Status (osrm::OSRM::*match_fn)(const osrm::MatchParameters ¶ms, -// osrm::engine::api::ResultT &result) const = -// &osrm::OSRM::Match; -// async(info, &argumentsToMatchParameter, match_fn, true); -// } - -// // clang-format off -// /** -// * The trip plugin solves the Traveling Salesman Problem using a greedy heuristic -// * (farthest-insertion algorithm) for 10 or * more waypoints and uses brute force for less than 10 -// * waypoints. The returned path does not have to be the shortest path, * as TSP is NP-hard it is -// * only an approximation. -// * -// * Note that all input coordinates have to be connected for the trip service to work. -// * Currently, not all combinations of `roundtrip`, `source` and `destination` are supported. -// * Right now, the following combinations are possible: -// * -// * | roundtrip | source | destination | supported | -// * | :-- | :-- | :-- | :-- | -// * | true | first | last | **yes** | -// * | true | first | any | **yes** | -// * | true | any | last | **yes** | -// * | true | any | any | **yes** | -// * | false | first | last | **yes** | -// * | false | first | any | no | -// * | false | any | last | no | -// * | false | any | any | no | -// * -// * @name trip -// * @memberof OSRM -// * @param {Object} options - Object literal containing parameters for the trip query. -// * @param {Array} [options.coordinates] The coordinates this request will use, coordinates as `[{lon},{lat}]` values, in decimal degrees. -// * @param {Array} [options.bearings] Limits the search to segments with given bearing in degrees towards true north in clockwise direction. -// * Can be `null` or an array of `[{value},{range}]` with `integer 0 .. 360,integer 0 .. 180`. -// * @param {Array} [options.radiuses] Limits the coordinate snapping to streets in the given radius in meters. Can be `double >= 0` or `null` (unlimited, default). -// * @param {Array} [options.hints] Hints for the coordinate snapping. Array of base64 encoded strings. -// * @param {Boolean} [options.generate_hints=true] Whether or not adds a Hint to the response which can be used in subsequent requests. -// * @param {Boolean} [options.steps=false] Return route steps for each route. -// * @param {Array|Boolean} [options.annotations=false] An array with strings of `duration`, `nodes`, `distance`, `weight`, `datasources`, `speed` or boolean for enabling/disabling all. -// * @param {String} [options.geometries=polyline] Returned route geometry format (influences overview and per step). Can also be `geojson`. -// * @param {String} [options.overview=simplified] Add overview geometry either `full`, `simplified` -// * @param {Function} callback -// * @param {Boolean} [options.roundtrip=true] Return route is a roundtrip. -// * @param {String} [options.source=any] Return route starts at `any` or `first` coordinate. -// * @param {String} [options.destination=any] Return route ends at `any` or `last` coordinate. -// * @param {Array} [options.approaches] Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`. -// * @param {String} [options.snapping] Which edges can be snapped to, either `default`, or `any`. `default` only snaps to edges marked by the profile as `is_startpoint`, `any` will allow snapping to any edge in the routing graph. -// * -// * @returns {Object} containing `waypoints` and `trips`. -// * **`waypoints`**: an array of [`Waypoint`](#waypoint) objects representing all waypoints in input order. -// * Each Waypoint object has the following additional properties, -// * 1) `trips_index`: index to trips of the sub-trip the point was matched to, and -// * 2) `waypoint_index`: index of the point in the trip. -// * **`trips`**: an array of [`Route`](#route) objects that assemble the trace. -// * -// * @example -// * var osrm = new OSRM('network.osrm'); -// * var options = { -// * coordinates: [ -// * [13.36761474609375, 52.51663871100423], -// * [13.374481201171875, 52.506191342034576] -// * ], -// * source: "first", -// * destination: "last", -// * roundtrip: false -// * } -// * osrm.trip(options, function(err, response) { -// * if (err) throw err; -// * console.log(response.waypoints); // array of Waypoint objects -// * console.log(response.trips); // array of Route objects -// * }); -// */ -// // clang-format on -// NAN_METHOD(Engine::trip) // -// { -// osrm::Status (osrm::OSRM::*trip_fn)(const osrm::TripParameters ¶ms, -// osrm::engine::api::ResultT &result) const = -// &osrm::OSRM::Trip; -// async(info, &argumentsToTripParameter, trip_fn, true); -// } - -// /** -// * All plugins support a second additional object that is available to configure some NodeJS -// * specific behaviours. -// * -// * @name Configuration -// * @param {Object} [plugin_config] - Object literal containing parameters for the trip query. -// * @param {String} [plugin_config.format] The format of the result object to various API calls. -// * Valid options are `object` (default if `options.format` is -// * `json`), which returns a standard Javascript object, as described above, and `buffer`(default if -// * `options.format` is `flatbuffers`), which will return a NodeJS -// * **[Buffer](https://nodejs.org/api/buffer.html)** object, containing a JSON string or Flatbuffers -// * object. The latter has the advantage that it can be immediately serialized to disk/sent over the -// * network, and the generation of the string is performed outside the main NodeJS event loop. This -// * option is ignored by the `tile` plugin. Also note that `options.format` set to `flatbuffers` -// * cannot be used with `plugin_config.format` set to `object`. `json_buffer` is deprecated alias for -// * `buffer`. -// * -// * @example -// * var osrm = new OSRM('network.osrm'); -// * var options = { -// * coordinates: [ -// * [13.36761474609375, 52.51663871100423], -// * [13.374481201171875, 52.506191342034576] -// * ] -// * }; -// * osrm.route(options, { format: "buffer" }, function(err, response) { -// * if (err) throw err; -// * console.log(response.toString("utf-8")); -// * }); -// */ - -// /** -// * @class Responses -// */ - -// /** -// * Represents a route through (potentially multiple) waypoints. -// * -// * @name Route -// * @memberof Responses -// * -// * @param {documentation} external in -// * [`osrm-backend`](../http.md#route-object) -// * -// */ - -// /** -// * Represents a route between two waypoints. -// * -// * @name RouteLeg -// * @memberof Responses -// * -// * @param {documentation} external in -// * [`osrm-backend`](../http.md#routeleg-object) -// * -// */ - -// /** -// * A step consists of a maneuver such as a turn or merge, followed by a distance of travel along a -// * single way to the subsequent step. -// * -// * @name RouteStep -// * @memberof Responses -// * -// * @param {documentation} external in -// * [`osrm-backend`](../http.md#routestep-object) -// * -// */ - -// /** -// * -// * @name StepManeuver -// * @memberof Responses -// * -// * @param {documentation} external in -// * [`osrm-backend`](../http.md#stepmaneuver-object) -// * -// */ - -// /** -// * Object used to describe waypoint on a route. -// * -// * @name Waypoint -// * @memberof Responses -// * -// * @param {documentation} external in -// * [`osrm-backend`](../http.md#waypoint-object) -// * -// */ - -// } // namespace node_osrm