1*cc02d7e2SAndroid Build Coastguard Worker# Copyright 2020 The gRPC Authors 2*cc02d7e2SAndroid Build Coastguard Worker# 3*cc02d7e2SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 4*cc02d7e2SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 5*cc02d7e2SAndroid Build Coastguard Worker# You may obtain a copy of the License at 6*cc02d7e2SAndroid Build Coastguard Worker# 7*cc02d7e2SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 8*cc02d7e2SAndroid Build Coastguard Worker# 9*cc02d7e2SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 10*cc02d7e2SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 11*cc02d7e2SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*cc02d7e2SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 13*cc02d7e2SAndroid Build Coastguard Worker# limitations under the License. 14*cc02d7e2SAndroid Build Coastguard Worker 15*cc02d7e2SAndroid Build Coastguard Workerfrom concurrent.futures import ThreadPoolExecutor 16*cc02d7e2SAndroid Build Coastguard Workerimport logging 17*cc02d7e2SAndroid Build Coastguard Workerimport threading 18*cc02d7e2SAndroid Build Coastguard Workerimport time 19*cc02d7e2SAndroid Build Coastguard Workerfrom typing import Iterable 20*cc02d7e2SAndroid Build Coastguard Worker 21*cc02d7e2SAndroid Build Coastguard Workerfrom google.protobuf.json_format import MessageToJson 22*cc02d7e2SAndroid Build Coastguard Workerimport grpc 23*cc02d7e2SAndroid Build Coastguard Worker 24*cc02d7e2SAndroid Build Coastguard Workerimport phone_pb2 25*cc02d7e2SAndroid Build Coastguard Workerimport phone_pb2_grpc 26*cc02d7e2SAndroid Build Coastguard Worker 27*cc02d7e2SAndroid Build Coastguard Worker 28*cc02d7e2SAndroid Build Coastguard Workerdef create_state_response( 29*cc02d7e2SAndroid Build Coastguard Worker call_state: phone_pb2.CallState.State, 30*cc02d7e2SAndroid Build Coastguard Worker) -> phone_pb2.StreamCallResponse: 31*cc02d7e2SAndroid Build Coastguard Worker response = phone_pb2.StreamCallResponse() 32*cc02d7e2SAndroid Build Coastguard Worker response.call_state.state = call_state 33*cc02d7e2SAndroid Build Coastguard Worker return response 34*cc02d7e2SAndroid Build Coastguard Worker 35*cc02d7e2SAndroid Build Coastguard Worker 36*cc02d7e2SAndroid Build Coastguard Workerclass Phone(phone_pb2_grpc.PhoneServicer): 37*cc02d7e2SAndroid Build Coastguard Worker def __init__(self): 38*cc02d7e2SAndroid Build Coastguard Worker self._id_counter = 0 39*cc02d7e2SAndroid Build Coastguard Worker self._lock = threading.RLock() 40*cc02d7e2SAndroid Build Coastguard Worker 41*cc02d7e2SAndroid Build Coastguard Worker def _create_call_session(self) -> phone_pb2.CallInfo: 42*cc02d7e2SAndroid Build Coastguard Worker call_info = phone_pb2.CallInfo() 43*cc02d7e2SAndroid Build Coastguard Worker with self._lock: 44*cc02d7e2SAndroid Build Coastguard Worker call_info.session_id = str(self._id_counter) 45*cc02d7e2SAndroid Build Coastguard Worker self._id_counter += 1 46*cc02d7e2SAndroid Build Coastguard Worker call_info.media = "https://link.to.audio.resources" 47*cc02d7e2SAndroid Build Coastguard Worker logging.info("Created a call session [%s]", MessageToJson(call_info)) 48*cc02d7e2SAndroid Build Coastguard Worker return call_info 49*cc02d7e2SAndroid Build Coastguard Worker 50*cc02d7e2SAndroid Build Coastguard Worker def _clean_call_session(self, call_info: phone_pb2.CallInfo) -> None: 51*cc02d7e2SAndroid Build Coastguard Worker logging.info("Call session cleaned [%s]", MessageToJson(call_info)) 52*cc02d7e2SAndroid Build Coastguard Worker 53*cc02d7e2SAndroid Build Coastguard Worker def StreamCall( 54*cc02d7e2SAndroid Build Coastguard Worker self, 55*cc02d7e2SAndroid Build Coastguard Worker request_iterator: Iterable[phone_pb2.StreamCallRequest], 56*cc02d7e2SAndroid Build Coastguard Worker context: grpc.ServicerContext, 57*cc02d7e2SAndroid Build Coastguard Worker ) -> Iterable[phone_pb2.StreamCallResponse]: 58*cc02d7e2SAndroid Build Coastguard Worker try: 59*cc02d7e2SAndroid Build Coastguard Worker request = next(request_iterator) 60*cc02d7e2SAndroid Build Coastguard Worker logging.info( 61*cc02d7e2SAndroid Build Coastguard Worker "Received a phone call request for number [%s]", 62*cc02d7e2SAndroid Build Coastguard Worker request.phone_number, 63*cc02d7e2SAndroid Build Coastguard Worker ) 64*cc02d7e2SAndroid Build Coastguard Worker except StopIteration: 65*cc02d7e2SAndroid Build Coastguard Worker raise RuntimeError("Failed to receive call request") 66*cc02d7e2SAndroid Build Coastguard Worker # Simulate the acceptance of call request 67*cc02d7e2SAndroid Build Coastguard Worker time.sleep(1) 68*cc02d7e2SAndroid Build Coastguard Worker yield create_state_response(phone_pb2.CallState.NEW) 69*cc02d7e2SAndroid Build Coastguard Worker # Simulate the start of the call session 70*cc02d7e2SAndroid Build Coastguard Worker time.sleep(1) 71*cc02d7e2SAndroid Build Coastguard Worker call_info = self._create_call_session() 72*cc02d7e2SAndroid Build Coastguard Worker context.add_callback(lambda: self._clean_call_session(call_info)) 73*cc02d7e2SAndroid Build Coastguard Worker response = phone_pb2.StreamCallResponse() 74*cc02d7e2SAndroid Build Coastguard Worker response.call_info.session_id = call_info.session_id 75*cc02d7e2SAndroid Build Coastguard Worker response.call_info.media = call_info.media 76*cc02d7e2SAndroid Build Coastguard Worker yield response 77*cc02d7e2SAndroid Build Coastguard Worker yield create_state_response(phone_pb2.CallState.ACTIVE) 78*cc02d7e2SAndroid Build Coastguard Worker # Simulate the end of the call 79*cc02d7e2SAndroid Build Coastguard Worker time.sleep(2) 80*cc02d7e2SAndroid Build Coastguard Worker yield create_state_response(phone_pb2.CallState.ENDED) 81*cc02d7e2SAndroid Build Coastguard Worker logging.info("Call finished [%s]", request.phone_number) 82*cc02d7e2SAndroid Build Coastguard Worker 83*cc02d7e2SAndroid Build Coastguard Worker 84*cc02d7e2SAndroid Build Coastguard Workerdef serve(address: str) -> None: 85*cc02d7e2SAndroid Build Coastguard Worker server = grpc.server(ThreadPoolExecutor()) 86*cc02d7e2SAndroid Build Coastguard Worker phone_pb2_grpc.add_PhoneServicer_to_server(Phone(), server) 87*cc02d7e2SAndroid Build Coastguard Worker server.add_insecure_port(address) 88*cc02d7e2SAndroid Build Coastguard Worker server.start() 89*cc02d7e2SAndroid Build Coastguard Worker logging.info("Server serving at %s", address) 90*cc02d7e2SAndroid Build Coastguard Worker server.wait_for_termination() 91*cc02d7e2SAndroid Build Coastguard Worker 92*cc02d7e2SAndroid Build Coastguard Worker 93*cc02d7e2SAndroid Build Coastguard Workerif __name__ == "__main__": 94*cc02d7e2SAndroid Build Coastguard Worker logging.basicConfig(level=logging.INFO) 95*cc02d7e2SAndroid Build Coastguard Worker serve("[::]:50051") 96