Example #1
0
    def parseNodeNum(self, cmd):

        # Make sure the command even has enough arguments for there to be a
        # node number argument present!

        if not len(cmd.cmdArgs) >= 1:
            logger.error(
                "CommandHandler.parseNodeNum(): I expected this command to have at least one argument, a node number.  It doesn't."
            )
            return None

            # Try parsing the first argument as a node number.  If this fails,
            # log an error and use the invalid node number '-1'.

        try:
            cmd.nodeNum = int(cmd.cmdArgs[0])
        except ValueError:
            logger.error(
                "CommandHandler.parseNodeNum(): I expected the first argument to this command to be a node number, an integer.  It isn't.  Using -1 instead."
            )
            cmd.nodeNum = -1  # Invalid value.
            return  # No point in setting the component or skipping the arg.

            # Change the component name in this thread's logging context to the
            # name of the node that sent this command.  When we finish processing
            # the command later, we can switch the component back to "server"

        logmaster.setComponent("node#%d" % cmd.nodeNum)

        # Now that we've parsed the node number into its own attribute,
        # it doesn't need to be in the arg list any more.  Strip it off arg list.

        cmd.cmdArgs = cmd.cmdArgs[1:]

        return cmd.nodeNum
Example #2
0
    def parseNodeNum(self, cmd):

        # Make sure the command even has enough arguments for there to be a
        # node number argument present!

        if not len(cmd.cmdArgs) >= 1:
            logger.error(
                "CommandHandler.parseNodeNum(): I expected this command to have at least one argument, a node number.  It doesn't."
            )
            return None

            # Try parsing the first argument as a node number.  If this fails,
            # log an error and use the invalid node number '-1'.

        try:
            cmd.nodeNum = int(cmd.cmdArgs[0])
        except ValueError:
            logger.error(
                "CommandHandler.parseNodeNum(): I expected the first argument to this command to be a node number, an integer.  It isn't.  Using -1 instead."
            )
            cmd.nodeNum = -1  # Invalid value.
            return  # No point in setting the component or skipping the arg.

            # Change the component name in this thread's logging context to the
            # name of the node that sent this command.  When we finish processing
            # the command later, we can switch the component back to "server"

        logmaster.setComponent("node#%d" % cmd.nodeNum)

        # Now that we've parsed the node number into its own attribute,
        # it doesn't need to be in the arg list any more.  Strip it off arg list.

        cmd.cmdArgs = cmd.cmdArgs[1:]

        return cmd.nodeNum
Example #3
0
    def process(this, msg: communicator.Message):

        # If we're not already in the CommandHandler worker thread, then
        # do the work in that thread, in the background.

        if threading.current_thread(
        ) != this:  # Ensure we're in worker thread.
            this(lambda: this.process(msg))
            return

        self = this  # Our thready self is this very object that we are operating on.

        #        logger.debug("CommandHandler.process(): Processing the message: [%s]..." % msg.data.strip())

        try:
            cmd = Command(msg)  # Parse message into command/argument words.
        except EmptyCommand:
            logger.info(
                "CommandHandler.process(): Ignoring empty command [%s]." %
                msg.data)
            return

            # For the moment, we are assuming that all commands are originating
            # from sensor nodes, and that the first argument to every command
            # is the node's ID (0,1,2,3).  However, this is really an unnecessary
            # convention for all but the POWERED_ON message, because all subsequent
            # messages from a given node will be received on a Connection that is
            # already associated with that node.  So, consider changing this.  It
            # would require some extensive rewriting though.  Also, even if we don't
            # do that, really, we should check for the node number only if this is a
            # command that isn't coming from the user (operator of server app), as
            # opposed to coming from a remote node.  Should Messages be marked
            # with their source?  Or should we just be more flexible in our parsing?
            # Some commands may not make sense to associate with nodes at all, e.g.
            # a server shutdown command.  Need to think this through properly, and
            # figure out what's really the right way to handle things.

        nodenum = self.parseNodeNum(
            cmd)  # Extract node number from command line.
        #\_ Also updates component in log context.

        # Now that we know the node number that this command claims to be coming
        # from, we take this at face value, and assume that the entire connection
        # on which we received that message is the main connection associated with
        # that node number, and change the connection window's title accordingly.
        # Please observe that this is a very brittle thing to do, because it only
        # really makes sense for node-specific commands received over a MainServer
        # connection.  See the comment above the previous line of code.  So, for
        # example, if the user tries to type a command on the console, the following
        # line will at present cause the command-handler thread to raise an exception
        # and exit, effectively crippling the server.

        if hasattr(
                msg.conn, 'term'
        ):  # Is the connection this message came from even associated with a terminal widget?
            msg.conn.term.set_title("Node #%d Main Server Connection #%d" %
                                    (nodenum, msg.conn.cid))

            # Finally, we are ready to try dispatching the command for execution.

        try:
            # Note to self, the "msg" above, a Communicator message,
            # does not have exactly the same fields as the original
            # Message class objects defined in this file.  This may
            # cause problems.  Need to fix them. - Obsolete comment?

            self.dispatch_command(cmd)

        except Exception as e:
            logger.error(
                "CommandHandler.process(): Caught an exception [%s] while dispatching command [%s].  Ignoring."
                % (str(e), cmd.cmdString))

        finally:
            # Most command handlers will temporarily change the "component"
            # field in this thread's logging context to the name of whatever
            # node sent the command, to facilitate debugging.  Here, we change
            # it back to "server" to avoid confusion when debugging the command
            # parse-and-dispatch process.

            logmaster.setComponent("server")
