Ejemplo n.º 1
0
    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\nSynchronous 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
Ejemplo n.º 2
0
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\nSynchronous 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
        '''

        # Create a controller for this call
        controller = self.channel.newController()
        
        if callback is None and timeout is None:
            # Sync call without timeout
            return rpc(self.service, controller, request, callback)

        # 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

        # 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 controller
        if rpc_callback == callback:
            return controller

        # Run with timeout
        end = time() + (timeout / 1000)

        # Wait for timeout or thread to exit indicating call has returned
        rpc_thread.join(timeout)

        if time() >= end and not result['done']:
            raise RpcError('request timed out')

        if controller.failed():
            raise RpcError(controller.error())

        return result['response']