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