1# Copyright 2020 The gRPC Authors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14"""The Python AsyncIO implementation of the gRPC route guide client.""" 15 16import asyncio 17import logging 18import random 19from typing import Iterable, List 20 21import grpc 22import route_guide_pb2 23import route_guide_pb2_grpc 24import route_guide_resources 25 26 27def make_route_note( 28 message: str, latitude: int, longitude: int 29) -> route_guide_pb2.RouteNote: 30 return route_guide_pb2.RouteNote( 31 message=message, 32 location=route_guide_pb2.Point(latitude=latitude, longitude=longitude), 33 ) 34 35 36# Performs a unary call 37async def guide_get_one_feature( 38 stub: route_guide_pb2_grpc.RouteGuideStub, point: route_guide_pb2.Point 39) -> None: 40 feature = await stub.GetFeature(point) 41 if not feature.location: 42 print("Server returned incomplete feature") 43 return 44 45 if feature.name: 46 print(f"Feature called {feature.name} at {feature.location}") 47 else: 48 print(f"Found no feature at {feature.location}") 49 50 51async def guide_get_feature(stub: route_guide_pb2_grpc.RouteGuideStub) -> None: 52 # The following two coroutines will be wrapped in a Future object 53 # and scheduled in the event loop so that they can run concurrently 54 task_group = asyncio.gather( 55 guide_get_one_feature( 56 stub, 57 route_guide_pb2.Point(latitude=409146138, longitude=-746188906), 58 ), 59 guide_get_one_feature( 60 stub, route_guide_pb2.Point(latitude=0, longitude=0) 61 ), 62 ) 63 # Wait until the Future is resolved 64 await task_group 65 66 67# Performs a server-streaming call 68async def guide_list_features( 69 stub: route_guide_pb2_grpc.RouteGuideStub, 70) -> None: 71 rectangle = route_guide_pb2.Rectangle( 72 lo=route_guide_pb2.Point(latitude=400000000, longitude=-750000000), 73 hi=route_guide_pb2.Point(latitude=420000000, longitude=-730000000), 74 ) 75 print("Looking for features between 40, -75 and 42, -73") 76 77 features = stub.ListFeatures(rectangle) 78 79 async for feature in features: 80 print(f"Feature called {feature.name} at {feature.location}") 81 82 83def generate_route( 84 feature_list: List[route_guide_pb2.Feature], 85) -> Iterable[route_guide_pb2.Point]: 86 for _ in range(0, 10): 87 random_feature = random.choice(feature_list) 88 print(f"Visiting point {random_feature.location}") 89 yield random_feature.location 90 91 92# Performs a client-streaming call 93async def guide_record_route(stub: route_guide_pb2_grpc.RouteGuideStub) -> None: 94 feature_list = route_guide_resources.read_route_guide_database() 95 route_iterator = generate_route(feature_list) 96 97 # gRPC AsyncIO client-streaming RPC API accepts both synchronous iterables 98 # and async iterables. 99 route_summary = await stub.RecordRoute(route_iterator) 100 print(f"Finished trip with {route_summary.point_count} points") 101 print(f"Passed {route_summary.feature_count} features") 102 print(f"Travelled {route_summary.distance} meters") 103 print(f"It took {route_summary.elapsed_time} seconds") 104 105 106def generate_messages() -> Iterable[route_guide_pb2.RouteNote]: 107 messages = [ 108 make_route_note("First message", 0, 0), 109 make_route_note("Second message", 0, 1), 110 make_route_note("Third message", 1, 0), 111 make_route_note("Fourth message", 0, 0), 112 make_route_note("Fifth message", 1, 0), 113 ] 114 for msg in messages: 115 print(f"Sending {msg.message} at {msg.location}") 116 yield msg 117 118 119# Performs a bidi-streaming call 120async def guide_route_chat(stub: route_guide_pb2_grpc.RouteGuideStub) -> None: 121 # gRPC AsyncIO bidi-streaming RPC API accepts both synchronous iterables 122 # and async iterables. 123 call = stub.RouteChat(generate_messages()) 124 async for response in call: 125 print(f"Received message {response.message} at {response.location}") 126 127 128async def main() -> None: 129 async with grpc.aio.insecure_channel("localhost:50051") as channel: 130 stub = route_guide_pb2_grpc.RouteGuideStub(channel) 131 print("-------------- GetFeature --------------") 132 await guide_get_feature(stub) 133 print("-------------- ListFeatures --------------") 134 await guide_list_features(stub) 135 print("-------------- RecordRoute --------------") 136 await guide_record_route(stub) 137 print("-------------- RouteChat --------------") 138 await guide_route_chat(stub) 139 140 141if __name__ == "__main__": 142 logging.basicConfig(level=logging.INFO) 143 asyncio.get_event_loop().run_until_complete(main()) 144