node-red-node-web-nodes
Version:
A collection of Node-RED nodes for popular web services.
321 lines (303 loc) • 13 kB
JavaScript
/**
* Copyright 2015 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
module.exports = function(RED) {
"use strict";
var request = require('request');
var clone = require('clone');
function GoogleDirectionsNode(n) {
RED.nodes.createNode(this,n);
var node = this;
this.googleAPI = RED.nodes.getNode(n.googleAPI);
this.on('input', function(msg){
var url, queryParams, key, origin, destination, mode, waypoints, alternatives, avoid, language, units, region, departure_time, arrival_time, transit_mode, transit_routing_preferences;
if(this.googleAPI && this.googleAPI.credentials && this.googleAPI.credentials.key){
key = this.googleAPI.credentials.key;
} else if(msg.key){
key = msg.key;
}
origin = n.origin || msg.origin;
destination = n.destination || msg.destination;
mode = n.mode || msg.mode;
waypoints = n.waypoints || msg.waypoints;
alternatives = n.alternatives || msg.alternatives;
avoid = n.avoid || msg.avoid;
language = n.language || msg.language;
units = n.units || msg.units;
region = n.region || msg.region;
departure_time = n.departure_time || msg.departure_time;
arrival_time = n.arrival_time || msg.arrival_time;
transit_mode = n.transit_mode || msg.transit_mode;
transit_routing_preferences = n.transit_routing_preferences || msg.transit_routing_preferences;
function processInput(){
queryParams = {};
if(key){
queryParams.key = key;
}
directionsRequest(function(response){
if(response){
node.send(response);
}
});
}
function directionsRequest(cb){
url = 'https://maps.googleapis.com/maps/api/directions/json';
if(!origin){
throwNodeError({
code: 400,
message: 'Please supply an origin value',
status: 'MISSING_VALUES'
}, msg);
return;
}
if(!destination){
throwNodeError({
code: 400,
message: 'Please supply an destination value',
status: 'MISSING_VALUES'
}, msg);
return;
}
queryParams.origin = origin;
queryParams.destination = destination;
if(mode){
queryParams.mode = mode;
}
if(waypoints){
queryParams.waypoints = waypoints;
}
if(alternatives){
queryParams.alternatives = alternatives;
}
if(avoid){
queryParams.avoid = avoid;
}
if(language){
queryParams.language = language;
}
if(units){
queryParams.units = units;
}
if(region){
queryParams.region = region;
}
if(departure_time){
queryParams.departure_time = departure_time;
}
if(arrival_time){
queryParams.arrival_time = arrival_time;
}
if(transit_mode){
queryParams.transit_mode = transit_mode;
}
if(transit_routing_preferences){
queryParams.transit_routing_preferences = transit_routing_preferences;
}
// console.log(queryParams);
sendReqToGoogle(function(err, data){
if(err){
// console.log(err);
throwNodeError(err, msg);
return;
} else{
handleDirectionsResponse(JSON.parse(data), function(msg){
cb(msg);
});
}
});
}
function handleDirectionsResponse(data, cb){
var newMsg;
if(data.status == 'OK'){
newMsg = cloneMsg(msg); //quick clone msg
newMsg.payload = {
routes: [],
status: data.status
};
for(var i = 0; i < data.routes.length; i++){
newMsg.payload.routes.push(parseRoute(data.routes[i]));
}
newMsg.status = data.status;
newMsg.title = 'Travel directions via ' + newMsg.payload.routes[0].summary;
newMsg.description = 'Travel directions via ' + newMsg.payload.routes[0].summary;
newMsg.distance = newMsg.payload.routes[0].legs[0].distance.value;
newMsg.duration = newMsg.payload.routes[0].legs[0].duration.value;
newMsg.location = {
start: {
address: newMsg.payload.routes[0].legs[0].start_location.address,
lat: newMsg.payload.routes[0].legs[0].start_location.lat,
lon: newMsg.payload.routes[0].legs[0].start_location.lon
},
end: {
address: newMsg.payload.routes[0].legs[0].end_location.address,
lat: newMsg.payload.routes[0].legs[0].end_location.lat,
lon: newMsg.payload.routes[0].legs[0].end_location.lon
}
};
cb(newMsg);
} else if (data.status == 'ZERO_RESULTS'){
newMsg = cloneMsg(msg); //quick clone msg
newMsg.payload = {
status: 'ZERO_RESULTS'
};
newMsg.title = 'ZERO_RESULTS';
newMsg.description = 'ZERO_RESULTS';
cb(newMsg);
}else{
var error = {};
error.status = data.status;
switch(data.status){
case 'NOT_FOUND':
error.code = 400;
error.message = 'Could not find origin, destination, or waypoint';
break;
case 'MAX_WAYPOINTS_EXCEEDED':
error.code = 400;
error.message = 'Too many waypoints provided. The maximum allowed is 8';
break;
case 'INVALID_REQUEST':
error.code = 400;
error.message = 'Invalid request. Check for an invalid parameter or parameter value';
break;
case 'OVER_QUERY_REQUEST':
error.code = 429;
error.message = 'Too many requests from provided application key';
break;
case 'REQUEST_DENIED':
error.code = 400;
error.message = 'Request denied by Google';
break;
case 'UNKNOWN_ERROR':
error.code = 500;
error.message = 'An unknown error occured. Please try again';
break;
default:
error.code = 500;
error.message = 'An unknown error occured. Please try again';
}
throwNodeError({
code: 400,
message: 'Please supply an destination value',
status: 'MISSING_VALUES'
}, msg);
return;
}
}
function sendReqToGoogle(cb){
request.get({
url: url,
qs: queryParams,
method: "GET"
}, function(err, resp, body){
cb(err, body);
});
}
function parseRoute(route){
var parsedRoute = {};
parsedRoute.copyrights = route.copyrights;
parsedRoute.summary = route.summary;
parsedRoute.bounds = {
northeast: {
lat: route.bounds.northeast.lat,
lon: route.bounds.northeast.lng
},
southwest: {
lat: route.bounds.southwest.lat,
lon: route.bounds.southwest.lng
}
};
if(route.warnings.length > 0){
parsedRoute.warnings = route.warnings;
}
if(route.waypoint_order.length > 0){
parsedRoute.waypoint_order = route.waypoint_order;
}
parsedRoute.fare = route.fare;
parsedRoute.legs = [];
for(var i = 0; i < route.legs.length; i++){
parsedRoute.legs.push(parseLeg(route.legs[i]));
}
return parsedRoute;
}
function parseLeg(leg){
var parsedLeg = {};
parsedLeg.distance = leg.distance;
parsedLeg.duration = leg.duration;
parsedLeg.duration_in_traffic = leg.duration_in_traffic;
parsedLeg.departure_time = leg.departure_time;
parsedLeg.arrival_time = leg.arrival_time;
parsedLeg.start_location = {
address: leg.start_address,
lat: leg.start_location.lat,
lon: leg.start_location.lng
};
parsedLeg.end_location = {
address: leg.end_address,
lat: leg.end_location.lat,
lon: leg.end_location.lng
};
parsedLeg.steps = [];
for(var i = 0; i < leg.steps.length; i++){
parsedLeg.steps.push(parseStep(leg.steps[i]));
}
return parsedLeg;
}
function parseStep(step){
var parsedStep = {};
parsedStep.distance = step.distance;
parsedStep.duration = step.duration;
parsedStep.start_location = {
lat: step.start_location.lat,
lon: step.start_location.lng
};
parsedStep.end_location = {
lat: step.end_location.lat,
lon: step.end_location.lng
};
parsedStep.html_instructions = step.html_instructions;
parsedStep.maneuver = step.maneuver;
parsedStep.travel_mode = step.travel_mode;
if(parsedStep.travel_mode == 'transit'){
parsedStep.transit_details = step.transit_details;
}
return parsedStep;
}
processInput();
});
function throwNodeError(err, msg){
node.status({fill:"red",shape:"ring",text:"failed"});
msg.error = err;
node.error(err, msg);
return;
}
}
RED.nodes.registerType("google directions",GoogleDirectionsNode);
function cloneMsg(msg){
var req = msg.req;
var res = msg.res;
delete msg.req;
delete msg.res;
var m = clone(msg);
if (req) {
m.req = req;
msg.req = req;
}
if (res) {
m.res = res;
msg.res = res;
}
return m;
}
};