microsandbox_protocol_client/protocol.rs
1//! Public protocol extension boundary; no knowledge of agent or control ops.
2
3use std::sync::Arc;
4
5use microsandbox_protocol::wire::Envelope;
6
7use crate::{
8 BoxFuture, BoxTransport, ClientError, ClientLimits, ClientResult, ConnectOptions, ErrorKind,
9 Message,
10};
11
12//--------------------------------------------------------------------------------------------------
13// Types
14//--------------------------------------------------------------------------------------------------
15
16/// Protocol-specific setup and message metadata, leaving routing to `Client`.
17pub trait Protocol: Send + Sync + 'static {
18 /// Whether terminal completion permits reusing a correlation ID.
19 const REUSE_IDS: bool = true;
20 /// Shared immutable metadata negotiated during setup.
21 type Ready: Send + Sync + 'static;
22
23 /// Consume an owned stream and preserve any prefetched bytes in the result.
24 fn establish(
25 stream: BoxTransport,
26 options: ConnectOptions,
27 ) -> BoxFuture<'static, ClientResult<Established<Self::Ready>>>;
28
29 /// Validate availability and select metadata for a named outbound message.
30 fn prepare(ready: &Self::Ready, wire_name: &str) -> ClientResult<SendMetadata>;
31}
32
33/// Envelope semantics chosen during setup. Raw routing never invokes this.
34pub trait EnvelopeCodec: Send + Sync + 'static {
35 /// Encode an envelope without modifying already-encoded payload bytes.
36 fn encode(&self, generation: u8, wire_name: &str, payload: Vec<u8>) -> ClientResult<Vec<u8>>;
37
38 /// Decode an inspectable message while retaining its original wire frame.
39 fn decode(&self, frame: crate::RawFrame) -> ClientResult<Message>;
40}
41
42/// Standard `{v,t,p}` CBOR envelope with an open message namespace.
43#[derive(Debug, Clone, Copy, Default)]
44pub struct CborEnvelopeCodec;
45
46/// Successfully established transport and immutable protocol metadata.
47pub struct Established<R> {
48 /// Exclusive byte transport, including any unread prefetched bytes.
49 pub transport: BoxTransport,
50 /// Envelope codec selected by protocol setup.
51 pub codec: Arc<dyn EnvelopeCodec>,
52 /// Negotiated usable correlation IDs.
53 pub ids: IdRange,
54 /// Protocol-specific welcome/ready metadata.
55 pub ready: R,
56 /// Final connection limits, including peer-negotiated ceilings.
57 pub limits: ClientLimits,
58}
59
60/// Nonzero ID range; the wider upper bound represents the entire u32 space.
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub struct IdRange {
63 /// Inclusive lower bound, at least one.
64 pub start: u32,
65 /// Exclusive upper bound, at most 2^32.
66 pub end_exclusive: u64,
67}
68
69/// Protocol-generated envelope generation and frame flags.
70#[derive(Debug, Clone, Copy)]
71pub struct SendMetadata {
72 /// Envelope generation.
73 pub generation: u8,
74 /// Frame flags, independent of correlation ID allocation.
75 pub flags: u8,
76}
77
78//--------------------------------------------------------------------------------------------------
79// Methods
80//--------------------------------------------------------------------------------------------------
81
82impl IdRange {
83 /// Reject zero, empty, reversed, and overflowing ranges.
84 pub fn validate(self) -> ClientResult<()> {
85 if self.start == 0
86 || u64::from(self.start) >= self.end_exclusive
87 || self.end_exclusive > (1u64 << 32)
88 {
89 return Err(ClientError::new(ErrorKind::InvalidOptions));
90 }
91 Ok(())
92 }
93}
94
95//--------------------------------------------------------------------------------------------------
96// Trait Implementations
97//--------------------------------------------------------------------------------------------------
98
99impl EnvelopeCodec for CborEnvelopeCodec {
100 fn encode(&self, generation: u8, wire_name: &str, payload: Vec<u8>) -> ClientResult<Vec<u8>> {
101 Ok(Envelope {
102 v: generation,
103 t: wire_name.into(),
104 p: payload,
105 }
106 .encode()?)
107 }
108
109 fn decode(&self, frame: crate::RawFrame) -> ClientResult<Message> {
110 let envelope = Envelope::decode(&frame.body)?;
111 Ok(Message::new(frame, envelope))
112 }
113}