Example #1
0
    def call_method(self, name, method, params):
        """Call a previously registered subsystem method by name. Only
        methods tagged with the @api_call decorator can be called.

        :param name: Assigned name of the registered subsystem.
        :type name: string
        :param method: Subsystem method to be called.
        :type method: string
        :param params: Additional parameters for the called method.
        :type params: dict
        :returns: call_reply or error message dict to be sent to caller.

        """
        self.logger.debug("API call: {}.{}({})".format(name, method, params))
        if name in self.systems:
            obj = self.systems[name]
            if is_api_method(obj, method):
                try:
                    # Calls given obj.method, unpacking and passing params dict
                    call_return = getattr(obj, method)(**params)
                    msg = "Called {}.{}".format(name, method)
                    self.logger.debug(msg + ",returned:{}".format(call_return))
                    return msgs.call_reply(msg, call_return)
                except TypeError:
                    # Raised when we have a mismatch of the method's kwargs
                    # TODO: Return argspec here?
                    err_msg = "Invalid params for {}.{}".format(name, method)
                    self.logger.warning(err_msg)
                    return msgs.error(err_msg)
                except Exception as e:
                    # Catch exception raised by called method, notify client
                    err_msg = "Exception: '{}'".format(str(e))
                    self.logger.warning(err_msg)
                    return msgs.error(err_msg)
            else:
                err_msg = "Invalid method: '{}.{}'".format(name, method)
                self.logger.warning(err_msg)
                return msgs.error(err_msg)
        else:
            err_msg = "Invalid object: '{}'".format(name)
            self.logger.warning(err_msg)
            return msgs.error(err_msg)
Example #2
0
    def call_method(self, name, method, params):
        """Call a previously registered subsystem method by name. Only
        methods tagged with the @api_call decorator can be called.

        :param name: Assigned name of the registered subsystem.
        :type name: string
        :param method: Subsystem method to be called.
        :type method: string
        :param params: Additional parameters for the called method.
        :type params: dict
        :returns: call_reply or error message dict to be sent to caller.

        """
        self.logger.debug("API call: {}.{}({})".format(name, method, params))
        if name in self.systems:
            obj = self.systems[name]
            if is_api_method(obj, method):
                try:
                    # Calls given obj.method, unpacking and passing params dict
                    call_return = getattr(obj, method)(**params)
                    msg = "Called {}.{}".format(name, method)
                    self.logger.debug(msg + ",returned:{}".format(call_return))
                    return msgs.call_reply(msg, call_return)
                except TypeError:
                    # Raised when we have a mismatch of the method's kwargs
                    # TODO: Return argspec here?
                    err_msg = "Invalid params for {}.{}".format(name, method)
                    self.logger.warning(err_msg)
                    return msgs.error(err_msg)
                except Exception as e:
                    # Catch exception raised by called method, notify client
                    err_msg = "Exception: '{}'".format(str(e))
                    self.logger.warning(err_msg)
                    return msgs.error(err_msg)
            else:
                err_msg = "Invalid method: '{}.{}'".format(name, method)
                self.logger.warning(err_msg)
                return msgs.error(err_msg)
        else:
            err_msg = "Invalid object: '{}'".format(name)
            self.logger.warning(err_msg)
            return msgs.error(err_msg)
Example #3
0
    def handle_msg(self, msg):
        """Generic message handler. Hands-off based on type of message.

        :param msg: Message, received via ZMQ from client, to handle.
        :type msg: dict
        :returns: An appropriate message reply dict, from lib.messages.

        """
        self.logger.debug("Received: {}".format(msg))

        try:
            msg_type = msg["type"]
        except KeyError as e:
            return msgs.error(e)

        if msg_type == "ping_req":
            reply = msgs.ping_reply()
        elif msg_type == "list_req":
            reply = self.list_callables()
        elif msg_type == "call_req":
            try:
                obj_name = msg["obj_name"]
                method = msg["method"]
                params = msg["params"]
                reply = self.call_method(obj_name, method, params)
            except KeyError as e:
                return msgs.error(e)
        elif msg_type == "exit_req":
            self.logger.info("Received message to die. Bye!")
            reply = msgs.exit_reply()
            # Need to actually send reply here as we're about to exit
            self.logger.debug("Sending: {}".format(reply))
            self.ctrl_sock.send_json(reply)
            self.clean_up()
            sys.exit(0)
        else:
            err_msg = "Unrecognized message: {}".format(msg)
            self.logger.warning(err_msg)
            reply = msgs.error(err_msg)
        return reply
Example #4
0
    def handle_msg(self, msg):
        """Generic message handler. Hands-off based on type of message.

        :param msg: Message, received via ZMQ from client, to handle.
        :type msg: dict
        :returns: An appropriate message reply dict, from lib.messages.

        """
        self.logger.debug("Received: {}".format(msg))

        try:
            msg_type = msg["type"]
        except KeyError as e:
            return msgs.error(e)

        if msg_type == "ping_req":
            reply = msgs.ping_reply()
        elif msg_type == "list_req":
            reply = self.list_callables()
        elif msg_type == "call_req":
            try:
                obj_name = msg["obj_name"]
                method = msg["method"]
                params = msg["params"]
                reply = self.call_method(obj_name, method, params)
            except KeyError as e:
                return msgs.error(e)
        elif msg_type == "exit_req":
            self.logger.info("Received message to die. Bye!")
            reply = msgs.exit_reply()
            # Need to actually send reply here as we're about to exit
            self.logger.debug("Sending: {}".format(reply))
            self.ctrl_sock.send_json(reply)
            self.clean_up()
            sys.exit(0)
        else:
            err_msg = "Unrecognized message: {}".format(msg)
            self.logger.warning(err_msg)
            reply = msgs.error(err_msg)
        return reply
Example #5
0
 def listen(self):
     """Perpetually listen for messages, pass them to generic handler."""
     self.logger.info("Control server: {}".format(self.server_bind_addr))
     while True:
         try:
             msg = self.ctrl_sock.recv_json()
             reply = self.handle_msg(msg)
             self.logger.debug("Sending: {}".format(reply))
             self.ctrl_sock.send_json(reply)
         except JSONDecodeError:
             err_msg = "Not a JSON message!"
             self.logger.warning(err_msg)
             self.ctrl_sock.send_json(msgs.error(err_msg))
         except KeyboardInterrupt:
             self.logger.info("Exiting control server. Bye!")
             self.clean_up()
             sys.exit(0)
Example #6
0
 def listen(self):
     """Perpetually listen for messages, pass them to generic handler."""
     self.logger.info("Control server: {}".format(self.server_bind_addr))
     while True:
         try:
             msg = self.ctrl_sock.recv_json()
             reply = self.handle_msg(msg)
             self.logger.debug("Sending: {}".format(reply))
             self.ctrl_sock.send_json(reply)
         except JSONDecodeError:
             err_msg = "Not a JSON message!"
             self.logger.warning(err_msg)
             self.ctrl_sock.send_json(msgs.error(err_msg))
         except KeyboardInterrupt:
             self.logger.info("Exiting control server. Bye!")
             self.clean_up()
             sys.exit(0)