Example #4
0
    def process(this, msg: communicator.Message):

        # If we're not already in the CommandHandler worker thread, then
        # do the work in that thread, in the background.

        if threading.current_thread() != this:  # Ensure we're in worker thread.
            this(lambda: this.process(msg))
            return

        self = this  # Our thready self is this very object that we are operating on.

        #        logger.debug("CommandHandler.process(): Processing the message: [%s]..." % msg.data.strip())

        try:
            cmd = Command(msg)  # Parse message into command/argument words.
        except EmptyCommand:
            logger.info("CommandHandler.process(): Ignoring empty command [%s]." % msg.data)
            return

            # For the moment, we are assuming that all commands are originating
            # from sensor nodes, and that the first argument to every command
            # is the node's ID (0,1,2,3).  However, this is really an unnecessary
            # convention for all but the POWERED_ON message, because all subsequent
            # messages from a given node will be received on a Connection that is
            # already associated with that node.  So, consider changing this.  It
            # would require some extensive rewriting though.  Also, even if we don't
            # do that, really, we should check for the node number only if this is a
            # command that isn't coming from the user (operator of server app), as
            # opposed to coming from a remote node.  Should Messages be marked
            # with their source?  Or should we just be more flexible in our parsing?
            # Some commands may not make sense to associate with nodes at all, e.g.
            # a server shutdown command.  Need to think this through properly, and
            # figure out what's really the right way to handle things.

        nodenum = self.parseNodeNum(cmd)  # Extract node number from command line.
        # \_ Also updates component in log context.

        # Now that we know the node number that this command claims to be coming
        # from, we take this at face value, and assume that the entire connection
        # on which we received that message is the main connection associated with
        # that node number, and change the connection window's title accordingly.
        # Please observe that this is a very brittle thing to do, because it only
        # really makes sense for node-specific commands received over a MainServer
        # connection.  See the comment above the previous line of code.  So, for
        # example, if the user tries to type a command on the console, the following
        # line will at present cause the command-handler thread to raise an exception
        # and exit, effectively crippling the server.

        if hasattr(
            msg.conn, "term"
        ):  # Is the connection this message came from even associated with a terminal widget?
            msg.conn.term.set_title("Node #%d Main Server Connection #%d" % (nodenum, msg.conn.cid))

            # Finally, we are ready to try dispatching the command for execution.

        try:
            # Note to self, the "msg" above, a Communicator message,
            # does not have exactly the same fields as the original
            # Message class objects defined in this file.  This may
            # cause problems.  Need to fix them. - Obsolete comment?

            self.dispatch_command(cmd)

        except Exception as e:
            logger.error(
                "CommandHandler.process(): Caught an exception [%s] while dispatching command [%s].  Ignoring."
                % (str(e), cmd.cmdString)
            )

        finally:
            # Most command handlers will temporarily change the "component"
            # field in this thread's logging context to the name of whatever
            # node sent the command, to facilitate debugging.  Here, we change
            # it back to "server" to avoid confusion when debugging the command
            # parse-and-dispatch process.

            logmaster.setComponent("server")