| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261 | 
							- /*
 
-  *
 
-  * Copyright 2015, Google Inc.
 
-  * All rights reserved.
 
-  *
 
-  * Redistribution and use in source and binary forms, with or without
 
-  * modification, are permitted provided that the following conditions are
 
-  * met:
 
-  *
 
-  *     * Redistributions of source code must retain the above copyright
 
-  * notice, this list of conditions and the following disclaimer.
 
-  *     * Redistributions in binary form must reproduce the above
 
-  * copyright notice, this list of conditions and the following disclaimer
 
-  * in the documentation and/or other materials provided with the
 
-  * distribution.
 
-  *     * Neither the name of Google Inc. nor the names of its
 
-  * contributors may be used to endorse or promote products derived from
 
-  * this software without specific prior written permission.
 
-  *
 
-  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
-  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
-  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
-  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
-  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
-  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
-  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
-  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
-  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
-  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
-  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-  *
 
-  */
 
- var messages = require('./route_guide_pb');
 
- var services = require('./route_guide_grpc_pb');
 
- var fs = require('fs');
 
- var parseArgs = require('minimist');
 
- var path = require('path');
 
- var _ = require('lodash');
 
- var grpc = require('grpc');
 
- var COORD_FACTOR = 1e7;
 
- /**
 
-  * For simplicity, a point is a record type that looks like
 
-  * {latitude: number, longitude: number}, and a feature is a record type that
 
-  * looks like {name: string, location: point}. feature objects with name===''
 
-  * are points with no feature.
 
-  */
 
- /**
 
-  * List of feature objects at points that have been requested so far.
 
-  */
 
- var feature_list = [];
 
- /**
 
-  * Get a feature object at the given point, or creates one if it does not exist.
 
-  * @param {point} point The point to check
 
-  * @return {feature} The feature object at the point. Note that an empty name
 
-  *     indicates no feature
 
-  */
 
- function checkFeature(point) {
 
-   var feature;
 
-   // Check if there is already a feature object for the given point
 
-   for (var i = 0; i < feature_list.length; i++) {
 
-     feature = feature_list[i];
 
-     if (feature.getLocation().getLatitude() === point.getLatitude() &&
 
-         feature.getLocation().getLongitude() === point.getLongitude()) {
 
-       return feature;
 
-     }
 
-   }
 
-   var name = '';
 
-   feature = new messages.Feature();
 
-   feature.setName(name);
 
-   feature.setLocation(point);
 
-   return feature;
 
- }
 
- /**
 
-  * getFeature request handler. Gets a request with a point, and responds with a
 
-  * feature object indicating whether there is a feature at that point.
 
-  * @param {EventEmitter} call Call object for the handler to process
 
-  * @param {function(Error, feature)} callback Response callback
 
-  */
 
- function getFeature(call, callback) {
 
-   callback(null, checkFeature(call.request));
 
- }
 
- /**
 
-  * listFeatures request handler. Gets a request with two points, and responds
 
-  * with a stream of all features in the bounding box defined by those points.
 
-  * @param {Writable} call Writable stream for responses with an additional
 
-  *     request property for the request value.
 
-  */
 
- function listFeatures(call) {
 
-   var lo = call.request.getLo();
 
-   var hi = call.request.getHi();
 
-   var left = _.min([lo.getLongitude(), hi.getLongitude()]);
 
-   var right = _.max([lo.getLongitude(), hi.getLongitude()]);
 
-   var top = _.max([lo.getLatitude(), hi.getLatitude()]);
 
-   var bottom = _.min([lo.getLatitude(), hi.getLatitude()]);
 
-   // For each feature, check if it is in the given bounding box
 
-   _.each(feature_list, function(feature) {
 
-     if (feature.getName() === '') {
 
-       return;
 
-     }
 
-     if (feature.getLocation().getLongitude() >= left &&
 
-         feature.getLocation().getLongitude() <= right &&
 
-         feature.getLocation().getLatitude() >= bottom &&
 
-         feature.getLocation().getLatitude() <= top) {
 
-       call.write(feature);
 
-     }
 
-   });
 
-   call.end();
 
- }
 
- /**
 
-  * Calculate the distance between two points using the "haversine" formula.
 
-  * This code was taken from http://www.movable-type.co.uk/scripts/latlong.html.
 
-  * @param start The starting point
 
-  * @param end The end point
 
-  * @return The distance between the points in meters
 
-  */
 
