1# Copyright 2016 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"""A gRPC server servicing both Greeter and RouteGuide RPCs.""" 15 16from concurrent import futures 17import time 18import math 19 20import grpc 21 22import helloworld_pb2 23import helloworld_pb2_grpc 24import route_guide_pb2 25import route_guide_pb2_grpc 26import route_guide_resources 27 28_ONE_DAY_IN_SECONDS = 60 * 60 * 24 29 30 31def _get_feature(feature_db, point): 32 """Returns Feature at given location or None.""" 33 for feature in feature_db: 34 if feature.location == point: 35 return feature 36 return None 37 38 39def _get_distance(start, end): 40 """Distance between two points.""" 41 coord_factor = 10000000.0 42 lat_1 = start.latitude / coord_factor 43 lat_2 = end.latitude / coord_factor 44 lon_1 = start.longitude / coord_factor 45 lon_2 = end.longitude / coord_factor 46 lat_rad_1 = math.radians(lat_1) 47 lat_rad_2 = math.radians(lat_2) 48 delta_lat_rad = math.radians(lat_2 - lat_1) 49 delta_lon_rad = math.radians(lon_2 - lon_1) 50 51 a = (pow(math.sin(delta_lat_rad / 2), 2) + 52 (math.cos(lat_rad_1) * math.cos(lat_rad_2) * pow( 53 math.sin(delta_lon_rad / 2), 2))) 54 c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)) 55 R = 6371000 56 # metres 57 return R * c 58 59 60class _GreeterServicer(helloworld_pb2_grpc.GreeterServicer): 61 62 def SayHello(self, request, context): 63 return helloworld_pb2.HelloReply( 64 message='Hello, {}!'.format(request.name)) 65 66 67class _RouteGuideServicer(route_guide_pb2_grpc.RouteGuideServicer): 68 """Provides methods that implement functionality of route guide server.""" 69 70 def __init__(self): 71 self.db = route_guide_resources.read_route_guide_database() 72 73 def GetFeature(self, request, context): 74 feature = _get_feature(self.db, request) 75 if feature is None: 76 return route_guide_pb2.Feature(name="", location=request) 77 else: 78 return feature 79 80 def ListFeatures(self, request, context): 81 left = min(request.lo.longitude, request.hi.longitude) 82 right = max(request.lo.longitude, request.hi.longitude) 83 top = max(request.lo.latitude, request.hi.latitude) 84 bottom = min(request.lo.latitude, request.hi.latitude) 85 for feature in self.db: 86 if (feature.location.longitude >= left and 87 feature.location.longitude <= right and 88 feature.location.latitude >= bottom and 89 feature.location.latitude <= top): 90 yield feature 91 92 def RecordRoute(self, request_iterator, context): 93 point_count = 0 94 feature_count = 0 95 distance = 0.0 96 prev_point = None 97 98 start_time = time.time() 99 for point in request_iterator: 100 point_count += 1 101 if _get_feature(self.db, point): 102 feature_count += 1 103 if prev_point: 104 distance += _get_distance(prev_point, point) 105 prev_point = point 106 107 elapsed_time = time.time() - start_time 108 return route_guide_pb2.RouteSummary( 109 point_count=point_count, 110 feature_count=feature_count, 111 distance=int(distance), 112 elapsed_time=int(elapsed_time)) 113 114 def RouteChat(self, request_iterator, context): 115 prev_notes = [] 116 for new_note in request_iterator: 117 for prev_note in prev_notes: 118 if prev_note.location == new_note.location: 119 yield prev_note 120 prev_notes.append(new_note) 121 122 123def serve(): 124 server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) 125 helloworld_pb2_grpc.add_GreeterServicer_to_server(_GreeterServicer(), 126 server) 127 route_guide_pb2_grpc.add_RouteGuideServicer_to_server( 128 _RouteGuideServicer(), server) 129 server.add_insecure_port('[::]:50051') 130 server.start() 131 try: 132 while True: 133 time.sleep(_ONE_DAY_IN_SECONDS) 134 except KeyboardInterrupt: 135 server.stop(0) 136 137 138if __name__ == '__main__': 139 serve() 140