tmux-amq/src/tamq/broker.py
tegwick 92881b6b56
Some checks failed
tamq-ci / test (push) Failing after 6s
feat: add readable duplex messaging
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a03397-4d51-7fd1-8ff2-946eb22ea2bc
2026-08-25 19:26:27 +02:00

149 lines
5.3 KiB
Python

from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from .registry import RegistryError, validate_targets
from .routing import RoutedMessage, parse_address_line, parse_command_line
from .store import LimitBlock, Store
from .terminal import format_delivery
@dataclass(frozen=True)
class BrokerIdentity:
endpoint_id: str
source_repo: str
class InputBroker:
"""Convert attributed PTY lines into durable outbound messages."""
def __init__(
self,
store: Store,
identity: BrokerIdentity,
*,
limits: tuple[int, int, int] = (8, 1024, 32768),
notify: Callable[[str], None] | None = None,
):
self.store = store
self.identity = identity
self.notify = notify
self.store.configure_window(identity.endpoint_id, identity.source_repo, limits)
def _notice(self, text: str) -> None:
if self.notify is not None:
self.notify(f"From:tamq: {text}")
def _blocked(self, blocked: LimitBlock) -> None:
self._notice(
"Messaging blocked! Running linecount "
f"{blocked.count} limited by {blocked.limit} lines of {blocked.dimension} "
"in this terminal. Use 'Cmd: reset-limits' to unblock."
)
def _route(self, line: str, provenance: str) -> RoutedMessage | None:
routed = parse_address_line(line)
if routed is None:
return None
try:
validate_targets([routed.target_repo])
except RegistryError:
return None
result = self.store.admit_message(
self.identity.source_repo,
routed.target_repo,
routed.body,
endpoint=self.identity.endpoint_id,
source_repo=self.identity.source_repo,
provenance=provenance,
)
if isinstance(result, LimitBlock):
self._blocked(result)
return None
return routed
def inspect_operator_line(self, line: str) -> RoutedMessage | None:
"""Observe one submitted operator line; it is still forwarded unchanged."""
if line.startswith("From:"):
return None
self.store.count_line(
self.identity.endpoint_id, self.identity.source_repo, "input"
)
command = parse_command_line(line)
if command is not None:
self._command(command)
return None
return self._route(line, "operator_input")
def inspect_worker_line(self, line: str) -> RoutedMessage | None:
"""Observe worker output; Cmd is intentionally inert on this path."""
if line.startswith("From:"):
return None
self.store.count_line(
self.identity.endpoint_id, self.identity.source_repo, "output"
)
return self._route(line, "worker_output")
def inspect_line(self, line: str) -> RoutedMessage | None:
"""Compatibility entry point for operator-input observers."""
return self.inspect_operator_line(line)
def _command(self, command: str) -> None:
if command == "reset-limits":
self.store.reset_limits(
self.identity.endpoint_id, self.identity.source_repo
)
self._notice("Limits reset for this terminal.")
return
if "=" not in command:
self._notice(f"Unknown command: {command}")
return
name, value = (part.strip() for part in command.split("=", 1))
if name == "mode":
if value not in {"inbox", "output", "pushy", "trigger"}:
self._notice(f"Invalid mode: {value}")
return
if not self.store.set_endpoint_mode(self.identity.endpoint_id, value):
self._notice("Cannot change mode before endpoint registration.")
return
self._notice(f"Mode set to {value}.")
return
if name in {"maxmsg", "maxin", "maxout"}:
try:
parsed = int(value)
self.store.set_window_limit(
self.identity.endpoint_id,
self.identity.source_repo,
name,
parsed,
)
except ValueError as exc:
self._notice(str(exc))
return
self._notice(f"{name} set to {parsed} for this terminal.")
return
self._notice(f"Unknown command: {name}")
def deliver_pending(self, control, *, window_for_repo):
"""Place pending messages through the authoritative control client."""
delivered = 0
for row in self.store.list(state="pending"):
if row["endpoint_id"] not in (None, self.identity.endpoint_id):
continue
target = window_for_repo(row["target_repo"])
lease_id = self.store.claim(row["message_id"], self.identity.endpoint_id)
if lease_id is None:
continue
try:
control.inject(
target,
format_delivery(
row["sender_repo"], row["body"], row["provenance"]
),
)
except Exception:
continue
self.store.release(row["message_id"], lease_id, "injected")
delivered += 1
return delivered