Skip to main content

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}