diff --git a/docs/plugins/hooks.rst b/docs/plugins/hooks.rst index bc444a05..cb9a5cc8 100644 --- a/docs/plugins/hooks.rst +++ b/docs/plugins/hooks.rst @@ -426,7 +426,7 @@ This describes actually four hooks: * ``None``: Don't change anything. Note that Python functions will also automatically return ``None`` if an empty ``return`` statement is used or just nothing is returned explicitly from the handler. Hence, the following - examples are all falling into this category: + examples are all falling into this category and equivalent: .. code-block:: python @@ -451,21 +451,24 @@ This describes actually four hooks: should use this option. * A 2-tuple consisting of a rewritten version of the ``cmd`` and the ``cmd_type``, e.g. ``return "M105", "temperature_poll"``. Handlers which wish to rewrite both the command and the command type should use this option. - * A list of any of the above to allow for expanding one command into + * **"queuing" phase only**: A list of any of the above to allow for expanding one command into many. The following example shows how any queued command could be turned into a sequence of a temperature query, line number reset, display of the ``gcode`` on the printer's display and finally the actual command (this example does not make a lot of sense to be quite honest): .. code-block:: python - def rewrite_foo(self, comm_instance, phase, cmd, cmd_type, gcode, *args, **kwargs): - if gcode or not cmd.startswith("@foo"): - return + def rewrite_foo(self, comm_instance, phase, cmd, cmd_type, gcode, *args, **kwargs): + if gcode or not cmd.startswith("@foo"): + return - return [("M105", "temperature_poll"), - ("M110",), - "M117 echo foo: {}".format(cmd)] + return [("M105", "temperature_poll"), # 2-tuple, command & command type + ("M110",), # 1-tuple, just the command + "M117 echo foo: {}".format(cmd)] # string, just the command + __plugin_hooks__ = { + "octoprint.comm.protocol.gcode.queuing": rewrite_foo + } Note: Only one command of a given ``cmd_type`` (other than None) may be queued at a time. Trying to rewrite the ``cmd_type`` to one already in the queue will give an error. diff --git a/src/octoprint/util/comm.py b/src/octoprint/util/comm.py index f8c50eec..299efc19 100644 --- a/src/octoprint/util/comm.py +++ b/src/octoprint/util/comm.py @@ -2255,18 +2255,13 @@ class MachineCom(object): # and now let's fetch the next item from the queue continue - if len(results) > 1: - with self._sendingLock: - # prepend reversed (so order gets restored) - to_prepend = reversed(results[1:-1]) - for m in to_prepend: - try: - self._send_queue.prepend((m[0], None, m[1], on_sent, True), item_type=m[1]) - on_sent = None - except TypeAlreadyInQueue: - pass + # we explicitly throw away plugin hook results that try + # to perform command expansion in the sending/sent phase, + # so "results" really should only have more than one entry + # at this point if our core code contains a bug + assert len(results) == 1 - # we only actually send the first entry here + # we only use the first (and only!) entry here command, _, gcode, subcode = results[0] if command.strip() == "": @@ -2341,7 +2336,13 @@ class MachineCom(object): self._logger.exception("Error while processing hook {name} for phase {phase} and command {command}:".format(**locals())) else: normalized = _normalize_command_handler_result(command, command_type, gcode, subcode, hook_results) - new_results += normalized + + # make sure we don't allow multi entry results in anything but the queuing phase + if not phase in ("queuing",) and len(normalized) > 1: + self._logger.error("Error while processing hook {name} for phase {phase} and command {command}: Hook returned multi-entry result for phase {phase} and command {command}. That's not supported, if you need to do multi expansion of commands you need to do this in the queuing phase. Ignoring hook result and sending command as-is.".format(**locals())) + new_results.append((command, command_type, gcode, subcode)) + else: + new_results += normalized if not new_results: # hook handler returned None or empty list for all commands, so we'll stop here and return a full out empty result return []