degenbot.operator ================= .. py:module:: degenbot.operator .. autoapi-nested-parse:: Operator control surface for a live bot. A Unix-domain-socket command channel (":mod:`degenbot.operator.operator_channel`") that lets an operator steer a running bot — add a specific path or trigger a bounded on-demand discovery — without touching its process. The host runs an :class:`~degenbot.operator.operator_channel.OperatorServer`; the ``degenbot path add`` / ``degenbot path discover`` CLI writes commands to it. Submodules ---------- .. toctree:: :maxdepth: 1 /autoapi/degenbot/operator/operator_channel/index Package Contents ---------------- .. py:data:: OperatorHandler .. py:class:: OperatorServer(handler: OperatorHandler, *, socket_path: str, request_timeout: float = 60.0) A Unix-domain-socket command server for a live bot. Run :meth:`serve` as an asyncio task (e.g. a background task on the registration loop). It accepts one or more concurrent client connections, reads one JSON request line, routes it to the wrapped handler, and writes one JSON response line. The handler is wrapped by :func:`wrap_handler` so a failing command replies with ``{"ok": false}`` instead of raising into the host. :param handler: async ``(op, payload) -> dict`` (see :data:`OperatorHandler`). :param socket_path: filesystem path for the Unix domain socket. :param request_timeout: seconds to wait for a request line before dropping the connection (default 60). .. py:method:: serve() -> None :async: Start the socket server and accept connections until closed. Runs forever (cancellable); the caller starts it with ``asyncio.create_task`` and cancels it on shutdown. The ``serve_forever`` loop runs as its own future so :meth:`close` can cancel it (without that, ``wait_closed`` in ``close`` would block on the still-pending loop). .. py:method:: wait_ready(timeout_s: float = 5.0) -> None :async: Wait until :meth:`serve` has bound the socket and is listening. :param timeout_s: seconds to wait before raising :class:`TimeoutError`. .. py:method:: close() -> None :async: Stop accepting connections and remove the socket file. Self-sufficient: cancels the in-flight ``serve_forever`` loop (so ``wait_closed()`` cannot block on it) then closes the server and unlinks the socket. Safe to call whether ``serve()`` is still running, was cancelled by the host, or is running on another thread's event loop. .. py:class:: StepSpec A hop descriptor in the discovery-item shape the pipeline consumes. .. attribute:: type The typed pool family for the hop (V2/V3/V4). .. attribute:: address The pool address (``0x`` + 40 hex). .. attribute:: hash The V4 pool id (``0x`` + 64 hex) when ``type`` is ``PoolKind.V4``. .. py:attribute:: type :type: degenbot.pathfinding.PoolKind .. py:attribute:: address :type: str .. py:attribute:: hash :type: object | None :value: None .. py:function:: send_command(socket_path: str, op: str, payload: dict[str, Any]) -> dict[str, Any] :async: Connect to a running :class:`OperatorServer` and send one command. :param socket_path: the Unix domain socket path the server listens on. :param op: command op (``add_path`` / ``discover``). :param payload: the command payload. :returns: The server's response dict (``{"ok": bool, "detail"/"error": ...}``). :raises RuntimeError: if the server sends no response line. .. py:function:: step_from_wire(step: dict[str, Any]) -> StepSpec Translate a wire ``steps`` entry into a :class:`StepSpec`. :param step: ``{"family": "V2|V3|V4", "address": "0x..", "hash": "0x.."?}``. :returns: A :class:`StepSpec` mapping ``family`` to its typed pool kind. :raises ValueError: if ``family`` is not V2/V3/V4 or ``address`` is absent.