Skip to content

util/service: Add the generic loopback transport - #498

Draft
chrysh wants to merge 2 commits into
OpenPRoT:ocp-global-demo-wipfrom
9elements:service-loopback
Draft

chrysh wants to merge 2 commits into
OpenPRoT:ocp-global-demo-wipfrom
9elements:service-loopback

Conversation

@chrysh

@chrysh chrysh commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

i2c and pldm each wrote their own loopback, both the same shape around a different dispatch function. Loopback<D, N> is that shape once, over the Dispatch trait.

The point is that the server implementation running behind a kernel channel in production is the one answering here, so a host test exercises the real encode, dispatch and decode paths instead of a stand-in.

It implements both transport traits, because an in-process call can serve either. That is also its limit: the response exists the moment the request does, so poll never returns Ok(None). Testing an event loop's not-ready handling needs a real channel, which is what the QEMU test in #497 does.

N sizes the response buffer the async path holds between start and poll. The blocking path writes into the caller's buffer and does not use it.

Nine unit tests: both transport shapes, a response that does not fit on each path, double start, poll and cancel with nothing in flight, and a dispatch that cannot answer at all.

Not in here: the i2c and pldm migrations that delete their local loopbacks, and the typed clients.

Review the last commit only; below it is #485.

Progress toward 9elements#13.

Every IPC service so far has defined its own copy of the same three
seams: a transport trait, a server dispatch function, and the error
type between them. i2c and pldm each carry one, and they have already
drifted apart. This crate holds them once so a service defines its
wire format and nothing else.

Transport blocks until the response arrives; AsyncTransport splits the
round-trip so an event-loop caller never blocks. A type implements
whichever it can serve, or both.

Dispatch is the server end, one request frame in, one response frame
out. It returns Result rather than a byte count with 0 meaning failure:
a service that merely failed an operation encodes that into the response
frame and still returns Ok, and the one case with nothing to send back
is a response buffer too small to hold even an error frame.

Traits only, no implementations and no migrations, so there is nothing
to unit test here. The generic loopback and the kernel channel
transport follow, then i2c and pldm move over.

Assisted-by: Claude Code
i2c and pldm each wrote their own loopback, both the same shape around a
different dispatch function. Loopback<D, N> is that shape once, over the
Dispatch trait: the server implementation that runs behind a kernel
channel in production answers in-process here, so a host test exercises
the real encode, dispatch and decode paths.

It serves both transport traits because an in-process call can, and that
is also its limit: the response exists the moment the request does, so
poll never returns Ok(None). Testing an event loop's not-ready handling
needs a real channel.

N sizes the response buffer the async path holds between start and poll.
The blocking path writes into the caller's buffer and does not use it.

Assisted-by: Claude Opus 5

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant