Skip to main content

Module stomp

Module stomp 

Source
Expand description

STOMP 1.2 client implementation.

§The handshake is a gate, not a formality

connect() does not return until the broker has answered CONNECT with a well-formed CONNECTED carrying a version header naming 1.2. Anything else — an ERROR, a CONNECTED with no version, a version we did not offer, some other command, silence until the timeout, or a closed socket — is an Err, so client_startup records ClientStatus::Error and no stomp_connected event is ever raised. This is exactly the strictness async-stomp applies to our server (its Connector::connect() refuses to hand back a transport otherwise), and it is the difference between a client that reports a session and a client that has one.

§No per-connection state machine, deliberately

src/server/tcp/mod.rs carries Idle/Processing/Accumulating because raw TCP has no frame boundaries, so a second read arriving mid-LLM-call has to be queued somewhere. STOMP has frame boundaries: this loop reads, parses out whole frames, and handles them one at a time in the same task. Bytes arriving during a model call sit in the socket buffer — TCP’s own backpressure — and are parsed on the next pass. There is no window in which two model calls could overlap on this connection, so there is nothing to track.

§Why there is no boxed follow-up recursion here

The root CLAUDE.md requires a depth-bounded, boxed recursive call for clients whose action → event → action cycle is self-referential in-process. This client’s cycle is not: every action it can take puts a frame on the wire, and the answer comes back as another frame that the same read loop parses and reports. The chain continues by itself, through the socket, exactly as datalink’s does through its pcap queue — so the model can subscribe, be told about the MESSAGE that arrives, and publish in response, without any function here calling itself. The only bound needed is the one every client already has, client/llm_budget.rs.

§Graceful shutdown

The disconnect action does not hang up. It writes DISCONNECT with a fixed receipt (actions::DISCONNECT_RECEIPT_ID) and this loop closes when the matching RECEIPT arrives — the specification’s shutdown, and the only thing that tells a publisher the broker durably took what it sent. A broker that never answers is bounded by [DISCONNECT_GRACE] rather than leaving the loop parked forever.

Re-exports§

pub use actions::StompClientProtocol;

Modules§

actions
STOMP 1.2 client actions.

Structs§

StompClient
STOMP 1.2 client.