pub struct BridgeLoop<U, C, S, K>{ /* private fields */ }Expand description
Carries frames from a downstream peer, through a Bridge, back to it.
§The handshake happens here, not upstream
A bridge is a server to the client in front of it, so the loop answers
initialize itself rather than letting the request reach the upstream. That
is what keeps the client on the revision the bridge chose and tells it only
the capabilities the bridge can actually serve; forwarding the handshake
would hand the client the upstream’s own answers to both questions.
Before a handshake completes, a request is refused rather than forwarded — the specification requires it, and a bridge that forwarded one would speak for a client the upstream had never accepted.
notifications/initialized is answered locally and not forwarded. The
upstream session was initialised when the bridge connected, before any
client existed; forwarding this one would tell the upstream a second client
had arrived, describing a session it already considers open.
§What a loop knows before a client arrives
Only one leg. The upstream negotiated with its server when the bridge
connected; the client that supplies the other leg has not shown up yet, and
inventing one would put a second opinion next to the real one. So
agreement is None until a handshake completes, and a
caller reporting on a bridge can tell “these two sides share nothing” from
“no client ever arrived” — a distinction a placeholder leg would erase.
§Examples
use protocol_droid::application::bridge::{BridgeLoop, ToolResultCodec, Wiring};
let wiring = Wiring::new(upstream, policy, server, codec);
let mut bridge_loop = BridgeLoop::new(wiring, config, source, sink);Implementations§
Source§impl<U, C, S, K> BridgeLoop<U, C, S, K>
impl<U, C, S, K> BridgeLoop<U, C, S, K>
Sourcepub const fn new(
wiring: Wiring<U, C>,
config: DownstreamConfig,
source: S,
sink: K,
) -> Self
pub const fn new( wiring: Wiring<U, C>, config: DownstreamConfig, source: S, sink: K, ) -> Self
A loop waiting for a client’s handshake.
Sourcepub fn agreement(&self) -> Option<&Agreement>
pub fn agreement(&self) -> Option<&Agreement>
What this bridge knows about its two sides.
None until a handshake completes: there is one leg until then, and an
agreement needs two. Inventing the missing one would put a second,
fabricated opinion next to the real one.
Sourcepub async fn run(&mut self) -> Result<LoopReport, LoopError>
pub async fn run(&mut self) -> Result<LoopReport, LoopError>
Runs until the downstream peer’s stream ends.
The handshake is part of this, not a separate step the caller has to
remember: a caller that forgot it would forward a client’s initialize
upstream and answer them with someone else’s capabilities.
§Errors
LoopError when the downstream pipe itself fails, or when a reply the
bridge built cannot be written. A refusal from the upstream peer is not
an error here — it is answered to the client and counted in
LoopReport::failed.