mirror of https://github.com/grpc/grpc.git
Merge pull request #121 from grpc/grpc_samples_ruby_route_guide_doc
Grpc samples ruby route guide docpull/3109/head
commit
bbe7958b34
17 changed files with 1939 additions and 72 deletions
@ -0,0 +1 @@ |
||||
*.pyc |
@ -0,0 +1,119 @@ |
||||
// 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 = "proto2"; |
||||
|
||||
//TODO: see https://github.com/grpc/grpc/issues/814 |
||||
//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; |
||||
} |
@ -0,0 +1,131 @@ |
||||
# 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. |
||||
|
||||
"""The Python implementation of the gRPC route guide client.""" |
||||
|
||||
import random |
||||
import time |
||||
|
||||
import route_guide_pb2 |
||||
import route_guide_resources |
||||
|
||||
_TIMEOUT_SECONDS = 30 |
||||
|
||||
|
||||
def make_route_note(message, latitude, longitude): |
||||
route_note = route_guide_pb2.RouteNote(message=message) |
||||
route_note.location.latitude = latitude |
||||
route_note.location.longitude = longitude |
||||
return route_note |
||||
|
||||
|
||||
def guide_get_one_feature(stub, point): |
||||
feature = stub.GetFeature(point, _TIMEOUT_SECONDS) |
||||
if not feature.location: |
||||
print "Server returned incomplete feature" |
||||
return |
||||
|
||||
if feature.name: |
||||
print "Feature called %s at %s" % (feature.name, feature.location) |
||||
else: |
||||
print "Found no feature at %s" % feature.location |
||||
|
||||
|
||||
def guide_get_feature(stub): |
||||
guide_get_one_feature(stub, route_guide_pb2.Point(latitude=409146138, longitude=-746188906)) |
||||
guide_get_one_feature(stub, route_guide_pb2.Point(latitude=0, longitude=0)) |
||||
|
||||
|
||||
def guide_list_features(stub): |
||||
rect = route_guide_pb2.Rectangle() |
||||
rect.lo.latitude = 400000000 |
||||
rect.lo.longitude = -750000000 |
||||
rect.hi.latitude = 420000000 |
||||
rect.hi.longitude = -730000000 |
||||
print "Looking for features between 40, -75 and 42, -73" |
||||
|
||||
features = stub.ListFeatures(rect, _TIMEOUT_SECONDS) |
||||
|
||||
for feature in features: |
||||
print "Feature called %s at %s" % (feature.name, feature.location) |
||||
|
||||
|
||||
def generate_route(feature_list): |
||||
for _ in range(0, 10): |
||||
random_feature = feature_list[random.randint(0, len(feature_list) - 1)] |
||||
print "Visiting point %s" % random_feature.location |
||||
yield random_feature.location |
||||
time.sleep(random.uniform(0.5, 1.5)) |
||||
|
||||
|
||||
def guide_record_route(stub): |
||||
feature_list = route_guide_resources.read_route_guide_database() |
||||
|
||||
route_iter = generate_route(feature_list) |
||||
route_summary = stub.RecordRoute(route_iter, _TIMEOUT_SECONDS) |
||||
print "Finished trip with %s points " % route_summary.point_count |
||||
print "Passed %s features " % route_summary.feature_count |
||||
print "Travelled %s meters " % route_summary.distance |
||||
print "It took %s seconds " % route_summary.elapsed_time |
||||
|
||||
|
||||
def generate_messages(): |
||||
messages = [ |
||||
make_route_note("First message", 0, 0), |
||||
make_route_note("Second message", 0, 1), |
||||
make_route_note("Third message", 1, 0), |
||||
make_route_note("Fourth message", 0, 0), |
||||
make_route_note("Fifth message", 1, 0), |
||||
] |
||||
for msg in messages: |
||||
print "Sending %s at %s" % (msg.message, msg.location) |
||||
yield msg |
||||
time.sleep(random.uniform(0.5, 1.0)) |
||||
|
||||
|
||||
def guide_route_chat(stub): |
||||
responses = stub.RouteChat(generate_messages(), _TIMEOUT_SECONDS) |
||||
for response in responses: |
||||
print "Received message %s at %s" % (response.message, response.location) |
||||
|
||||
|
||||
def run(): |
||||
with route_guide_pb2.early_adopter_create_RouteGuide_stub('localhost', 50051) as stub: |
||||
print "-------------- GetFeature --------------" |
||||
guide_get_feature(stub); |
||||
print "-------------- ListFeatures --------------" |
||||
guide_list_features(stub); |
||||
print "-------------- RecordRoute --------------" |
||||
guide_record_route(stub); |
||||
print "-------------- RouteChat --------------" |
||||
guide_route_chat(stub); |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
run() |
@ -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" |
||||
}] |
@ -0,0 +1,370 @@ |
||||
# Generated by the protocol buffer compiler. DO NOT EDIT! |
||||
# source: route_guide.proto |
||||
|
||||
import sys |
||||
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) |
||||
from google.protobuf import descriptor as _descriptor |
||||
from google.protobuf import message as _message |
||||
from google.protobuf import reflection as _reflection |
||||
from google.protobuf import symbol_database as _symbol_database |
||||
from google.protobuf import descriptor_pb2 |
||||
# @@protoc_insertion_point(imports) |
||||
|
||||
_sym_db = _symbol_database.Default() |
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor( |
||||
name='route_guide.proto', |
||||
package='', |
||||
serialized_pb=_b('\n\x11route_guide.proto\",\n\x05Point\x12\x10\n\x08latitude\x18\x01 \x01(\x05\x12\x11\n\tlongitude\x18\x02 \x01(\x05\"3\n\tRectangle\x12\x12\n\x02lo\x18\x01 \x01(\x0b\x32\x06.Point\x12\x12\n\x02hi\x18\x02 \x01(\x0b\x32\x06.Point\"1\n\x07\x46\x65\x61ture\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x18\n\x08location\x18\x02 \x01(\x0b\x32\x06.Point\"6\n\tRouteNote\x12\x18\n\x08location\x18\x01 \x01(\x0b\x32\x06.Point\x12\x0f\n\x07message\x18\x02 \x01(\t\"b\n\x0cRouteSummary\x12\x13\n\x0bpoint_count\x18\x01 \x01(\x05\x12\x15\n\rfeature_count\x18\x02 \x01(\x05\x12\x10\n\x08\x64istance\x18\x03 \x01(\x05\x12\x14\n\x0c\x65lapsed_time\x18\x04 \x01(\x05\x32\xad\x01\n\nRouteGuide\x12 \n\nGetFeature\x12\x06.Point\x1a\x08.Feature\"\x00\x12(\n\x0cListFeatures\x12\n.Rectangle\x1a\x08.Feature\"\x00\x30\x01\x12(\n\x0bRecordRoute\x12\x06.Point\x1a\r.RouteSummary\"\x00(\x01\x12)\n\tRouteChat\x12\n.RouteNote\x1a\n.RouteNote\"\x00(\x01\x30\x01') |
||||
) |
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR) |
||||
|
||||
|
||||
|
||||
|
||||
_POINT = _descriptor.Descriptor( |
||||
name='Point', |
||||
full_name='Point', |
||||
filename=None, |
||||
file=DESCRIPTOR, |
||||
containing_type=None, |
||||
fields=[ |
||||
_descriptor.FieldDescriptor( |
||||
name='latitude', full_name='Point.latitude', index=0, |
||||
number=1, type=5, cpp_type=1, label=1, |
||||
has_default_value=False, default_value=0, |
||||
message_type=None, enum_type=None, containing_type=None, |
||||
is_extension=False, extension_scope=None, |
||||
options=None), |
||||
_descriptor.FieldDescriptor( |
||||
name='longitude', full_name='Point.longitude', index=1, |
||||
number=2, type=5, cpp_type=1, label=1, |
||||
has_default_value=False, default_value=0, |
||||
message_type=None, enum_type=None, containing_type=None, |
||||
is_extension=False, extension_scope=None, |
||||
options=None), |
||||
], |
||||
extensions=[ |
||||
], |
||||
nested_types=[], |
||||
enum_types=[ |
||||
], |
||||
options=None, |
||||
is_extendable=False, |
||||
extension_ranges=[], |
||||
oneofs=[ |
||||
], |
||||
serialized_start=21, |
||||
serialized_end=65, |
||||
) |
||||
|
||||
|
||||
_RECTANGLE = _descriptor.Descriptor( |
||||
name='Rectangle', |
||||
full_name='Rectangle', |
||||
filename=None, |
||||
file=DESCRIPTOR, |
||||
containing_type=None, |
||||
fields=[ |
||||
_descriptor.FieldDescriptor( |
||||
name='lo', full_name='Rectangle.lo', index=0, |
||||
number=1, type=11, cpp_type=10, label=1, |
||||
has_default_value=False, default_value=None, |
||||
message_type=None, enum_type=None, containing_type=None, |
||||
is_extension=False, extension_scope=None, |
||||
options=None), |
||||
_descriptor.FieldDescriptor( |
||||
name='hi', full_name='Rectangle.hi', index=1, |
||||
number=2, type=11, cpp_type=10, label=1, |
||||
has_default_value=False, default_value=None, |
||||
message_type=None, enum_type=None, containing_type=None, |
||||
is_extension=False, extension_scope=None, |
||||
options=None), |
||||
], |
||||
extensions=[ |
||||
], |
||||
nested_types=[], |
||||
enum_types=[ |
||||
], |
||||
options=None, |
||||
is_extendable=False, |
||||
extension_ranges=[], |
||||
oneofs=[ |
||||
], |
||||
serialized_start=67, |
||||
serialized_end=118, |
||||
) |
||||
|
||||
|
||||
_FEATURE = _descriptor.Descriptor( |
||||
name='Feature', |
||||
full_name='Feature', |
||||
filename=None, |
||||
file=DESCRIPTOR, |
||||
containing_type=None, |
||||
fields=[ |
||||
_descriptor.FieldDescriptor( |
||||
name='name', full_name='Feature.name', index=0, |
||||
number=1, type=9, cpp_type=9, label=1, |
||||
has_default_value=False, default_value=_b("").decode('utf-8'), |
||||
message_type=None, enum_type=None, containing_type=None, |
||||
is_extension=False, extension_scope=None, |
||||
options=None), |
||||
_descriptor.FieldDescriptor( |
||||
name='location', full_name='Feature.location', index=1, |
||||
number=2, type=11, cpp_type=10, label=1, |
||||
has_default_value=False, default_value=None, |
||||
message_type=None, enum_type=None, containing_type=None, |
||||
is_extension=False, extension_scope=None, |
||||
options=None), |
||||
], |
||||
extensions=[ |
||||
], |
||||
nested_types=[], |
||||
enum_types=[ |
||||
], |
||||
options=None, |
||||
is_extendable=False, |
||||
extension_ranges=[], |
||||
oneofs=[ |
||||
], |
||||
serialized_start=120, |
||||
serialized_end=169, |
||||
) |
||||
|
||||
|
||||
_ROUTENOTE = _descriptor.Descriptor( |
||||
name='RouteNote', |
||||
full_name='RouteNote', |
||||
filename=None, |
||||
file=DESCRIPTOR, |
||||
containing_type=None, |
||||
fields=[ |
||||
_descriptor.FieldDescriptor( |
||||
name='location', full_name='RouteNote.location', index=0, |
||||
number=1, type=11, cpp_type=10, label=1, |
||||
has_default_value=False, default_value=None, |
||||
message_type=None, enum_type=None, containing_type=None, |
||||
is_extension=False, extension_scope=None, |
||||
options=None), |
||||
_descriptor.FieldDescriptor( |
||||
name='message', full_name='RouteNote.message', index=1, |
||||
number=2, type=9, cpp_type=9, label=1, |
||||
has_default_value=False, default_value=_b("").decode('utf-8'), |
||||
message_type=None, enum_type=None, containing_type=None, |
||||
is_extension=False, extension_scope=None, |
||||
options=None), |
||||
], |
||||
extensions=[ |
||||
], |
||||
nested_types=[], |
||||
enum_types=[ |
||||
], |
||||
options=None, |
||||
is_extendable=False, |
||||
extension_ranges=[], |
||||
oneofs=[ |
||||
], |
||||
serialized_start=171, |
||||
serialized_end=225, |
||||
) |
||||
|
||||
|
||||
_ROUTESUMMARY = _descriptor.Descriptor( |
||||
name='RouteSummary', |
||||
full_name='RouteSummary', |
||||
filename=None, |
||||
file=DESCRIPTOR, |
||||
containing_type=None, |
||||
fields=[ |
||||
_descriptor.FieldDescriptor( |
||||
name='point_count', full_name='RouteSummary.point_count', index=0, |
||||
number=1, type=5, cpp_type=1, label=1, |
||||
has_default_value=False, default_value=0, |
||||
message_type=None, enum_type=None, containing_type=None, |
||||
is_extension=False, extension_scope=None, |
||||
options=None), |
||||
_descriptor.FieldDescriptor( |
||||
name='feature_count', full_name='RouteSummary.feature_count', index=1, |
||||
number=2, type=5, cpp_type=1, label=1, |
||||
has_default_value=False, default_value=0, |
||||
message_type=None, enum_type=None, containing_type=None, |
||||
is_extension=False, extension_scope=None, |
||||
options=None), |
||||
_descriptor.FieldDescriptor( |
||||
name='distance', full_name='RouteSummary.distance', index=2, |
||||
number=3, type=5, cpp_type=1, label=1, |
||||
has_default_value=False, default_value=0, |
||||
message_type=None, enum_type=None, containing_type=None, |
||||
is_extension=False, extension_scope=None, |
||||
options=None), |
||||
_descriptor.FieldDescriptor( |
||||
name='elapsed_time', full_name='RouteSummary.elapsed_time', index=3, |
||||
number=4, type=5, cpp_type=1, label=1, |
||||
has_default_value=False, default_value=0, |
||||
message_type=None, enum_type=None, containing_type=None, |
||||
is_extension=False, extension_scope=None, |
||||
options=None), |
||||
], |
||||
extensions=[ |
||||
], |
||||
nested_types=[], |
||||
enum_types=[ |
||||
], |
||||
options=None, |
||||
is_extendable=False, |
||||
extension_ranges=[], |
||||
oneofs=[ |
||||
], |
||||
serialized_start=227, |
||||
serialized_end=325, |
||||
) |
||||
|
||||
_RECTANGLE.fields_by_name['lo'].message_type = _POINT |
||||
_RECTANGLE.fields_by_name['hi'].message_type = _POINT |
||||
_FEATURE.fields_by_name['location'].message_type = _POINT |
||||
_ROUTENOTE.fields_by_name['location'].message_type = _POINT |
||||
DESCRIPTOR.message_types_by_name['Point'] = _POINT |
||||
DESCRIPTOR.message_types_by_name['Rectangle'] = _RECTANGLE |
||||
DESCRIPTOR.message_types_by_name['Feature'] = _FEATURE |
||||
DESCRIPTOR.message_types_by_name['RouteNote'] = _ROUTENOTE |
||||
DESCRIPTOR.message_types_by_name['RouteSummary'] = _ROUTESUMMARY |
||||
|
||||
Point = _reflection.GeneratedProtocolMessageType('Point', (_message.Message,), dict( |
||||
DESCRIPTOR = _POINT, |
||||
__module__ = 'route_guide_pb2' |
||||
# @@protoc_insertion_point(class_scope:Point) |
||||
)) |
||||
_sym_db.RegisterMessage(Point) |
||||
|
||||
Rectangle = _reflection.GeneratedProtocolMessageType('Rectangle', (_message.Message,), dict( |
||||
DESCRIPTOR = _RECTANGLE, |
||||
__module__ = 'route_guide_pb2' |
||||
# @@protoc_insertion_point(class_scope:Rectangle) |
||||
)) |
||||
_sym_db.RegisterMessage(Rectangle) |
||||
|
||||
Feature = _reflection.GeneratedProtocolMessageType('Feature', (_message.Message,), dict( |
||||
DESCRIPTOR = _FEATURE, |
||||
__module__ = 'route_guide_pb2' |
||||
# @@protoc_insertion_point(class_scope:Feature) |
||||
)) |
||||
_sym_db.RegisterMessage(Feature) |
||||
|
||||
RouteNote = _reflection.GeneratedProtocolMessageType('RouteNote', (_message.Message,), dict( |
||||
DESCRIPTOR = _ROUTENOTE, |
||||
__module__ = 'route_guide_pb2' |
||||
# @@protoc_insertion_point(class_scope:RouteNote) |
||||
)) |
||||
_sym_db.RegisterMessage(RouteNote) |
||||
|
||||
RouteSummary = _reflection.GeneratedProtocolMessageType('RouteSummary', (_message.Message,), dict( |
||||
DESCRIPTOR = _ROUTESUMMARY, |
||||
__module__ = 'route_guide_pb2' |
||||
# @@protoc_insertion_point(class_scope:RouteSummary) |
||||
)) |
||||
_sym_db.RegisterMessage(RouteSummary) |
||||
|
||||
|
||||
import abc |
||||
from grpc._adapter import fore |
||||
from grpc._adapter import rear |
||||
from grpc.framework.assembly import implementations |
||||
from grpc.framework.assembly import utilities |
||||
class EarlyAdopterRouteGuideServicer(object): |
||||
"""<fill me in later!>""" |
||||
__metaclass__ = abc.ABCMeta |
||||
@abc.abstractmethod |
||||
def GetFeature(self, request): |
||||
raise NotImplementedError() |
||||
@abc.abstractmethod |
||||
def ListFeatures(self, request): |
||||
raise NotImplementedError() |
||||
@abc.abstractmethod |
||||
def RecordRoute(self, request_iterator): |
||||
raise NotImplementedError() |
||||
@abc.abstractmethod |
||||
def RouteChat(self, request_iterator): |
||||
raise NotImplementedError() |
||||
class EarlyAdopterRouteGuideServer(object): |
||||
"""<fill me in later!>""" |
||||
__metaclass__ = abc.ABCMeta |
||||
@abc.abstractmethod |
||||
def start(self): |
||||
raise NotImplementedError() |
||||
@abc.abstractmethod |
||||
def stop(self): |
||||
raise NotImplementedError() |
||||
class EarlyAdopterRouteGuideStub(object): |
||||
"""<fill me in later!>""" |
||||
__metaclass__ = abc.ABCMeta |
||||
@abc.abstractmethod |
||||
def GetFeature(self, request): |
||||
raise NotImplementedError() |
||||
GetFeature.async = None |
||||
@abc.abstractmethod |
||||
def ListFeatures(self, request): |
||||
raise NotImplementedError() |
||||
ListFeatures.async = None |
||||
@abc.abstractmethod |
||||
def RecordRoute(self, request_iterator): |
||||
raise NotImplementedError() |
||||
RecordRoute.async = None |
||||
@abc.abstractmethod |
||||
def RouteChat(self, request_iterator): |
||||
raise NotImplementedError() |
||||
RouteChat.async = None |
||||
def early_adopter_create_RouteGuide_server(servicer, port, root_certificates, key_chain_pairs): |
||||
method_implementations = { |
||||
"GetFeature": utilities.unary_unary_inline(servicer.GetFeature), |
||||
"ListFeatures": utilities.unary_stream_inline(servicer.ListFeatures), |
||||
"RecordRoute": utilities.stream_unary_inline(servicer.RecordRoute), |
||||
"RouteChat": utilities.stream_stream_inline(servicer.RouteChat), |
||||
} |
||||
import route_guide_pb2 |
||||
import route_guide_pb2 |
||||
import route_guide_pb2 |
||||
import route_guide_pb2 |
||||
request_deserializers = { |
||||
"GetFeature": route_guide_pb2.Point.FromString, |
||||
"ListFeatures": route_guide_pb2.Rectangle.FromString, |
||||
"RecordRoute": route_guide_pb2.Point.FromString, |
||||
"RouteChat": route_guide_pb2.RouteNote.FromString, |
||||
} |
||||
response_serializers = { |
||||
"GetFeature": lambda x: x.SerializeToString(), |
||||
"ListFeatures": lambda x: x.SerializeToString(), |
||||
"RecordRoute": lambda x: x.SerializeToString(), |
||||
"RouteChat": lambda x: x.SerializeToString(), |
||||
} |
||||
link = fore.activated_fore_link(port, request_deserializers, response_serializers, root_certificates, key_chain_pairs) |
||||
return implementations.assemble_service(method_implementations, link) |
||||
def early_adopter_create_RouteGuide_stub(host, port): |
||||
method_implementations = { |
||||
"GetFeature": utilities.unary_unary_inline(None), |
||||
"ListFeatures": utilities.unary_stream_inline(None), |
||||
"RecordRoute": utilities.stream_unary_inline(None), |
||||
"RouteChat": utilities.stream_stream_inline(None), |
||||
} |
||||
import route_guide_pb2 |
||||
import route_guide_pb2 |
||||
import route_guide_pb2 |
||||
import route_guide_pb2 |
||||
response_deserializers = { |
||||
"GetFeature": route_guide_pb2.Feature.FromString, |
||||
"ListFeatures": route_guide_pb2.Feature.FromString, |
||||
"RecordRoute": route_guide_pb2.RouteSummary.FromString, |
||||
"RouteChat": route_guide_pb2.RouteNote.FromString, |
||||
} |
||||
request_serializers = { |
||||
"GetFeature": lambda x: x.SerializeToString(), |
||||
"ListFeatures": lambda x: x.SerializeToString(), |
||||
"RecordRoute": lambda x: x.SerializeToString(), |
||||
"RouteChat": lambda x: x.SerializeToString(), |
||||
} |
||||
link = rear.activated_rear_link(host, port, request_serializers, response_deserializers) |
||||
return implementations.assemble_dynamic_inline_stub(method_implementations, link) |
||||
# @@protoc_insertion_point(module_scope) |
@ -0,0 +1,53 @@ |
||||
# 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. |
||||
|
||||
"""Common resources used in the gRPC route guide example.""" |
||||
|
||||
import json |
||||
|
||||
import route_guide_pb2 |
||||
|
||||
|
||||
def read_route_guide_database(): |
||||
"""Reads the route guide database. |
||||
|
||||
Returns: |
||||
The full contents of the route guide database as a sequence of |
||||
route_guide_pb2.Features. |
||||
""" |
||||
feature_list = [] |
||||
with open("route_guide_db.json") as route_guide_db_file: |
||||
for item in json.load(route_guide_db_file): |
||||
feature = route_guide_pb2.Feature( |
||||
name=item["name"], |
||||
location=route_guide_pb2.Point( |
||||
latitude=item["location"]["latitude"], |
||||
longitude=item["location"]["longitude"])) |
||||
feature_list.append(feature) |
||||
return feature_list |
@ -0,0 +1,138 @@ |
||||
# 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. |
||||
|
||||
"""The Python implementation of the gRPC route guide server.""" |
||||
|
||||
import time |
||||
import math |
||||
|
||||
import route_guide_pb2 |
||||
import route_guide_resources |
||||
|
||||
_ONE_DAY_IN_SECONDS = 60 * 60 * 24 |
||||
|
||||
|
||||
def get_feature(feature_db, point): |
||||
"""Returns Feature at given location or None.""" |
||||
for feature in feature_db: |
||||
if feature.location == point: |
||||
return feature |
||||
return None |
||||
|
||||
|
||||
def get_distance(start, end): |
||||
"""Distance between two points.""" |
||||
coord_factor = 10000000.0 |
||||
lat_1 = start.latitude / coord_factor |
||||
lat_2 = end.latitude / coord_factor |
||||
lon_1 = start.latitude / coord_factor |
||||
lon_2 = end.longitude / coord_factor |
||||
lat_rad_1 = math.radians(lat_1) |
||||
lat_rad_2 = math.radians(lat_2) |
||||
delta_lat_rad = math.radians(lat_2 - lat_1) |
||||
delta_lon_rad = math.radians(lon_2 - lon_1) |
||||
|
||||
a = (pow(math.sin(delta_lat_rad / 2), 2) + |
||||
(math.cos(lat_rad_1) * math.cos(lat_rad_2) * |
||||
pow(math.sin(delta_lon_rad / 2), 2))) |
||||
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)) |
||||
R = 6371000; # metres |
||||
return R * c; |
||||
|
||||
class RouteGuideServicer(route_guide_pb2.EarlyAdopterRouteGuideServicer): |
||||
"""Provides methods that implement functionality of route guide server.""" |
||||
|
||||
def __init__(self): |
||||
self.db = route_guide_resources.read_route_guide_database() |
||||
|
||||
def GetFeature(self, request, context): |
||||
feature = get_feature(self.db, request) |
||||
if not feature: |
||||
feature = route_guide_pb2.Feature( |
||||
name="", |
||||
location=route_guide_pb2.Point( |
||||
latitude=request.latitude, longitude=request.longitude)) |
||||
return feature |
||||
|
||||
def ListFeatures(self, request, context): |
||||
lo = request.lo |
||||
hi = request.hi |
||||
left = min(lo.longitude, hi.longitude) |
||||
right = max(lo.longitude, hi.longitude) |
||||
top = max(lo.latitude, hi.latitude) |
||||
bottom = min(lo.latitude, hi.latitude) |
||||
for feature in self.db: |
||||
if (feature.location.longitude >= left and |
||||
feature.location.longitude <= right and |
||||
feature.location.latitude >= bottom and |
||||
feature.location.latitude <= top): |
||||
yield feature |
||||
|
||||
def RecordRoute(self, request_iterator, context): |
||||
point_count = 0 |
||||
feature_count = 0 |
||||
distance = 0.0 |
||||
prev_point = None |
||||
|
||||
start_time = time.time() |
||||
for point in request_iterator: |
||||
point_count += 1 |
||||
if get_feature(self.db, point): |
||||
feature_count += 1 |
||||
if prev_point: |
||||
distance += get_distance(prev_point, point) |
||||
prev_point = point |
||||
|
||||
elapsed_time = time.time() - start_time |
||||
return route_guide_pb2.RouteSummary(point_count=point_count, |
||||
feature_count=feature_count, |
||||
distance=int(distance), |
||||
elapsed_time=int(elapsed_time)) |
||||
|
||||
def RouteChat(self, request_iterator, context): |
||||
prev_notes = [] |
||||
for new_note in request_iterator: |
||||
for prev_note in prev_notes: |
||||
if prev_note.location == new_note.location: |
||||
yield prev_note |
||||
prev_notes.append(new_note) |
||||
|
||||
|
||||
def serve(): |
||||
server = route_guide_pb2.early_adopter_create_RouteGuide_server( |
||||
RouteGuideServicer(), 50051, None, None) |
||||
server.start() |
||||
try: |
||||
while True: |
||||
time.sleep(_ONE_DAY_IN_SECONDS) |
||||
except KeyboardInterrupt: |
||||
server.stop() |
||||
|
||||
if __name__ == '__main__': |
||||
serve() |
@ -0,0 +1,8 @@ |
||||
#!/bin/bash |
||||
|
||||
# This is where you have cloned out the https://github.com/grpc/grpc repository |
||||
# And built gRPC Python. |
||||
# ADJUST THIS PATH TO WHERE YOUR ACTUAL LOCATION IS |
||||
GRPC_ROOT=~/github/grpc |
||||
|
||||
$GRPC_ROOT/python2.7_virtual_environment/bin/python -B route_guide_client.py |
@ -0,0 +1,4 @@ |
||||
#!/bin/bash |
||||
|
||||
# Runs the protoc with gRPC plugin to generate protocol messages and gRPC stubs. |
||||
protoc -I . --python_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_python_plugin` route_guide.proto |
@ -0,0 +1,8 @@ |
||||
#!/bin/bash |
||||
|
||||
# This is where you have cloned out the https://github.com/grpc/grpc repository |
||||
# And built gRPC Python. |
||||
# ADJUST THIS PATH TO WHERE YOUR ACTUAL LOCATION IS |
||||
GRPC_ROOT=~/github/grpc |
||||
|
||||
$GRPC_ROOT/python2.7_virtual_environment/bin/python -B route_guide_server.py |
@ -0,0 +1,285 @@ |
||||
#gRPC Basics: Ruby |
||||
|
||||
This tutorial provides a basic Ruby programmer's introduction to working with gRPC. By walking through this example you'll learn how to: |
||||
|
||||
- Define a service in a .proto file. |
||||
- Generate server and client code using the protocol buffer compiler. |
||||
- Use the Ruby gRPC API to write a simple client and server for your service. |
||||
|
||||
It assumes that you have read the [Getting started](https://github.com/grpc/grpc-common) guide and are familiar with [protocol buffers] (https://developers.google.com/protocol-buffers/docs/overview). Note that the example in this tutorial uses the proto3 version of the protocol buffers language, which is currently in alpha release: you can see the [release notes](https://github.com/google/protobuf/releases) for the new version in the protocol buffers Github repository. |
||||
|
||||
This isn't a comprehensive guide to using gRPC in Ruby: more reference documentation is coming soon. |
||||
|
||||
## Why use gRPC? |
||||
|
||||
Our example is a simple route mapping application that lets clients get information about features on their route, create a summary of their route, and exchange route information such as traffic updates with the server and other clients. |
||||
|
||||
With gRPC we can define our service once in a .proto file and implement clients and servers in any of gRPC's supported languages, which in turn can be run in environments ranging from servers inside Google to your own tablet - all the complexity of communication between different languages and environments is handled for you by gRPC. We also get all the advantages of working with protocol buffers, including efficient serialization, a simple IDL, and easy interface updating. |
||||
|
||||
## Example code and setup |
||||
|
||||
The example code for our tutorial is in [grpc/grpc-common/ruby/route_guide](https://github.com/grpc/grpc-common/tree/master/ruby/route_guide). To download the example, clone the `grpc-common` repository by running the following command: |
||||
```shell |
||||
$ git clone https://github.com/google/grpc-common.git |
||||
``` |
||||
|
||||
Then change your current directory to `grpc-common/ruby/route_guide`: |
||||
```shell |
||||
$ cd grpc-common/ruby/route_guide |
||||
``` |
||||
|
||||
You also should have the relevant tools installed to generate the server and client interface code - if you don't already, follow the setup instructions in [the Ruby quick start guide](https://github.com/grpc/grpc-common/tree/master/ruby). |
||||
|
||||
|
||||
## Defining the service |
||||
|
||||
Our first step (as you'll know from [Getting started](https://github.com/grpc/grpc-common)) is to define the gRPC *service* and the method *request* and *response* types using [protocol buffers] (https://developers.google.com/protocol-buffers/docs/overview). You can see the complete .proto file in [`grpc-common/protos/route_guide.proto`](https://github.com/grpc/grpc-common/blob/master/protos/route_guide.proto). |
||||
|
||||
To define a service, you specify a named `service` in your .proto file: |
||||
|
||||
```protobuf |
||||
service RouteGuide { |
||||
... |
||||
} |
||||
``` |
||||
|
||||
Then you define `rpc` methods inside your service definition, specifying their request and response types. gRPC lets you define four kinds of service method, all of which are used in the `RouteGuide` service: |
||||
|
||||
- A *simple RPC* where the client sends a request to the server using the stub and waits for a response to come back, just like a normal function call. |
||||
```protobuf |
||||
// Obtains the feature at a given position. |
||||
rpc GetFeature(Point) returns (Feature) {} |
||||
``` |
||||
|
||||
- A *server-side streaming RPC* where the client sends a request to the server and gets a stream to read a sequence of messages back. The client reads from the returned stream until there are no more messages. As you can see in our example, you specify a server-side streaming method by placing the `stream` keyword before the *response* type. |
||||
```protobuf |
||||
// 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-side streaming RPC* where the client writes a sequence of messages and sends them to the server, again using a provided stream. Once the client has finished writing the messages, it waits for the server to read them all and return its response. You specify a server-side streaming method by placing the `stream` keyword before the *request* type. |
||||
```protobuf |
||||
// 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* where both sides send a sequence of messages using a read-write stream. The two streams operate independently, so clients and servers can read and write in whatever order they like: for example, the server could wait to receive all the client messages before writing its responses, or it could alternately read a message then write a message, or some other combination of reads and writes. The order of messages in each stream is preserved. You specify this type of method by placing the `stream` keyword before both the request and the response. |
||||
```protobuf |
||||
// 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) {} |
||||
``` |
||||
|
||||
Our .proto file also contains protocol buffer message type definitions for all the request and response types used in our service methods - for example, here's the `Point` message type: |
||||
```protobuf |
||||
// 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 { |
||||
int32 latitude = 1; |
||||
int32 longitude = 2; |
||||
} |
||||
``` |
||||
|
||||
|
||||
## Generating client and server code |
||||
|
||||
Next we need to generate the gRPC client and server interfaces from our .proto service definition. We do this using the protocol buffer compiler `protoc` with a special gRPC Ruby plugin. |
||||
|
||||
If you want to run this yourself, make sure you've installed protoc and followed the gRPC Ruby plugin [installation instructions](https://github.com/grpc/grpc/blob/master/INSTALL) first): |
||||
|
||||
Once that's done, the following command can be used to generate the ruby code. |
||||
|
||||
```shell |
||||
$ protoc -I ../../protos --ruby_out=lib --grpc_out=lib --plugin=protoc-gen-grpc=`which grpc_ruby_plugin` ../../protos/route_guide.proto |
||||
``` |
||||
|
||||
Running this command regenerates the following files in the lib directory: |
||||
- `lib/route_guide.pb` defines a module `Examples::RouteGuide` |
||||
- This contain all the protocol buffer code to populate, serialize, and retrieve our request and response message types |
||||
- `lib/route_guide_services.pb`, extends `Examples::RouteGuide` with stub and service classes |
||||
- a class `Service` for use as a base class when defining RouteGuide service implementations |
||||
- a class `Stub` that can be used to access remote RouteGuide instances |
||||
|
||||
|
||||
<a name="server"></a> |
||||
## Creating the server |
||||
|
||||
First let's look at how we create a `RouteGuide` server. If you're only interested in creating gRPC clients, you can skip this section and go straight to [Creating the client](#client) (though you might find it interesting anyway!). |
||||
|
||||
There are two parts to making our `RouteGuide` service do its job: |
||||
- Implementing the service interface generated from our service definition: doing the actual "work" of our service. |
||||
- Running a gRPC server to listen for requests from clients and return the service responses. |
||||
|
||||
You can find our example `RouteGuide` server in [grpc-common/ruby/route_guide/route_guide_server.rb](https://github.com/grpc/grpc-common/blob/master/ruby/route_guide/route_guide_server.rb). Let's take a closer look at how it works. |
||||
|
||||
### Implementing RouteGuide |
||||
|
||||
As you can see, our server has a `ServerImpl` class that extends the generated `RouteGuide::Service`: |
||||
|
||||
```ruby |
||||
# ServerImpl provides an implementation of the RouteGuide service. |
||||
class ServerImpl < RouteGuide::Service |
||||
``` |
||||
|
||||
`ServerImpl` implements all our service methods. Let's look at the simplest type first, `GetFeature`, which just gets a `Point` from the client and returns the corresponding feature information from its database in a `Feature`. |
||||
|
||||
```ruby |
||||
def get_feature(point, _call) |
||||
name = @feature_db[{ |
||||
'longitude' => point.longitude, |
||||
'latitude' => point.latitude }] || '' |
||||
Feature.new(location: point, name: name) |
||||
end |
||||
``` |
||||
|
||||
The method is passed a _call for the RPC, the client's `Point` protocol buffer request, and returns a `Feature` protocol buffer. In the method we create the `Feature` with the appropriate information, and then `return` it. |
||||
|
||||
Now let's look at something a bit more complicated - a streaming RPC. `ListFeatures` is a server-side streaming RPC, so we need to send back multiple `Feature`s to our client. |
||||
|
||||
```ruby |
||||
# in ServerImpl |
||||
|
||||
def list_features(rectangle, _call) |
||||
RectangleEnum.new(@feature_db, rectangle).each |
||||
end |
||||
``` |
||||
|
||||
As you can see, here the request object is a `Rectangle` in which our client wants to find `Feature`s, but instead of returning a simple response we need to return an [Enumerator](http://ruby-doc.org//core-2.2.0/Enumerator.html) that yields the responses. In the method, we use a helper class `RectangleEnum`, to act as an Enumerator implementation. |
||||
|
||||
Similarly, the client-side streaming method `record_route` uses an [Enumerable](http://ruby-doc.org//core-2.2.0/Enumerable.html), but here it's obtained from the call object, which we've ignored in the earlier examples. `call.each_remote_read` yields each message sent by the client in turn. |
||||
|
||||
```ruby |
||||
call.each_remote_read do |point| |
||||
... |
||||
end |
||||
``` |
||||
Finally, let's look at our bidirectional streaming RPC `route_chat`. |
||||
|
||||
```ruby |
||||
def route_chat(notes) |
||||
q = EnumeratorQueue.new(self) |
||||
t = Thread.new do |
||||
begin |
||||
notes.each do |n| |
||||
... |
||||
end |
||||
end |
||||
q = EnumeratorQueue.new(self) |
||||
... |
||||
return q.each_item |
||||
end |
||||
``` |
||||
|
||||
Here the method receives an [Enumerable](http://ruby-doc.org//core-2.2.0/Enumerable.html), but also returns an [Enumerator](http://ruby-doc.org//core-2.2.0/Enumerator.html) that yields the responses. The implementation demonstrates how to set these up so that the requests and responses can be handled concurrently. Although each side will always get the other's messages in the order they were written, both the client and server can read and write in any order — the streams operate completely independently. |
||||
|
||||
### Starting the server |
||||
|
||||
Once we've implemented all our methods, we also need to start up a gRPC server so that clients can actually use our service. The following snippet shows how we do this for our `RouteGuide` service: |
||||
|
||||
```ruby |
||||
s = GRPC::RpcServer.new |
||||
s.add_http2_port(port) |
||||
logger.info("... running insecurely on #{port}") |
||||
s.handle(ServerImpl.new(feature_db)) |
||||
s.run |
||||
``` |
||||
As you can see, we build and start our server using a `GRPC::RpcServer`. To do this, we: |
||||
|
||||
1. Create an instance of our service implementation class `ServerImpl`. |
||||
2. Specify the address and port we want to use to listen for client requests using the builder's `add_http2_port` method. |
||||
3. Register our service implementation with the `GRPC::RpcServer`. |
||||
4. Call `run` on the`GRPC::RpcServer` to create and start an RPC server for our service. |
||||
|
||||
<a name="client"></a> |
||||
## Creating the client |
||||
|
||||
In this section, we'll look at creating a Rubyclient for our `RouteGuide` service. You can see our complete example client code in [grpc-common/ruby/route_guide/route_guide_client.rb](https://github.com/grpc/grpc-common/blob/master/ruby/route_guide/route_guide_client.rb). |
||||
|
||||
### Creating a stub |
||||
|
||||
To call service methods, we first need to create a *stub*. |
||||
|
||||
We use the `Stub` class of the `RouteGuide` module generated from our .proto. |
||||
|
||||
```ruby |
||||
stub = RouteGuide::Stub.new('localhost:50051') |
||||
``` |
||||
|
||||
### Calling service methods |
||||
|
||||
Now let's look at how we call our service methods. Note that the gRPC Ruby only provides *blocking/synchronous* versions of each method: this means that the RPC call waits for the server to respond, and will either return a response or raise an exception. |
||||
|
||||
#### Simple RPC |
||||
|
||||
Calling the simple RPC `GetFeature` is nearly as straightforward as calling a local method. |
||||
|
||||
```ruby |
||||
GET_FEATURE_POINTS = [ |
||||
Point.new(latitude: 409_146_138, longitude: -746_188_906), |
||||
Point.new(latitude: 0, longitude: 0) |
||||
] |
||||
.. |
||||
GET_FEATURE_POINTS.each do |pt| |
||||
resp = stub.get_feature(pt) |
||||
... |
||||
p "- found '#{resp.name}' at #{pt.inspect}" |
||||
end |
||||
``` |
||||
|
||||
As you can see, we create and populate a request protocol buffer object (in our case `Point`), and create a response protocol buffer object for the server to fill in. Finally, we call the method on the stub, passing it the context, request, and response. If the method returns `OK`, then we can read the response information from the server from our response object. |
||||
|
||||
|
||||
#### Streaming RPCs |
||||
|
||||
Now let's look at our streaming methods. If you've already read [Creating the server](#server) some of this may look very familiar - streaming RPCs are implemented in a similar way on both sides. Here's where we call the server-side streaming method `list_features`, which returns an `Enumerable` of `Features` |
||||
|
||||
```ruby |
||||
resps = stub.list_features(LIST_FEATURES_RECT) |
||||
resps.each do |r| |
||||
p "- found '#{r.name}' at #{r.location.inspect}" |
||||
end |
||||
``` |
||||
|
||||
The client-side streaming method `record_route` is similar, except there we pass the server an `Enumerable`. |
||||
|
||||
```ruby |
||||
... |
||||
reqs = RandomRoute.new(features, points_on_route) |
||||
resp = stub.record_route(reqs.each, deadline) |
||||
... |
||||
``` |
||||
|
||||
Finally, let's look at our bidirectional streaming RPC `route_chat`. In this case, we pass `Enumerable` to the method and get back an `Enumerable`. |
||||
|
||||
```ruby |
||||
resps = stub.route_chat(ROUTE_CHAT_NOTES) |
||||
resps.each { |r| p "received #{r.inspect}" } |
||||
``` |
||||
|
||||
Although it's not shown well by this example, each enumerable is independent of the other - both the client and server can read and write in any order — the streams operate completely independently. |
||||
|
||||
## Try it out! |
||||
|
||||
Build client and server: |
||||
|
||||
```shell |
||||
$ # from grpc-common/ruby |
||||
$ gem install bundler && bundle install |
||||
``` |
||||
Run the server, which will listen on port 50051: |
||||
```shell |
||||
$ # from grpc-common/ruby |
||||
$ bundle exec route_guide/route_guide_server.rb ../node/route_guide/route_guide_db.json & |
||||
``` |
||||
Run the client (in a different terminal): |
||||
```shell |
||||
$ # from grpc-common/ruby |
||||
$ bundle exec route_guide/route_guide_client.rb ../node/route_guide/route_guide_db.json & |
||||
``` |
||||
|
Loading…
Reference in new issue