2016-05-26 18:39:46 -04:00
|
|
|
'use strict';
|
|
|
|
|
2016-09-19 17:13:44 -04:00
|
|
|
const Timeout = require('node-timeout');
|
|
|
|
const request = require('request');
|
|
|
|
const ensureDecimal = require('../lib/utils').ensureDecimal;
|
2016-03-04 15:11:05 -05:00
|
|
|
|
|
|
|
module.exports = function () {
|
|
|
|
this.requestPath = (service, params, callback) => {
|
2016-03-29 13:35:56 -04:00
|
|
|
var uri;
|
|
|
|
if (service == 'timestamp') {
|
|
|
|
uri = [this.HOST, service].join('/');
|
|
|
|
} else {
|
|
|
|
uri = [this.HOST, service, 'v1', this.profile].join('/');
|
|
|
|
}
|
|
|
|
|
2016-03-04 15:11:05 -05:00
|
|
|
return this.sendRequest(uri, params, callback);
|
|
|
|
};
|
|
|
|
|
|
|
|
this.requestUrl = (path, callback) => {
|
|
|
|
var uri = this.query = [this.HOST, path].join('/'),
|
2016-05-05 12:36:30 -04:00
|
|
|
limit = Timeout(this.TIMEOUT, { err: { statusCode: 408 } });
|
2016-03-04 15:11:05 -05:00
|
|
|
|
|
|
|
function runRequest (cb) {
|
|
|
|
request(uri, cb);
|
|
|
|
}
|
|
|
|
|
|
|
|
runRequest(limit((err, res, body) => {
|
|
|
|
if (err) {
|
|
|
|
if (err.statusCode === 408) return callback(this.RoutedError('*** osrm-routed did not respond'));
|
|
|
|
else if (err.code === 'ECONNREFUSED')
|
|
|
|
return callback(this.RoutedError('*** osrm-routed is not running'));
|
|
|
|
} else
|
|
|
|
return callback(err, res, body);
|
|
|
|
}));
|
|
|
|
};
|
|
|
|
|
|
|
|
// Overwrites the default values in defaults
|
|
|
|
// e.g. [[a, 1], [b, 2]], [[a, 5], [d, 10]] => [[a, 5], [b, 2], [d, 10]]
|
|
|
|
this.overwriteParams = (defaults, other) => {
|
2016-03-25 14:58:30 -04:00
|
|
|
var otherMap = {};
|
|
|
|
for (var key in other) otherMap[key] = other[key];
|
|
|
|
return Object.assign({}, defaults, otherMap);
|
2016-03-04 15:11:05 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
var encodeWaypoints = (waypoints) => {
|
2016-09-19 17:13:44 -04:00
|
|
|
return waypoints.map(w => [w.lon, w.lat].map(ensureDecimal).join(','));
|
2016-03-04 15:11:05 -05:00
|
|
|
};
|
|
|
|
|
2017-05-22 10:07:12 -04:00
|
|
|
this.requestRoute = (waypoints, bearings, approaches, userParams, callback) => {
|
2016-03-04 15:11:05 -05:00
|
|
|
if (bearings.length && bearings.length !== waypoints.length) throw new Error('*** number of bearings does not equal the number of waypoints');
|
2017-05-22 10:07:12 -04:00
|
|
|
if (approaches.length && approaches.length !== waypoints.length) throw new Error('*** number of approaches does not equal the number of waypoints');
|
2016-03-04 15:11:05 -05:00
|
|
|
|
2016-03-25 14:58:30 -04:00
|
|
|
var defaults = {
|
2016-03-29 13:39:48 -04:00
|
|
|
output: 'json',
|
|
|
|
steps: 'true',
|
|
|
|
alternatives: 'false'
|
|
|
|
},
|
2016-03-04 15:11:05 -05:00
|
|
|
params = this.overwriteParams(defaults, userParams),
|
|
|
|
encodedWaypoints = encodeWaypoints(waypoints);
|
2016-03-25 14:58:30 -04:00
|
|
|
|
|
|
|
params.coordinates = encodedWaypoints;
|
|
|
|
|
2016-03-04 15:11:05 -05:00
|
|
|
if (bearings.length) {
|
2016-03-30 21:34:13 -04:00
|
|
|
params.bearings = bearings.map(b => {
|
|
|
|
var bs = b.split(',');
|
|
|
|
if (bs.length === 2) return b;
|
|
|
|
else return b += ',10';
|
|
|
|
}).join(';');
|
2016-03-04 15:11:05 -05:00
|
|
|
}
|
|
|
|
|
2017-05-22 10:07:12 -04:00
|
|
|
if (approaches.length) {
|
|
|
|
params.approaches = approaches.join(';');
|
2017-05-16 12:46:26 -04:00
|
|
|
}
|
2016-03-25 14:58:30 -04:00
|
|
|
return this.requestPath('route', params, callback);
|
2016-03-04 15:11:05 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
this.requestNearest = (node, userParams, callback) => {
|
2016-03-25 14:58:30 -04:00
|
|
|
var defaults = {
|
2016-03-29 13:39:48 -04:00
|
|
|
output: 'json'
|
|
|
|
},
|
2016-03-04 15:11:05 -05:00
|
|
|
params = this.overwriteParams(defaults, userParams);
|
2016-03-25 14:58:30 -04:00
|
|
|
params.coordinates = [[node.lon, node.lat].join(',')];
|
2016-03-04 15:11:05 -05:00
|
|
|
|
|
|
|
return this.requestPath('nearest', params, callback);
|
|
|
|
};
|
|
|
|
|
|
|
|
this.requestTable = (waypoints, userParams, callback) => {
|
2016-03-25 14:58:30 -04:00
|
|
|
var defaults = {
|
2016-03-29 13:39:48 -04:00
|
|
|
output: 'json'
|
|
|
|
},
|
2016-03-04 15:11:05 -05:00
|
|
|
params = this.overwriteParams(defaults, userParams);
|
2016-03-25 14:58:30 -04:00
|
|
|
|
|
|
|
params.coordinates = waypoints.map(w => [w.coord.lon, w.coord.lat].join(','));
|
2016-03-29 21:18:09 -04:00
|
|
|
var srcs = waypoints.map((w, i) => [w.type, i]).filter(w => w[0] === 'src').map(w => w[1]),
|
|
|
|
dsts = waypoints.map((w, i) => [w.type, i]).filter(w => w[0] === 'dst').map(w => w[1]);
|
|
|
|
if (srcs.length) params.sources = srcs.join(';');
|
|
|
|
if (dsts.length) params.destinations = dsts.join(';');
|
2016-03-04 15:11:05 -05:00
|
|
|
|
|
|
|
return this.requestPath('table', params, callback);
|
|
|
|
};
|
|
|
|
|
|
|
|
this.requestTrip = (waypoints, userParams, callback) => {
|
2016-03-25 14:58:30 -04:00
|
|
|
var defaults = {
|
2016-03-29 13:39:48 -04:00
|
|
|
output: 'json'
|
|
|
|
},
|
2016-03-04 15:11:05 -05:00
|
|
|
params = this.overwriteParams(defaults, userParams);
|
2016-03-25 14:58:30 -04:00
|
|
|
|
|
|
|
params.coordinates = encodeWaypoints(waypoints);
|
2016-03-04 15:11:05 -05:00
|
|
|
|
|
|
|
return this.requestPath('trip', params, callback);
|
|
|
|
};
|
|
|
|
|
|
|
|
this.requestMatching = (waypoints, timestamps, userParams, callback) => {
|
2016-03-25 14:58:30 -04:00
|
|
|
var defaults = {
|
2016-03-29 13:39:48 -04:00
|
|
|
output: 'json'
|
|
|
|
},
|
2016-03-04 15:11:05 -05:00
|
|
|
params = this.overwriteParams(defaults, userParams);
|
2016-03-25 14:58:30 -04:00
|
|
|
|
|
|
|
params.coordinates = encodeWaypoints(waypoints);
|
|
|
|
|
2016-03-04 15:11:05 -05:00
|
|
|
if (timestamps.length) {
|
2016-03-30 09:45:48 -04:00
|
|
|
params.timestamps = timestamps.join(';');
|
2016-03-04 15:11:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return this.requestPath('match', params, callback);
|
|
|
|
};
|
|
|
|
|
2016-08-17 03:49:19 -04:00
|
|
|
this.extractInstructionList = (instructions, keyFinder) => {
|
2016-03-04 15:11:05 -05:00
|
|
|
if (instructions) {
|
2016-03-28 17:49:29 -04:00
|
|
|
return instructions.legs.reduce((m, v) => m.concat(v.steps), [])
|
|
|
|
.map(keyFinder)
|
2016-03-04 15:11:05 -05:00
|
|
|
.join(',');
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-04-28 19:48:44 -04:00
|
|
|
this.summary = (instructions) => {
|
|
|
|
if (instructions) {
|
2016-09-28 17:41:34 -04:00
|
|
|
return instructions.legs.map(l => l.summary).join(';');
|
2016-04-28 19:48:44 -04:00
|
|
|
}
|
2016-04-29 05:39:33 -04:00
|
|
|
};
|
2016-04-28 19:48:44 -04:00
|
|
|
|
2016-03-04 15:11:05 -05:00
|
|
|
this.wayList = (instructions) => {
|
2016-03-27 23:55:12 -04:00
|
|
|
return this.extractInstructionList(instructions, s => s.name);
|
2016-03-04 15:11:05 -05:00
|
|
|
};
|
|
|
|
|
2016-09-05 09:01:51 -04:00
|
|
|
this.refList = (instructions) => {
|
|
|
|
return this.extractInstructionList(instructions, s => s.ref || '');
|
|
|
|
};
|
|
|
|
|
2016-05-25 21:35:38 -04:00
|
|
|
this.pronunciationList = (instructions) => {
|
|
|
|
return this.extractInstructionList(instructions, s => s.pronunciation || '');
|
|
|
|
};
|
|
|
|
|
2016-05-26 18:47:46 -04:00
|
|
|
this.destinationsList = (instructions) => {
|
|
|
|
return this.extractInstructionList(instructions, s => s.destinations || '');
|
|
|
|
};
|
|
|
|
|
2017-06-29 16:12:25 -04:00
|
|
|
this.exitsList = (instructions) => {
|
|
|
|
return this.extractInstructionList(instructions, s => s.exits || '');
|
|
|
|
};
|
|
|
|
|
2016-08-17 03:49:19 -04:00
|
|
|
this.reverseBearing = (bearing) => {
|
|
|
|
if (bearing >= 180)
|
|
|
|
return bearing - 180.;
|
|
|
|
return bearing + 180;
|
|
|
|
};
|
|
|
|
|
2016-03-04 15:11:05 -05:00
|
|
|
this.bearingList = (instructions) => {
|
2016-08-17 03:49:19 -04:00
|
|
|
return this.extractInstructionList(instructions, s => ('in' in s.intersections[0] ? this.reverseBearing(s.intersections[0].bearings[s.intersections[0].in]) : 0)
|
|
|
|
+ '->' +
|
|
|
|
('out' in s.intersections[0] ? s.intersections[0].bearings[s.intersections[0].out] : 0));
|
2016-03-04 15:11:05 -05:00
|
|
|
};
|
|
|
|
|
2017-05-22 10:07:12 -04:00
|
|
|
this.approachList = (instructions) => {
|
|
|
|
return this.extractInstructionList(instructions, s => s.approaches || '');
|
2017-05-16 12:46:26 -04:00
|
|
|
};
|
|
|
|
|
2016-06-01 13:56:50 -04:00
|
|
|
this.annotationList = (instructions) => {
|
2017-01-31 06:04:07 -05:00
|
|
|
if (!('annotation' in instructions.legs[0]))
|
2016-05-12 12:50:10 -04:00
|
|
|
return '';
|
|
|
|
|
2017-02-02 07:30:01 -05:00
|
|
|
var merged = {};
|
|
|
|
instructions.legs.map(l => {
|
|
|
|
Object.keys(l.annotation).forEach(a => {
|
|
|
|
if (!merged[a]) merged[a] = [];
|
|
|
|
merged[a].push(l.annotation[a].join(':'));
|
|
|
|
});
|
|
|
|
});
|
|
|
|
Object.keys(merged).map(a => {
|
|
|
|
merged[a] = merged[a].join(',');
|
|
|
|
});
|
|
|
|
return merged;
|
2016-06-01 17:37:21 -04:00
|
|
|
};
|
2016-05-19 11:04:00 -04:00
|
|
|
|
2017-01-17 05:49:31 -05:00
|
|
|
this.alternativesList = (instructions) => {
|
|
|
|
// alternatives_count come from tracepoints list
|
|
|
|
return instructions.tracepoints.map(t => t.alternatives_count.toString()).join(',');
|
|
|
|
};
|
|
|
|
|
2016-05-13 13:18:00 -04:00
|
|
|
this.lanesList = (instructions) => {
|
2016-06-15 08:38:24 -04:00
|
|
|
return this.extractInstructionList(instructions, instruction => {
|
2016-07-21 08:34:32 -04:00
|
|
|
if( 'lanes' in instruction.intersections[0] )
|
2016-06-15 08:38:24 -04:00
|
|
|
{
|
2016-07-21 08:34:32 -04:00
|
|
|
return instruction.intersections[0].lanes.map( p => { return (p.indications).join(';') + ':' + p.valid; } ).join(' ');
|
2016-06-15 08:38:24 -04:00
|
|
|
} else
|
|
|
|
{
|
|
|
|
return '';
|
|
|
|
}});
|
2016-05-13 13:18:00 -04:00
|
|
|
};
|
|
|
|
|
2016-03-04 15:11:05 -05:00
|
|
|
this.turnList = (instructions) => {
|
2016-03-28 17:49:29 -04:00
|
|
|
return instructions.legs.reduce((m, v) => m.concat(v.steps), [])
|
2016-03-29 16:55:02 -04:00
|
|
|
.map(v => {
|
|
|
|
switch (v.maneuver.type) {
|
2016-03-30 09:46:19 -04:00
|
|
|
case 'depart':
|
|
|
|
case 'arrive':
|
|
|
|
return v.maneuver.type;
|
2016-05-03 07:37:41 -04:00
|
|
|
case 'on ramp':
|
|
|
|
case 'off ramp':
|
|
|
|
return v.maneuver.type + ' ' + v.maneuver.modifier;
|
2016-03-30 09:46:19 -04:00
|
|
|
case 'roundabout':
|
|
|
|
return 'roundabout-exit-' + v.maneuver.exit;
|
2016-03-23 08:04:23 -04:00
|
|
|
case 'rotary':
|
|
|
|
if( 'rotary_name' in v )
|
|
|
|
return v.rotary_name + '-exit-' + v.maneuver.exit;
|
|
|
|
else
|
|
|
|
return 'rotary-exit-' + v.maneuver.exit;
|
2016-05-03 07:37:41 -04:00
|
|
|
case 'roundabout turn':
|
2016-04-18 07:41:19 -04:00
|
|
|
return v.maneuver.type + ' ' + v.maneuver.modifier + ' exit-' + v.maneuver.exit;
|
2016-03-31 16:03:31 -04:00
|
|
|
// FIXME this is a little bit over-simplistic for merge/fork instructions
|
2016-03-30 09:46:19 -04:00
|
|
|
default:
|
2016-03-23 08:04:23 -04:00
|
|
|
return v.maneuver.type + ' ' + v.maneuver.modifier;
|
2016-03-29 16:55:02 -04:00
|
|
|
}
|
|
|
|
})
|
2016-11-08 06:52:15 -05:00
|
|
|
.join(',');
|
|
|
|
};
|
|
|
|
|
|
|
|
this.locations = (instructions) => {
|
|
|
|
return instructions.legs.reduce((m, v) => m.concat(v.steps), [])
|
|
|
|
.map(v => {
|
|
|
|
return this.findNodeByLocation(v.maneuver.location);
|
|
|
|
})
|
2016-03-28 17:49:29 -04:00
|
|
|
.join(',');
|
2016-03-04 15:11:05 -05:00
|
|
|
};
|
|
|
|
|
2016-05-10 02:37:45 -04:00
|
|
|
this.intersectionList = (instructions) => {
|
|
|
|
return instructions.legs.reduce((m, v) => m.concat(v.steps), [])
|
|
|
|
.map( v => {
|
|
|
|
return v.intersections
|
|
|
|
.map( intersection => {
|
|
|
|
var string = intersection.entry[0]+':'+intersection.bearings[0], i;
|
|
|
|
for( i = 1; i < intersection.bearings.length; ++i )
|
|
|
|
string = string + ' ' + intersection.entry[i]+':'+intersection.bearings[i];
|
|
|
|
return string;
|
2016-05-12 05:16:52 -04:00
|
|
|
}).join(',');
|
|
|
|
}).join(';');
|
2016-05-10 02:37:45 -04:00
|
|
|
};
|
|
|
|
|
2016-03-04 15:11:05 -05:00
|
|
|
this.modeList = (instructions) => {
|
2016-03-28 17:49:29 -04:00
|
|
|
return this.extractInstructionList(instructions, s => s.mode);
|
2016-03-04 15:11:05 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
this.timeList = (instructions) => {
|
2016-03-28 17:49:29 -04:00
|
|
|
return this.extractInstructionList(instructions, s => s.duration + 's');
|
2016-03-04 15:11:05 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
this.distanceList = (instructions) => {
|
2016-03-28 17:49:29 -04:00
|
|
|
return this.extractInstructionList(instructions, s => s.distance + 'm');
|
2016-03-04 15:11:05 -05:00
|
|
|
};
|
2016-05-12 12:50:10 -04:00
|
|
|
|
|
|
|
this.weightName = (instructions) => {
|
|
|
|
return instructions ? instructions.weight_name : '';
|
|
|
|
};
|
|
|
|
|
|
|
|
this.weightList = (instructions) => {
|
|
|
|
return this.extractInstructionList(instructions, s => s.weight);
|
|
|
|
};
|
2016-03-04 15:11:05 -05:00
|
|
|
};
|