def enter_main_loop(self): """ Wait for requests from the other side. The communication protocol for remote procedure calls is as follows: - Every request is a dictionary containing at least a ``command`` key with a string value (the name of the method to invoke). - The value of the optional ``arguments`` key gives a list of positional arguments to pass to the method. - The value of the optional ``keyword-arguments`` key gives a dictionary of keyword arguments to pass to the method. Responses are structured as follows: - Every response is a dictionary containing at least a ``success`` key with a boolean value. - If ``success=True`` the key ``result`` gives the return value of the method. - If ``success=False`` the key ``error`` gives a string explaining what went wrong. :raises: :py:exc:`ProtocolError` when the remote side violates the defined protocol. """ while True: request = self.read() method_name = request.get('method') method = getattr(self, method_name, None) args = request.get('args', []) kw = request.get('kw', {}) if method and not method_name.startswith('_'): try: logger.info("Remote is calling local method %s ..", format_call(method_name, *args, **kw)) result = method(*args, **kw) logger.info( "Local method call was successful and returned result %r.", result) self.write(dict(success=True, result=result)) except Exception as e: logger.exception( "Swallowing unexpected exception during local method call so we don't crash!" ) self.write(dict(success=False, error=str(e))) else: logger.warning("Remote tried to call unsupported method %s!", method_name) self.write( dict(success=False, error="Method %s not supported" % method_name))
def enter_main_loop(self): """ Wait for requests from the other side. The communication protocol for remote procedure calls is as follows: - Every request is a dictionary containing at least a ``command`` key with a string value (the name of the method to invoke). - The value of the optional ``arguments`` key gives a list of positional arguments to pass to the method. - The value of the optional ``keyword-arguments`` key gives a dictionary of keyword arguments to pass to the method. Responses are structured as follows: - Every response is a dictionary containing at least a ``success`` key with a boolean value. - If ``success=True`` the key ``result`` gives the return value of the method. - If ``success=False`` the key ``error`` gives a string explaining what went wrong. :raises: :exc:`ProtocolError` when the remote side violates the defined protocol. """ while True: request = self.read() method_name = request.get('method') method = getattr(self, method_name, None) args = request.get('args', []) kw = request.get('kw', {}) if method and not method_name.startswith('_'): try: logger.info("Remote is calling local method %s ..", format_call(method_name, *args, **kw)) result = method(*args, **kw) logger.info("Local method call was successful and returned result %r.", result) self.write(dict(success=True, result=result)) except Exception as e: logger.exception("Swallowing unexpected exception during local method call so we don't crash!") self.write(dict(success=False, error=str(e))) else: logger.warning("Remote tried to call unsupported method %s!", method_name) self.write(dict(success=False, error="Method %s not supported" % method_name))
def call_remote_method(self, method, *args, **kw): """ Call a method on the remote object. :param method: The name of the method to call (a string). :param args: The positional arguments for the method. :param kw: The keyword arguments for the method. :returns: The return value of the remote method. """ timer = Timer() logger.debug("Calling remote method %s ..", format_call(method, *args, **kw)) self.write(dict(method=method, args=args, kw=kw)) response = self.read() if response['success']: logger.debug("Remote method call succeeded in %s and returned %r!", timer, response['result']) return response['result'] else: logger.warning("Remote method call failed after %s: %s", timer, response['error']) raise RemoteMethodFailed(response['error'])