def call(self, rpc, msg, timeout): """ Save the object that has been created and return the response. Will timeout after timeout ms if response has not been received Accepted Arguments: timeout -- (Integer) ms to wait for a response before returning """ # Define local callback function to handle RPC response # and initialize result dict result = { "done": False, "success": False, "response": None, "error_msg": "timeout", "error_code": None } #Can't use just a simple boolean for 'done' because of the way it is #referenced in the callback. The scope isn't clear and python #will redefine 'done' rather than change the value unless explicitly #defined as 'global done' #done = False def callback(request, response): result["response"] = response result["done"] = True result["error_msg"] = "" result["success"] = True #Setup the RPC channel channel = SocketRpcChannel(host=self.host, port=self.port) controller = channel.newController() service = self.service_stub_class(channel) #Make the RPC call and pass in a generic object with a #function called "run" linked to callback try: #Attempting to do something similar to a JAVA anonymous class #Create an instalce of a new generic type initialized with a #dict that has a run method pointing to the callback function rpc(service, controller, msg, type("", (), {"run": callback})()) except Exception, info: print controller.error
class TestRpcThread(unittest.TestCase): ''' Unit tests for the protobuf.service.RpcThread class.''' def setUp(self): self.channel = SocketRpcChannel(host=host, port=port) self.controller = self.channel.newController() self.service = test_pb2.TestService_Stub(self.channel) self.request = test_pb2.Request() self.request.str_data = 'I like cheese' self.callback = lambda request, response : response self.thread = service.RpcThread(test_pb2.TestService_Stub.TestMethod, self.service, self.controller, self.request, self.callback) ServerThread.start_server() def tearDown(self): pass def test__init__(self): '''Test RpcThread constructor.''' self.assertEqual(self.thread.method, test_pb2.TestService_Stub.TestMethod, "Attribute 'method' incorrectly initialized") self.assertEqual(self.thread.service, self.service, "Attribute 'service' incorrectly initialized") self.assertEqual(self.thread.controller, self.controller, "Attribute 'controller' incorrectly initialized") self.assertEqual(self.thread.request, self.request, "Attribute 'request' incorrectly initialized") self.assertEqual(self.thread.callback, self.callback, "Attribute 'callback' incorrectly initialized") self.assertEqual(self.thread.isDaemon(), True, "Thread not set as Daemon") def test_run(self): '''Test the run method''' try: self.thread.run() except Exception, e: self.assert_(False, "TestRpcThread.run() threw and exception", e)
def setUp(self): self.channel = SocketRpcChannel(host=host, port=port) self.controller = self.channel.newController() self.service = test_pb2.TestService_Stub(self.channel) self.request = test_pb2.Request() self.request.str_data = 'I like cheese' self.callback = lambda request, response : response self.thread = service.RpcThread(test_pb2.TestService_Stub.TestMethod, self.service, self.controller, self.request, self.callback) ServerThread.start_server()
def call(self, rpc, msg, timeout): """ Save the object that has been created and return the response. Will timeout after timeout ms if response has not been received Accepted Arguments: timeout -- (Integer) ms to wait for a response before returning """ # Define local callback function to handle RPC response # and initialize result dict result = {"done":False, "success":False, "response":None, "error_msg":"timeout", "error_code":None} #Can't use just a simple boolean for 'done' because of the way it is #referenced in the callback. The scope isn't clear and python #will redefine 'done' rather than change the value unless explicitly #defined as 'global done' #done = False def callback(request, response): result["response"] = response result["done"] = True result["error_msg"] = "" result["success"] = True #Setup the RPC channel channel = SocketRpcChannel(host=self.host, port=self.port) controller = channel.newController() service = self.service_stub_class(channel) #Make the RPC call and pass in a generic object with a #function called "run" linked to callback try: #Attempting to do something similar to a JAVA anonymous class #Create an instalce of a new generic type initialized with a #dict that has a run method pointing to the callback function rpc(service, controller, msg, type("", (), {"run":callback})()) except Exception, info: print controller.error
def __init__(self, service_stub_class, port, host): ''' Contruct a new ProtoBufRpcRequest and return it. Accepted Arguments: service_stub_class -- (Service_Stub) The client side RPC stub class produced by protoc from the .proto file port -- (Integer) The port on which the service is running on the RPC server. host -- (String) The hostname or IP address of the server running the RPC service. ''' self.service_stub_class = service_stub_class self.port = port self.host = host # Setup the RPC channel self.channel = SocketRpcChannel(host=self.host, port=self.port) self.service = self.service_stub_class(self.channel) # go through service_stub methods and add a wrapper function to # this object that will call the method for method in service_stub_class.GetDescriptor().methods: # Add service methods to the this object rpc = lambda request, timeout=None, callback=None, service=self, method=method.name : service.call( service_stub_class.__dict__[method], request, timeout, callback) rpc.__doc__ = method.name + ' method of the ' + \ service_stub_class.DESCRIPTOR.name + ' from the ' + \ service_stub_class.__module__ + ' module generated by the ' + \ 'protoc compiler. This method can be called synchronously ' + \ 'by setting timeout -> ms or asynchrounously by setting ' + \ 'callback -> function(request,response)\n\n' + \ 'Synchronous Example:\n' + \ '\trequest = ' + method.input_type.name + '()\n' + \ '\ttry:\n' + \ '\t#Wait 1000ms for a response\n' + \ '\t\tresponse = ' + method.name + '(request, timeout=1000)\n' + \ '\texcept: RpcException\n' + \ '\t\t#Handle exception\n\n' + \ 'Asynchronous Example:\n' + \ '\tdef callback(request,response):\n' + \ '\t\t#Do some stuff\n' + \ '\trequest = ' + method.input_type.name + '()\n' + \ '\ttry:\n' + \ '\t\t' + method.name + '(request, callback=callback)\n' + \ '\texcept: RpcException\n' + \ '\t\t#Handle exception\n\n' self.__dict__[method.name] = rpc
class RpcService(object): ''' Class abstracting the Protocol Buffer RPC calls for a supplied service stub. ''' def __init__(self, service_stub_class, port, host): ''' Contruct a new ProtoBufRpcRequest and return it. Accepted Arguments: service_stub_class -- (Service_Stub) The client side RPC stub class produced by protoc from the .proto file port -- (Integer) The port on which the service is running on the RPC server. host -- (String) The hostname or IP address of the server running the RPC service. ''' self.service_stub_class = service_stub_class self.port = port self.host = host # Setup the RPC channel self.channel = SocketRpcChannel(host=self.host, port=self.port) self.service = self.service_stub_class(self.channel) # go through service_stub methods and add a wrapper function to # this object that will call the method for method in service_stub_class.GetDescriptor().methods: # Add service methods to the this object rpc = lambda request, timeout=None, callback=None, service=self, method=method.name : service.call( service_stub_class.__dict__[method], request, timeout, callback) rpc.__doc__ = method.name + ' method of the ' + \ service_stub_class.DESCRIPTOR.name + ' from the ' + \ service_stub_class.__module__ + ' module generated by the ' + \ 'protoc compiler. This method can be called synchronously ' + \ 'by setting timeout -> ms or asynchrounously by setting ' + \ 'callback -> function(request,response)\n\n' + \ 'Synchronous Example:\n' + \ '\trequest = ' + method.input_type.name + '()\n' + \ '\ttry:\n' + \ '\t#Wait 1000ms for a response\n' + \ '\t\tresponse = ' + method.name + '(request, timeout=1000)\n' + \ '\texcept: RpcException\n' + \ '\t\t#Handle exception\n\n' + \ 'Asynchronous Example:\n' + \ '\tdef callback(request,response):\n' + \ '\t\t#Do some stuff\n' + \ '\trequest = ' + method.input_type.name + '()\n' + \ '\ttry:\n' + \ '\t\t' + method.name + '(request, callback=callback)\n' + \ '\texcept: RpcException\n' + \ '\t\t#Handle exception\n\n' self.__dict__[method.name] = rpc def call(self, rpc, request, timeout=None, callback=None): ''' Save the object that has been created and return the response. Will timeout after timeout ms if response has not been received. The timeout arg is only used for asynch requests. If a callback has been supplied the timeout arg is not used. The response value will be returned for a synch request but nothing will be returned for an asynch request. Accepted Arguments: timeout -- (Integer) ms to wait for a response before returning ''' # Define local callback function to handle RPC response # and initialize result dict result = {'done': False, 'response': None} def synch_callback(request, response): result['response'] = response result['done'] = True result['error_msg'] = '' result['success'] = True # If no callback has been passed in then this is meant to be synchronous if callback == None: rpc_callback = synch_callback else: if ((not callable(callback) and (callback.__class__.__dict__.get('run') == None or callback.run.func_code.co_argcount < 2)) or (callable(callback) and callback.func_code.co_argcount < 2)): raise Exception("callback must be a callable with signature " + "callback(request, response, ...) or an " + "object with a callable run function with " + "the same signature") rpc_callback = callback # Create a controller for this call controller = self.channel.newController() # Spawn a new thread to wait for the callback so this can return # immediately if an asynch callback has been requested rpc_thread = RpcThread(rpc, self.service, controller, request, rpc_callback) rpc_thread.start() # If a callback has been passed in return if rpc_callback == callback: return else: if timeout == None: timeout = 100 end = time() + (timeout / 1000) # Tight loop waiting for timeout or synch_callback to set done to True while time() < end and not result['done']: if controller.failed(): if type(controller.error) is str: raise Exception(controller.error) else: raise controller.error if time() >= end and not result['done']: raise RpcError('request timed out') return result['response']