diff options
Diffstat (limited to 'src/node')
-rw-r--r-- | src/node/examples/route_guide.proto | 120 | ||||
-rw-r--r-- | src/node/examples/route_guide_client.js | 231 | ||||
-rw-r--r-- | src/node/examples/route_guide_db.json | 601 | ||||
-rw-r--r-- | src/node/examples/route_guide_server.js | 249 | ||||
-rw-r--r-- | src/node/interop/empty.proto | 6 | ||||
-rw-r--r-- | src/node/package.json | 1 |
6 files changed, 1202 insertions, 6 deletions
diff --git a/src/node/examples/route_guide.proto b/src/node/examples/route_guide.proto new file mode 100644 index 0000000000..442112823e --- /dev/null +++ b/src/node/examples/route_guide.proto @@ -0,0 +1,120 @@ +// 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. + +syntax = "proto3"; + +option java_package = "io.grpc.examples"; + +package examples; + +// Interface exported by the server. +service RouteGuide { + // A simple RPC. + // + // Obtains the feature at a given position. + rpc GetFeature(Point) returns (Feature) {} + + // A server-to-client streaming RPC. + // + // Obtains the Features available within the given Rectangle. Results are + // streamed rather than returned at once (e.g. in a response message with a + // repeated field), as the rectangle may cover a large area and contain a + // huge number of features. + rpc ListFeatures(Rectangle) returns (stream Feature) {} + + // A client-to-server streaming RPC. + // + // Accepts a stream of Points on a route being traversed, returning a + // RouteSummary when traversal is completed. + rpc RecordRoute(stream Point) returns (RouteSummary) {} + + // A Bidirectional streaming RPC. + // + // Accepts a stream of RouteNotes sent while a route is being traversed, + // while receiving other RouteNotes (e.g. from other users). + rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} +} + +// Points are represented as latitude-longitude pairs in the E7 representation +// (degrees multiplied by 10**7 and rounded to the nearest integer). +// Latitudes should be in the range +/- 90 degrees and longitude should be in +// the range +/- 180 degrees (inclusive). +message Point { + optional int32 latitude = 1; + optional int32 longitude = 2; +} + +// A latitude-longitude rectangle, represented as two diagonally opposite +// points "lo" and "hi". +message Rectangle { + // One corner of the rectangle. + optional Point lo = 1; + + // The other corner of the rectangle. + optional Point hi = 2; +} + +// A feature names something at a given point. +// +// If a feature could not be named, the name is empty. +message Feature { + // The name of the feature. + optional string name = 1; + + // The point where the feature is detected. + optional Point location = 2; +} + +// A RouteNote is a message sent while at a given point. +message RouteNote { + // The location from which the message is sent. + optional Point location = 1; + + // The message to be sent. + optional string message = 2; +} + +// A RouteSummary is received in response to a RecordRoute rpc. +// +// It contains the number of individual points received, the number of +// detected features, and the total distance covered as the cumulative sum of +// the distance between each point. +message RouteSummary { + // The number of points received. + optional int32 point_count = 1; + + // The number of known features passed while traversing the route. + optional int32 feature_count = 2; + + // The distance covered in metres. + optional int32 distance = 3; + + // The duration of the traversal in seconds. + optional int32 elapsed_time = 4; +} diff --git a/src/node/examples/route_guide_client.js b/src/node/examples/route_guide_client.js new file mode 100644 index 0000000000..d4c083a6c5 --- /dev/null +++ b/src/node/examples/route_guide_client.js @@ -0,0 +1,231 @@ +// 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 async = require('async'); +var fs = require('fs'); +var parseArgs = require('minimist'); +var path = require('path'); +var _ = require('underscore'); +var grpc = require('..'); +var examples = grpc.load(__dirname + '/route_guide.proto').examples; +var client = new examples.RouteGuide('localhost:50051'); + +var COORD_FACTOR = 1e7; + +/** + * Run the getFeature demo. Calls getFeature with a point known to have a + * feature and a point known not to have a feature. + * @param {function} callback Called when this demo is complete + */ +function runGetFeature(callback) { + var next = _.after(2, callback); + function featureCallback(error, feature) { + if (error) { + callback(error); + } + if (feature.name === '') { + console.log('Found no feature at ' + + feature.location.latitude/COORD_FACTOR + ', ' + + feature.location.longitude/COORD_FACTOR); + } else { + console.log('Found feature called "' + feature.name + '" at ' + + feature.location.latitude/COORD_FACTOR + ', ' + + feature.location.longitude/COORD_FACTOR); + } + next(); + } + var point1 = { + latitude: 409146138, + longitude: -746188906 + }; + var point2 = { + latitude: 0, + longitude: 0 + }; + client.getFeature(point1, featureCallback); + client.getFeature(point2, featureCallback); +} + +/** + * Run the listFeatures demo. Calls listFeatures with a rectangle containing all + * of the features in the pre-generated database. Prints each response as it + * comes in. + * @param {function} callback Called when this demo is complete + */ +function runListFeatures(callback) { + var rectangle = { + lo: { + latitude: 400000000, + longitude: -750000000 + }, + hi: { + latitude: 420000000, + longitude: -730000000 + } + }; + console.log('Looking for features between 40, -75 and 42, -73'); + var call = client.listFeatures(rectangle); + call.on('data', function(feature) { + console.log('Found feature called "' + feature.name + '" at ' + + feature.location.latitude/COORD_FACTOR + ', ' + + feature.location.longitude/COORD_FACTOR); + }); + call.on('end', callback); +} + +/** + * Run the recordRoute demo. Sends several randomly chosen points from the + * pre-generated feature database with a variable delay in between. Prints the + * statistics when they are sent from the server. + * @param {function} callback Called when this demo is complete + */ +function runRecordRoute(callback) { + var argv = parseArgs(process.argv, { + string: 'db_path' + }); + fs.readFile(path.resolve(argv.db_path), function(err, data) { + if (err) callback(err); + var feature_list = JSON.parse(data); + + var num_points = 10; + var call = client.recordRoute(function(error, stats) { + if (error) { + callback(error); + } + console.log('Finished trip with', stats.point_count, 'points'); + console.log('Passed', stats.feature_count, 'features'); + console.log('Travelled', stats.distance, 'meters'); + console.log('It took', stats.elapsed_time, 'seconds'); + callback(); + }); + /** + * Constructs a function that asynchronously sends the given point and then + * delays sending its callback + * @param {number} lat The latitude to send + * @param {number} lng The longitude to send + * @return {function(function)} The function that sends the point + */ + function pointSender(lat, lng) { + /** + * Sends the point, then calls the callback after a delay + * @param {function} callback Called when complete + */ + return function(callback) { + console.log('Visiting point ' + lat/COORD_FACTOR + ', ' + + lng/COORD_FACTOR); + call.write({ + latitude: lat, + longitude: lng + }); + _.delay(callback, _.random(500, 1500)); + }; + } + var point_senders = []; + for (var i = 0; i < num_points; i++) { + var rand_point = feature_list[_.random(0, feature_list.length - 1)]; + point_senders[i] = pointSender(rand_point.location.latitude, + rand_point.location.longitude); + } + async.series(point_senders, function() { + call.end(); + }); + }); +} + +/** + * Run the routeChat demo. Send some chat messages, and print any chat messages + * that are sent from the server. + * @param {function} callback Called when the demo is complete + */ +function runRouteChat(callback) { + var call = client.routeChat(); + call.on('data', function(note) { + console.log('Got message "' + note.message + '" at ' + + note.location.latitude + ', ' + note.location.longitude); + }); + + call.on('end', callback); + + var notes = [{ + location: { + latitude: 0, + longitude: 0 + }, + message: 'First message' + }, { + location: { + latitude: 0, + longitude: 1 + }, + message: 'Second message' + }, { + location: { + latitude: 1, + longitude: 0 + }, + message: 'Third message' + }, { + location: { + latitude: 0, + longitude: 0 + }, + message: 'Fourth message' + }]; + for (var i = 0; i < notes.length; i++) { + var note = notes[i]; + console.log('Sending message "' + note.message + '" at ' + + note.location.latitude + ', ' + note.location.longitude); + call.write(note); + } + call.end(); +} + +/** + * Run all of the demos in order + */ +function main() { + async.series([ + runGetFeature, + runListFeatures, + runRecordRoute, + runRouteChat + ]); +} + +if (require.main === module) { + main(); +} + +exports.runGetFeature = runGetFeature; + +exports.runListFeatures = runListFeatures; + +exports.runRecordRoute = runRecordRoute; + +exports.runRouteChat = runRouteChat; diff --git a/src/node/examples/route_guide_db.json b/src/node/examples/route_guide_db.json new file mode 100644 index 0000000000..9d6a980ab7 --- /dev/null +++ b/src/node/examples/route_guide_db.json @@ -0,0 +1,601 @@ +[{ + "location": { + "latitude": 407838351, + "longitude": -746143763 + }, + "name": "Patriots Path, Mendham, NJ 07945, USA" +}, { + "location": { + "latitude": 408122808, + "longitude": -743999179 + }, + "name": "101 New Jersey 10, Whippany, NJ 07981, USA" +}, { + "location": { + "latitude": 413628156, + "longitude": -749015468 + }, + "name": "U.S. 6, Shohola, PA 18458, USA" +}, { + "location": { + "latitude": 419999544, + "longitude": -740371136 + }, + "name": "5 Conners Road, Kingston, NY 12401, USA" +}, { + "location": { + "latitude": 414008389, + "longitude": -743951297 + }, + "name": "Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA" +}, { + "location": { + "latitude": 419611318, + "longitude": -746524769 + }, + "name": "287 Flugertown Road, Livingston Manor, NY 12758, USA" +}, { + "location": { + "latitude": 406109563, + "longitude": -742186778 + }, + "name": "4001 Tremley Point Road, Linden, NJ 07036, USA" +}, { + "location": { + "latitude": 416802456, + "longitude": -742370183 + }, + "name": "352 South Mountain Road, Wallkill, NY 12589, USA" +}, { + "location": { + "latitude": 412950425, + "longitude": -741077389 + }, + "name": "Bailey Turn Road, Harriman, NY 10926, USA" +}, { + "location": { + "latitude": 412144655, + "longitude": -743949739 + }, + "name": "193-199 Wawayanda Road, Hewitt, NJ 07421, USA" +}, { + "location": { + "latitude": 415736605, + "longitude": -742847522 + }, + "name": "406-496 Ward Avenue, Pine Bush, NY 12566, USA" +}, { + "location": { + "latitude": 413843930, + "longitude": -740501726 + }, + "name": "162 Merrill Road, Highland Mills, NY 10930, USA" +}, { + "location": { + "latitude": 410873075, + "longitude": -744459023 + }, + "name": "Clinton Road, West Milford, NJ 07480, USA" +}, { + "location": { + "latitude": 412346009, + "longitude": -744026814 + }, + "name": "16 Old Brook Lane, Warwick, NY 10990, USA" +}, { + "location": { + "latitude": 402948455, + "longitude": -747903913 + }, + "name": "3 Drake Lane, Pennington, NJ 08534, USA" +}, { + "location": { + "latitude": 406337092, + "longitude": -740122226 + }, + "name": "6324 8th Avenue, Brooklyn, NY 11220, USA" +}, { + "location": { + "latitude": 406421967, + "longitude": -747727624 + }, + "name": "1 Merck Access Road, Whitehouse Station, NJ 08889, USA" +}, { + "location": { + "latitude": 416318082, + "longitude": -749677716 + }, + "name": "78-98 Schalck Road, Narrowsburg, NY 12764, USA" +}, { + "location": { + "latitude": 415301720, + "longitude": -748416257 + }, + "name": "282 Lakeview Drive Road, Highland Lake, NY 12743, USA" +}, { + "location": { + "latitude": 402647019, + "longitude": -747071791 + }, + "name": "330 Evelyn Avenue, Hamilton Township, NJ 08619, USA" +}, { + "location": { + "latitude": 412567807, + "longitude": -741058078 + }, + "name": "New York State Reference Route 987E, Southfields, NY 10975, USA" +}, { + "location": { + "latitude": 416855156, + "longitude": -744420597 + }, + "name": "103-271 Tempaloni Road, Ellenville, NY 12428, USA" +}, { + "location": { + "latitude": 404663628, + "longitude": -744820157 + }, + "name": "1300 Airport Road, North Brunswick Township, NJ 08902, USA" +}, { + "location": { + "latitude": 407113723, + "longitude": -749746483 + }, + "name": "" +}, { + "location": { + "latitude": 402133926, + "longitude": -743613249 + }, + "name": "" +}, { + "location": { + "latitude": 400273442, + "longitude": -741220915 + }, + "name": "" +}, { + "location": { + "latitude": 411236786, + "longitude": -744070769 + }, + "name": "" +}, { + "location": { + "latitude": 411633782, + "longitude": -746784970 + }, + "name": "211-225 Plains Road, Augusta, NJ 07822, USA" +}, { + "location": { + "latitude": 415830701, + "longitude": -742952812 + }, + "name": "" +}, { + "location": { + "latitude": 413447164, + "longitude": -748712898 + }, + "name": "165 Pedersen Ridge Road, Milford, PA 18337, USA" +}, { + "location": { + "latitude": 405047245, + "longitude": -749800722 + }, + "name": "100-122 Locktown Road, Frenchtown, NJ 08825, USA" +}, { + "location": { + "latitude": 418858923, + "longitude": -746156790 + }, + "name": "" +}, { + "location": { + "latitude": 417951888, + "longitude": -748484944 + }, + "name": "650-652 Willi Hill Road, Swan Lake, NY 12783, USA" +}, { + "location": { + "latitude": 407033786, + "longitude": -743977337 + }, + "name": "26 East 3rd Street, New Providence, NJ 07974, USA" +}, { + "location": { + "latitude": 417548014, + "longitude": -740075041 + }, + "name": "" +}, { + "location": { + "latitude": 410395868, + "longitude": -744972325 + }, + "name": "" +}, { + "location": { + "latitude": 404615353, + "longitude": -745129803 + }, + "name": "" +}, { + "location": { + "latitude": 406589790, + "longitude": -743560121 + }, + "name": "611 Lawrence Avenue, Westfield, NJ 07090, USA" +}, { + "location": { + "latitude": 414653148, + "longitude": -740477477 + }, + "name": "18 Lannis Avenue, New Windsor, NY 12553, USA" +}, { + "location": { + "latitude": 405957808, + "longitude": -743255336 + }, + "name": "82-104 Amherst Avenue, Colonia, NJ 07067, USA" +}, { + "location": { + "latitude": 411733589, + "longitude": -741648093 + }, + "name": "170 Seven Lakes Drive, Sloatsburg, NY 10974, USA" +}, { + "location": { + "latitude": 412676291, + "longitude": -742606606 + }, + "name": "1270 Lakes Road, Monroe, NY 10950, USA" +}, { + "location": { + "latitude": 409224445, + "longitude": -748286738 + }, + "name": "509-535 Alphano Road, Great Meadows, NJ 07838, USA" +}, { + "location": { + "latitude": 406523420, + "longitude": -742135517 + }, + "name": "652 Garden Street, Elizabeth, NJ 07202, USA" +}, { + "location": { + "latitude": 401827388, + "longitude": -740294537 + }, + "name": "349 Sea Spray Court, Neptune City, NJ 07753, USA" +}, { + "location": { + "latitude": 410564152, + "longitude": -743685054 + }, + "name": "13-17 Stanley Street, West Milford, NJ 07480, USA" +}, { + "location": { + "latitude": 408472324, + "longitude": -740726046 + }, + "name": "47 Industrial Avenue, Teterboro, NJ 07608, USA" +}, { + "location": { + "latitude": 412452168, + "longitude": -740214052 + }, + "name": "5 White Oak Lane, Stony Point, NY 10980, USA" +}, { + "location": { + "latitude": 409146138, + "longitude": -746188906 + }, + "name": "Berkshire Valley Management Area Trail, Jefferson, NJ, USA" +}, { + "location": { + "latitude": 404701380, + "longitude": -744781745 + }, + "name": "1007 Jersey Avenue, New Brunswick, NJ 08901, USA" +}, { + "location": { + "latitude": 409642566, + "longitude": -746017679 + }, + "name": "6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA" +}, { + "location": { + "latitude": 408031728, + "longitude": -748645385 + }, + "name": "1358-1474 New Jersey 57, Port Murray, NJ 07865, USA" +}, { + "location": { + "latitude": 413700272, + "longitude": -742135189 + }, + "name": "367 Prospect Road, Chester, NY 10918, USA" +}, { + "location": { + "latitude": 404310607, + "longitude": -740282632 + }, + "name": "10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA" +}, { + "location": { + "latitude": 409319800, + "longitude": -746201391 + }, + "name": "11 Ward Street, Mount Arlington, NJ 07856, USA" +}, { + "location": { + "latitude": 406685311, + "longitude": -742108603 + }, + "name": "300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA" +}, { + "location": { + "latitude": 419018117, + "longitude": -749142781 + }, + "name": "43 Dreher Road, Roscoe, NY 12776, USA" +}, { + "location": { + "latitude": 412856162, + "longitude": -745148837 + }, + "name": "Swan Street, Pine Island, NY 10969, USA" +}, { + "location": { + "latitude": 416560744, + "longitude": -746721964 + }, + "name": "66 Pleasantview Avenue, Monticello, NY 12701, USA" +}, { + "location": { + "latitude": 405314270, + "longitude": -749836354 + }, + "name": "" +}, { + "location": { + "latitude": 414219548, + "longitude": -743327440 + }, + "name": "" +}, { + "location": { + "latitude": 415534177, + "longitude": -742900616 + }, + "name": "565 Winding Hills Road, Montgomery, NY 12549, USA" +}, { + "location": { + "latitude": 406898530, + "longitude": -749127080 + }, + "name": "231 Rocky Run Road, Glen Gardner, NJ 08826, USA" +}, { + "location": { + "latitude": 407586880, + "longitude": -741670168 + }, + "name": "100 Mount Pleasant Avenue, Newark, NJ 07104, USA" +}, { + "location": { + "latitude": 400106455, + "longitude": -742870190 + }, + "name": "517-521 Huntington Drive, Manchester Township, NJ 08759, USA" +}, { + "location": { + "latitude": 400066188, + "longitude": -746793294 + }, + "name": "" +}, { + "location": { + "latitude": 418803880, + "longitude": -744102673 + }, + "name": "40 Mountain Road, Napanoch, NY 12458, USA" +}, { + "location": { + "latitude": 414204288, + "longitude": -747895140 + }, + "name": "" +}, { + "location": { + "latitude": 414777405, + "longitude": -740615601 + }, + "name": "" +}, { + "location": { + "latitude": 415464475, + "longitude": -747175374 + }, + "name": "48 North Road, Forestburgh, NY 12777, USA" +}, { + "location": { + "latitude": 404062378, + "longitude": -746376177 + }, + "name": "" +}, { + "location": { + "latitude": 405688272, + "longitude": -749285130 + }, + "name": "" +}, { + "location": { + "latitude": 400342070, + "longitude": -748788996 + }, + "name": "" +}, { + "location": { + "latitude": 401809022, + "longitude": -744157964 + }, + "name": "" +}, { + "location": { + "latitude": 404226644, + "longitude": -740517141 + }, + "name": "9 Thompson Avenue, Leonardo, NJ 07737, USA" +}, { + "location": { + "latitude": 410322033, + "longitude": -747871659 + }, + "name": "" +}, { + "location": { + "latitude": 407100674, + "longitude": -747742727 + }, + "name": "" +}, { + "location": { + "latitude": 418811433, + "longitude": -741718005 + }, + "name": "213 Bush Road, Stone Ridge, NY 12484, USA" +}, { + "location": { + "latitude": 415034302, + "longitude": -743850945 + }, + "name": "" +}, { + "location": { + "latitude": 411349992, + "longitude": -743694161 + }, + "name": "" +}, { + "location": { + "latitude": 404839914, + "longitude": -744759616 + }, + "name": "1-17 Bergen Court, New Brunswick, NJ 08901, USA" +}, { + "location": { + "latitude": 414638017, + "longitude": -745957854 + }, + "name": "35 Oakland Valley Road, Cuddebackville, NY 12729, USA" +}, { + "location": { + "latitude": 412127800, + "longitude": -740173578 + }, + "name": "" +}, { + "location": { + "latitude": 401263460, + "longitude": -747964303 + }, + "name": "" +}, { + "location": { + "latitude": 412843391, + "longitude": -749086026 + }, + "name": "" +}, { + "location": { + "latitude": 418512773, + "longitude": -743067823 + }, + "name": "" +}, { + "location": { + "latitude": 404318328, + "longitude": -740835638 + }, + "name": "42-102 Main Street, Belford, NJ 07718, USA" +}, { + "location": { + "latitude": 419020746, + "longitude": -741172328 + }, + "name": "" +}, { + "location": { + "latitude": 404080723, + "longitude": -746119569 + }, + "name": "" +}, { + "location": { + "latitude": 401012643, + "longitude": -744035134 + }, + "name": "" +}, { + "location": { + "latitude": 404306372, + "longitude": -741079661 + }, + "name": "" +}, { + "location": { + "latitude": 403966326, + "longitude": -748519297 + }, + "name": "" +}, { + "location": { + "latitude": 405002031, + "longitude": -748407866 + }, + "name": "" +}, { + "location": { + "latitude": 409532885, + "longitude": -742200683 + }, + "name": "" +}, { + "location": { + "latitude": 416851321, + "longitude": -742674555 + }, + "name": "" +}, { + "location": { + "latitude": 406411633, + "longitude": -741722051 + }, + "name": "3387 Richmond Terrace, Staten Island, NY 10303, USA" +}, { + "location": { + "latitude": 413069058, + "longitude": -744597778 + }, + "name": "261 Van Sickle Road, Goshen, NY 10924, USA" +}, { + "location": { + "latitude": 418465462, + "longitude": -746859398 + }, + "name": "" +}, { + "location": { + "latitude": 411733222, + "longitude": -744228360 + }, + "name": "" +}, { + "location": { + "latitude": 410248224, + "longitude": -747127767 + }, + "name": "3 Hasta Way, Newton, NJ 07860, USA" +}] diff --git a/src/node/examples/route_guide_server.js b/src/node/examples/route_guide_server.js new file mode 100644 index 0000000000..bc9ed25101 --- /dev/null +++ b/src/node/examples/route_guide_server.js @@ -0,0 +1,249 @@ +// 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 fs = require('fs'); +var parseArgs = require('minimist'); +var path = require('path'); +var _ = require('underscore'); +var grpc = require('..'); +var examples = grpc.load(__dirname + '/route_guide.proto').examples; + +var Server = grpc.buildServer([examples.RouteGuide.service]); + +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.location.latitude === point.latitude && + feature.location.longitude === point.longitude) { + return feature; + } + } + var name = ''; + feature = { + name: name, + location: 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.lo; + var hi = call.request.hi; + var left = _.min([lo.longitude, hi.longitude]); + var right = _.max([lo.longitude, hi.longitude]); + var top = _.max([lo.latitude, hi.latitude]); + var bottom = _.min([lo.latitude, hi.latitude]); + // For each feature, check if it is in the given bounding box + _.each(feature_list, function(feature) { + if (feature.name === '') { + return; + } + if (feature.location.longitude >= left && + feature.location.longitude <= right && + feature.location.latitude >= bottom && + feature.location.latitude <= 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.latitude / COORD_FACTOR; + var lat2 = end.latitude / COORD_FACTOR; + var lon1 = start.longitude / COORD_FACTOR; + var lon2 = end.longitude / 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() { + callback(null, { + point_count: point_count, + feature_count: feature_count, + // Cast the distance to an integer + distance: distance|0, + // End the timer + elapsed_time: process.hrtime(start_time)[0] + }); + }); +} + +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.latitude + ' ' + point.longitude; +} + +/** + * 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.location); + /* 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(JSON.parse(JSON.stringify(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() { + return new Server({ + 'examples.RouteGuide' : { + getFeature: getFeature, + listFeatures: listFeatures, + recordRoute: recordRoute, + routeChat: routeChat + } + }); +} + +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'); + var argv = parseArgs(process.argv, { + string: 'db_path' + }); + fs.readFile(path.resolve(argv.db_path), function(err, data) { + if (err) throw err; + feature_list = JSON.parse(data); + routeServer.listen(); + }); +} + +exports.getServer = getServer; diff --git a/src/node/interop/empty.proto b/src/node/interop/empty.proto index f66a108c19..4295a0a960 100644 --- a/src/node/interop/empty.proto +++ b/src/node/interop/empty.proto @@ -40,10 +40,4 @@ package grpc.testing; // rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { }; // }; // -// MOE:begin_strip -// The difference between this one and net/rpc/empty-message.proto is that -// 1) The generated message here is in proto2 C++ API. -// 2) The proto2.Empty has minimum dependencies -// (no message_set or net/rpc dependencies) -// MOE:end_strip message Empty {} diff --git a/src/node/package.json b/src/node/package.json index fe51c4736e..e6ac550554 100644 --- a/src/node/package.json +++ b/src/node/package.json @@ -15,6 +15,7 @@ "underscore.string": "^3.0.0" }, "devDependencies": { + "async": "^0.9.0", "googleauth": "google/google-auth-library-nodejs", "minimist": "^1.1.0", "mocha": "~1.21.0", |