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