var Timeout = require('node-timeout'); var request = require('request'); module.exports = function () { this.requestPath = (service, params, callback) => { var uri = [this.HOST, service].join('/'); return this.sendRequest(uri, params, callback); }; this.requestUrl = (path, callback) => { var uri = this.query = [this.HOST, path].join('/'), limit = Timeout(this.OSRM_TIMEOUT, { err: { statusCode: 408 } }); 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) => { var merged = {}; var overwrite = (o) => { merged[o[0]] = o[1]; }; defaults.forEach(overwrite); other.forEach(overwrite); return Object.keys(merged).map((key) => [key, merged[key]]); }; var encodeWaypoints = (waypoints) => { return waypoints.map(w => ['loc', [w.lat, w.lon].join(',')]); }; this.requestRoute = (waypoints, bearings, userParams, callback) => { if (bearings.length && bearings.length !== waypoints.length) throw new Error('*** number of bearings does not equal the number of waypoints'); var defaults = [['output','json'], ['instructions','true'], ['alt',false]], params = this.overwriteParams(defaults, userParams), encodedWaypoints = encodeWaypoints(waypoints); if (bearings.length) { var encodedBearings = bearings.map(b => ['b', b.toString()]); params = Array.prototype.concat.apply(params, encodedWaypoints.map((o, i) => [o, encodedBearings[i]])); } else { params = params.concat(encodedWaypoints); } return this.requestPath('viaroute', params, callback); }; this.requestNearest = (node, userParams, callback) => { var defaults = [['output', 'json']], params = this.overwriteParams(defaults, userParams); params.push(['loc', [node.lat, node.lon].join(',')]); return this.requestPath('nearest', params, callback); }; this.requestTable = (waypoints, userParams, callback) => { var defaults = [['output', 'json']], params = this.overwriteParams(defaults, userParams); params = params.concat(waypoints.map(w => [w.type, [w.coord.lat, w.coord.lon].join(',')])); return this.requestPath('table', params, callback); }; this.requestTrip = (waypoints, userParams, callback) => { var defaults = [['output', 'json']], params = this.overwriteParams(defaults, userParams); params = params.concat(encodeWaypoints(waypoints)); return this.requestPath('trip', params, callback); }; this.requestMatching = (waypoints, timestamps, userParams, callback) => { var defaults = [['output', 'json']], params = this.overwriteParams(defaults, userParams); var encodedWaypoints = encodeWaypoints(waypoints); if (timestamps.length) { var encodedTimestamps = timestamps.map(t => ['t', t.toString()]); params = Array.prototype.concat.apply(params, encodedWaypoints.map((o, i) => [o, encodedTimestamps[i]])); } else { params = params.concat(encodedWaypoints); } return this.requestPath('match', params, callback); }; this.extractInstructionList = (instructions, index, postfix) => { postfix = postfix || null; if (instructions) { return instructions.filter(r => r[0].toString() !== this.DESTINATION_REACHED.toString()) .map(r => r[index]) .map(r => (isNaN(parseInt(r)) && (!r || r == '')) ? '""' : '' + r + (postfix || '')) .join(','); } }; this.wayList = (instructions) => { return this.extractInstructionList(instructions, 1); }; this.compassList = (instructions) => { return this.extractInstructionList(instructions, 6); }; this.bearingList = (instructions) => { return this.extractInstructionList(instructions, 7); }; this.turnList = (instructions) => { var types = { '0': 'none', '1': 'straight', '2': 'slight_right', '3': 'right', '4': 'sharp_right', '5': 'u_turn', '6': 'sharp_left', '7': 'left', '8': 'slight_left', '9': 'via', '10': 'head', '11': 'enter_roundabout', '12': 'leave_roundabout', '13': 'stay_roundabout', '14': 'start_end_of_street', '15': 'destination', '16': 'name_changes', '17': 'enter_contraflow', '18': 'leave_contraflow' }; // replace instructions codes with strings, e.g. '11-3' gets converted to 'enter_roundabout-3' return instructions ? instructions.map(r => r[0].toString().replace(/^(\d*)/, (match, num) => types[num])).join(',') : instructions; }; this.modeList = (instructions) => { return this.extractInstructionList(instructions, 8); }; this.timeList = (instructions) => { return this.extractInstructionList(instructions, 4, 's'); }; this.distanceList = (instructions) => { return this.extractInstructionList(instructions, 2, 'm'); }; };