"""Thread/event-queue interface shared by connection adapters. The GUI enqueues payload bytes in commands and consumes events. Only a worker touches its transport; workers never call Tk. Settings are never retried automatically because repeating a remote key could perform an action twice. """ import queue import threading from controller.commands import initial_queries from controller.session import Update class ConnectionWorker(threading.Thread): def __init__(self, target, events): super().__init__(daemon=True) self.port = target self.events = events self.commands = queue.Queue(maxsize=32) self.stopped = threading.Event() def run(self): try: self.work() except Exception as exc: self.events.put(("log", f"ERROR {type(exc).__name__}: {exc}")) self.events.put(("error", str(exc))) finally: self.events.put(("closed", None)) def work(self): raise NotImplementedError def stop(self): self.stopped.set() def publish(self, update: Update): """Deliver replies and queue initial queries once per handshake.""" for frame in update.frames: self.events.put(("frame", frame)) if not frame.checksum_valid: self.events.put( ( "log", "RX checksum differs from known rules; retained payload " + frame.payload.hex(" "), ) ) if frame.kind and frame.payload: self.events.put(("payload", frame.payload)) if update.became_ready: self.events.put(("ready", None)) for payload in initial_queries(): self.commands.put_nowait(payload)