- function getDistance(start, end) {
 
-   function toRadians(num) {
 
-     return num * Math.PI / 180;
 
-   }
 
-   var lat1 = start.getLatitude() / COORD_FACTOR;
 
-   var lat2 = end.getLatitude() / COORD_FACTOR;
 
-   var lon1 = start.getLongitude() / COORD_FACTOR;
 
-   var lon2 = end.getLongitude() / COORD_FACTOR;
 
-   var R = 6371000; // metres
 
-   var φ1 = toRadians(lat1);
 
-   var φ2 = toRadians(lat2);
 
-   var Δφ = toRadians(lat2-lat1);
 
-   var Δλ = toRadians(lon2-lon1);
 
-   var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
 
-       Math.cos(φ1) * Math.cos(φ2) *
 
-       Math.sin(Δλ/2) * Math.sin(Δλ/2);
 
-   var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
 
-   return R * c;
 
- }
 
- /**
 
-  * recordRoute handler. Gets a stream of points, and responds with statistics
 
-  * about the "trip": number of points, number of known features visited, total
 
-  * distance traveled, and total time spent.
 
-  * @param {Readable} call The request point stream.
 
-  * @param {function(Error, routeSummary)} callback The callback to pass the
 
-  *     response to
 
-  */
 
- function recordRoute(call, callback) {
 
-   var point_count = 0;
 
-   var feature_count = 0;
 
-   var distance = 0;
 
-   var previous = null;
 
-   // Start a timer
 
-   var start_time = process.hrtime();
 
-   call.on('data', function(point) {
 
-     point_count += 1;
 
-     if (checkFeature(point).name !== '') {
 
-       feature_count += 1;
 
-     }
 
-     /* For each point after the first, add the incremental distance from the
 
-      * previous point to the total distance value */
 
-     if (previous != null) {
 
-       distance += getDistance(previous, point);
 
-     }
 
-     previous = point;
 
-   });
 
-   call.on('end', function() {
 
-     var summary = new messages.RouteSummary();
 
-     summary.setPointCount(point_count);
 
-     summary.setFeatureCount(feature_count);
 
-     // Cast the distance to an integer
 
-     summary.setDistance(distance|0);
 
-     // End the timer
 
-     summary.setElapsedTime(process.hrtime(start_time)[0]);
 
-     callback(null, summary);
 
-   });
 
- }
 
- var route_notes = {};
 
- /**
 
-  * Turn the point into a dictionary key.
 
-  * @param {point} point The point to use
 
-  * @return {string} The key for an object
 
-  */
 
- function pointKey(point) {
 
-   return point.getLatitude() + ' ' + point.getLongitude();
 
- }
 
- /**
 
-  * routeChat handler. Receives a stream of message/location pairs, and responds
 
-  * with a stream of all previous messages at each of those locations.
 
-  * @param {Duplex} call The stream for incoming and outgoing messages
 
-  */
 
- function routeChat(call) {
 
-   call.on('data', function(note) {
 
-     var key = pointKey(note.getLocation());
 
-     /* For each note sent, respond with all previous notes that correspond to
 
-      * the same point */
 
-     if (route_notes.hasOwnProperty(key)) {
 
-       _.each(route_notes[key], function(note) {
 
-         call.write(note);
 
-       });
 
-     } else {
 
-       route_notes[key] = [];
 
-     }
 
-     // Then add the new note to the list
 
-     route_notes[key].push(note);
 
-   });
 
-   call.on('end', function() {
 
-     call.end();
 
-   });
 
- }
 
- /**
 
-  * Get a new server with the handler functions in this file bound to the methods
 
-  * it serves.
 
-  * @return {Server} The new server object
 
-  */
 
- function getServer() {
 
-   var server = new grpc.Server();
 
-   server.addService(services.RouteGuideService, {
 
-     getFeature: getFeature,
 
-     listFeatures: listFeatures,
 
-     recordRoute: recordRoute,
 
-     routeChat: routeChat
 
-   });
 
-   return server;
 
- }
 
- if (require.main === module) {
 
-   // If this is run as a script, start a server on an unused port
 
-   var routeServer = getServer();
 
-   routeServer.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure());
 
-   var argv = parseArgs(process.argv, {
 
-     string: 'db_path'
 
-   });
 
-   fs.readFile(path.resolve(argv.db_path), function(err, data) {
 
-     if (err) throw err;
 
-     // Transform the loaded features to Feature objects
 
-     feature_list = _.map(JSON.parse(data), function(value) {
 
-       var feature = new messages.Feature();
 
-       feature.setName(value.name);
 
-       var location = new messages.Point();
 
-       location.setLatitude(value.location.latitude);
 
-       location.setLongitude(value.location.longitude);
 
-       feature.setLocation(location);
 
-       return feature;
 
-     });
 
-     routeServer.start();
 
-   });
 
- }
 
- exports.getServer = getServer;
 
 
  |