aboutsummaryrefslogtreecommitdiffstats
path: root/klippy
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2020-08-11 21:21:41 -0400
committerKevin O'Connor <kevin@koconnor.net>2020-08-16 13:20:26 -0400
commit16a53e6918a6514941095692a2ea588ca5274413 (patch)
tree98ff055f275846a1a22acc63f0b8f9aca2b1ad8e /klippy
parent568393c941df58d6dc0b0cb3dc9488cb1e0d37f3 (diff)
downloadkutter-16a53e6918a6514941095692a2ea588ca5274413.tar.gz
kutter-16a53e6918a6514941095692a2ea588ca5274413.tar.xz
kutter-16a53e6918a6514941095692a2ea588ca5274413.zip
webhooks: Require a subscription to receive gcode output
Add a new "gcode/subscribe_output" webhook endpoint to subscribe to gcode output. Only client connections that subscribe to the gcode output will receive that output. This also moves all the gcode webhooks from gcode.py to webhooks.py and arranges for gcode.py to be initialized prior to webhooks.py. Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Diffstat (limited to 'klippy')
-rw-r--r--klippy/gcode.py21
-rw-r--r--klippy/klippy.py2
-rw-r--r--klippy/webhooks.py62
3 files changed, 53 insertions, 32 deletions
diff --git a/klippy/gcode.py b/klippy/gcode.py
index 91e78ffa..9bacfbfa 100644
--- a/klippy/gcode.py
+++ b/klippy/gcode.py
@@ -78,16 +78,6 @@ class GCodeParser:
self._handle_disconnect)
printer.register_event_handler("extruder:activate_extruder",
self._handle_activate_extruder)
- # Register webhooks
- webhooks = self.printer.lookup_object('webhooks')
- webhooks.register_endpoint(
- "gcode/help", self._handle_remote_help)
- webhooks.register_endpoint(
- "gcode/script", self._handle_remote_script)
- webhooks.register_endpoint(
- "gcode/restart", self._handle_remote_restart)
- webhooks.register_endpoint(
- "gcode/firmware_restart", self._handle_remote_firmware_restart)
# Command handling
self.is_printer_ready = False
self.mutex = printer.get_reactor().mutex()
@@ -158,6 +148,8 @@ class GCodeParser:
"mux command %s %s %s already registered (%s)" % (
cmd, key, value, prev_values))
prev_values[value] = func
+ def get_command_help(self):
+ return dict(self.gcode_help)
def register_output_handler(self, cb):
self.output_callbacks.append(cb)
def set_move_transform(self, transform, force=False):
@@ -617,15 +609,6 @@ class GCodeParser:
if cmd in self.gcode_help:
cmdhelp.append("%-10s: %s" % (cmd, self.gcode_help[cmd]))
gcmd.respond_info("\n".join(cmdhelp), log=False)
- # Webhooks
- def _handle_remote_help(self, web_request):
- web_request.send(dict(self.gcode_help))
- def _handle_remote_restart(self, web_request):
- self.run_script('restart')
- def _handle_remote_firmware_restart(self, web_request):
- self.run_script('firmware_restart')
- def _handle_remote_script(self, web_request):
- self.run_script(web_request.get('script'))
# Support reading gcode from a pseudo-tty interface
class GCodeIO:
diff --git a/klippy/klippy.py b/klippy/klippy.py
index 33a96a7a..838a43c0 100644
--- a/klippy/klippy.py
+++ b/klippy/klippy.py
@@ -59,7 +59,7 @@ class Printer:
self.event_handlers = {}
self.objects = collections.OrderedDict()
# Init printer components that must be setup prior to config
- for m in [webhooks, gcode]:
+ for m in [gcode, webhooks]:
m.add_early_printer_objects(self)
def get_start_args(self):
return self.start_args
diff --git a/klippy/webhooks.py b/klippy/webhooks.py
index e923e986..d10f5c2c 100644
--- a/klippy/webhooks.py
+++ b/klippy/webhooks.py
@@ -45,12 +45,16 @@ class Sentinel:
class WebRequest:
error = WebRequestError
- def __init__(self, base_request):
+ def __init__(self, client_conn, base_request):
+ self.client_conn = client_conn
self.id = base_request['id']
self.path = base_request['path']
self.args = base_request['args']
self.response = None
+ def get_client_connection(self):
+ return self.client_conn
+
def get(self, item, default=Sentinel):
if item not in self.args:
if default == Sentinel:
@@ -170,6 +174,9 @@ class ClientConnection:
pass
self.server.pop_client(self.uid)
+ def is_closed(self):
+ return self.fd_handle is None
+
def process_received(self, eventtime):
try:
data = self.sock.recv(4096)
@@ -191,7 +198,7 @@ class ClientConnection:
logging.debug(
"webhooks: Request received: %s" % (req))
try:
- web_request = WebRequest(json_loads_byteified(req))
+ web_request = WebRequest(self, json_loads_byteified(req))
except Exception:
logging.exception(
"webhooks: Error decoding Server Request %s"
@@ -257,21 +264,11 @@ class WebHooks:
# Register Events
printer.register_event_handler(
- "klippy:connect", self._handle_connect)
- printer.register_event_handler(
"klippy:shutdown", self._notify_shutdown)
- def _handle_connect(self):
- gcode = self.printer.lookup_object('gcode')
- gcode.register_output_handler(self._process_gcode_response)
-
def _notify_shutdown(self):
self.call_remote_method("set_klippy_shutdown")
- def _process_gcode_response(self, gc_response):
- self.call_remote_method(
- "process_gcode_response", response=gc_response)
-
def register_endpoint(self, path, callback):
if path in self._endpoints:
raise WebRequestError("Path already registered to an endpoint")
@@ -318,6 +315,46 @@ class WebHooks:
"action_call_remote_method": self._action_call_remote_method
}
+class GCodeHelper:
+ def __init__(self, printer):
+ self.printer = printer
+ self.gcode = printer.lookup_object("gcode")
+ # Output subscription tracking
+ self.is_output_registered = False
+ self.clients = {}
+ # Register webhooks
+ wh = printer.lookup_object('webhooks')
+ wh.register_endpoint("gcode/help", self._handle_help)
+ wh.register_endpoint("gcode/script", self._handle_script)
+ wh.register_endpoint("gcode/restart", self._handle_restart)
+ wh.register_endpoint("gcode/firmware_restart",
+ self._handle_firmware_restart)
+ wh.register_endpoint("gcode/subscribe_output",
+ self._handle_subscribe_output)
+ def _handle_help(self, web_request):
+ web_request.send(self.gcode.get_command_help())
+ def _handle_script(self, web_request):
+ self.gcode.run_script(web_request.get('script'))
+ def _handle_restart(self, web_request):
+ self.gcode.run_script('restart')
+ def _handle_firmware_restart(self, web_request):
+ self.gcode.run_script('firmware_restart')
+ def _output_callback(self, msg):
+ for cconn, template in list(self.clients.items()):
+ if cconn.is_closed():
+ del self.clients[cconn]
+ continue
+ tmp = dict(template)
+ tmp['params'] = {'response': msg}
+ cconn.send(tmp)
+ def _handle_subscribe_output(self, web_request):
+ cconn = web_request.get_client_connection()
+ template = web_request.get('response_template', {})
+ self.clients[cconn] = template
+ if not self.is_output_registered:
+ self.gcode.register_output_handler(self._output_callback)
+ self.is_output_registered = True
+
SUBSCRIPTION_REFRESH_TIME = .25
class StatusHandler:
@@ -443,4 +480,5 @@ class StatusHandler:
def add_early_printer_objects(printer):
printer.add_object('webhooks', WebHooks(printer))
+ GCodeHelper(printer)
StatusHandler(printer)