osrm.js
Version:
REST client for the OSRM server API
194 lines (170 loc) • 6.11 kB
JavaScript
var http = require('http'),
https = require('https'),
qs = require('qs'),
url = require('url');
function OSRM(arg) {
this._url = 'https://router.project-osrm.org';
this._profile = 'driving';
this._timeout = 10000; // 10 seconds
if (typeof arg === 'string')
{
this._url = arg;
}
else if (Array.isArray(arg))
{
throw new Error('Argument must be string or options object');
}
else if (typeof arg === 'object')
{
this._url = arg.url || this._url;
this._profile = arg.profile || this._profile;
this._timeout = arg.timeout || this._timeout;
}
else if (typeof arg !== 'undefined')
{
throw new Error('Argument must be string or options object');
}
var protocol = url.parse(this._url).protocol;
if (protocol != "http:" && protocol != "https:")
{
throw new Error("Unsupported protocol: " + protocol);
}
this._get = function(url, callback) {
if (protocol === "http:")
{
return http.get(url, callback);
}
else if (protocol == "https:")
{
return https.get(url, callback);
}
throw Error("No protocol handler found for " + protocol);
}
}
OSRM.prototype = {
_filterOptions: function(options, keys) {
var filtered = {};
for (var k in options) {
if (keys.indexOf(k) >= 0 ) {
continue;
}
filtered[k] = options[k];
}
return filtered;
},
_stringifyCoordinates: function(lonLats) {
return lonLats.map(function(c) {return c[0] + ',' + c[1]; } ).join(';');
},
_stringifyOptionsArray: function(array) {
array.map(function(value) { return value === null && '' || value; }).join(';')
},
_stringifyOptions: function(options) {
// we use a different array encoding than the very wasteful QS encoding
for (var key in options) {
if (Array.isArray(options[key]))
{
options[key] = this._stringifyOptionsArray(options[key]);
}
}
return qs.stringify(options);
},
_encodeUrl: function(service, version, query, format, options, callback) {
var url = this._url + '/' + service + '/' + version + '/' + this._profile + '/' + query + '.' + format;
var option_string = this._stringifyOptions(options);
if (option_string.length > 0)
{
url += '?' + option_string;
}
return url;
},
request: function(arg, callback) {
var url = (typeof arg === 'string') && (this._url + arg) ||
this._encodeUrl(arg.service, arg.version, arg.query, arg.format, arg.options);
var timeout = setTimeout(function() { callback(new Error("Request timed out")); }, this._timeout);
this._get(url, function (response) {
var body = '';
response.on('data', function(data) {
body += data;
});
response.on('end', function() {
clearTimeout(timeout);
var format = response.headers['content-type'].split(";")[0];
if (format === 'application/json')
{
callback(null, JSON.parse(body));
}
// unknonw, pass through
else
{
callback(null, body);
}
});
}).on('error', function(err) {
callback(err);
});
},
nearest: function(options, callback) {
if (!options.coordinates) {
throw new Error('No coordinates properties in options.');
}
if (options.coordinates.length != 1) {
throw new Error('Only supports nearest queries for a single coordinate.');
}
var query = this._stringifyCoordinates(options.coordinates);
options = this._filterOptions(options, ['coordinates']);
this.request({service: 'nearest', version: 'v1', query: query, format: 'json', options: options}, callback);
},
match: function(options, callback) {
if (!options.coordinates) {
throw new Error('No coordinates properties in options.');
}
if (options.coordinates.length < 2) {
throw new Error('Needs at least two coordinates');
}
if (options.timestamps && options.coordinates.length != options.timestamps.length) {
throw new Error('Timestamps array needs to be the same size as the coordinates array');
}
var query = this._stringifyCoordinates(options.coordinates);
options = this._filterOptions(options, ['coordinates']);
this.request({service: 'match', version: 'v1', query: query, format: 'json', options: options}, callback);
},
route: function(options, callback) {
if (!options.coordinates) {
throw new Error('No coordinates properties in options.');
}
if (options.coordinates.length < 2) {
throw new Error('Needs at least two coordinates');
}
var query = this._stringifyCoordinates(options.coordinates);
options = this._filterOptions(options, ['coordinates']);
this.request({service: 'route', version: 'v1', query: query, format: 'json', options: options}, callback);
},
trip: function(options, callback) {
if (!options.coordinates) {
throw new Error('No coordinates properties in options.');
}
if (options.coordinates.length < 2) {
throw new Error('Needs at least two coordinates');
}
var query = this._stringifyCoordinates(options.coordinates);
options = this._filterOptions(options, ['coordinates']);
this.request({service: 'trip', version: 'v1', query: query, format: 'json', options: options}, callback);
},
table: function(options, callback) {
if (!options.coordinates) {
throw new Error('No coordinates properties in options.');
}
if (options.coordinates.length < 2) {
throw new Error('Needs at least two coordinates');
}
var query = this._stringifyCoordinates(options.coordinates);
options = this._filterOptions(options, ['coordinates']);
this.request({service: 'table', version: 'v1', query: query, format: 'json', options: options}, callback);
},
tile: function(xyz, callback) {
var query = 'tile(' + xyz.join(',') + ')';
this.request({service: 'tile', version: 'v1', query: query, format: 'mvt', options: {}}, callback);
},
};
if (typeof module !== 'undefined') module.exports = OSRM;
;