Skip to main content

moqtap_proxy/
types.rs

1//! The words the rest of the crate keys on.
2//!
3//! Five leaf types, each a plain `Copy` value with no behaviour: which side of
4//! the proxy a frame moves over, which of the two connections a call is about,
5//! which kind of data stream is being read, what a framed object is, and why
6//! the framer stopped framing one. Twenty-eight `use` edges from fourteen
7//! modules reach for them.
8//!
9//! Nothing here imports anything from this crate, which is the property that
10//! keeps those edges pointing one way. A leaf type living wherever it was
11//! first needed reverses them instead: `framer` taking a field of its own
12//! output type from `parser::data`, `event` taking two fields of an event
13//! from `framer` and `transport`.
14//!
15//! **Every one of the five is also re-exported from the module that owns its
16//! subject**, so `event::ProxySide`, `transport::Leg`, `framer::ObjectMeta`,
17//! `framer::BypassReason` and `parser::data::DataStreamType` all resolve.
18//! A downstream match on `ProxySide` with no wildcard arm keeps compiling, and
19//! nothing outside this crate has to move.
20
21use moqtap_codec::dispatch::AnyFetchEndOfRange;
22use moqtap_codec::version::DraftVersion;
23
24/// Which side of the proxy a message originates from.
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum ProxySide {
27    /// Client → Proxy (downstream ingress).
28    ClientToProxy,
29    /// Proxy → Relay (upstream egress).
30    ProxyToRelay,
31    /// Relay → Proxy (upstream ingress).
32    RelayToProxy,
33    /// Proxy → Client (downstream egress).
34    ProxyToClient,
35}
36
37/// Which of the proxy's two connections a call is about.
38///
39/// **Not [`ProxySide`]**, which this crate also
40/// has and which names something else entirely. A leg is a *connection*:
41/// the proxy holds exactly two, one to the client and one to the upstream
42/// relay, and each has its own endpoint, its own socket, its own
43/// certificate and its own transport parameters. A side is a *direction of
44/// travel* over a leg, which is why `ProxySide` has four variants where
45/// this has two — `ClientToProxy` and `ProxyToClient` are the two
46/// directions of the client leg, `ProxyToRelay` and `RelayToProxy` the two
47/// of the upstream leg.
48///
49/// The two are worth keeping straight because the compiler will not: both are
50/// small `Copy` enums that a reader skims as *which part of the proxy*. The
51/// test is what the thing being described belongs to. Anything QUIC settles
52/// once for a whole connection — a window, an MTU, a congestion controller, a
53/// socket — is a leg. Anything a single frame can be observed in or acted on —
54/// an event, a shaping rule, a hook site — is a side.
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub enum Leg {
57    /// The connection between a client and this proxy.
58    Client,
59    /// The connection between this proxy and the upstream relay.
60    Upstream,
61}
62
63/// The expected type of data stream.
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65pub enum DataStreamType {
66    /// Subgroup data stream (most common).
67    Subgroup,
68    /// Fetch response data stream.
69    Fetch,
70}
71
72/// A framed object's identity and framing, without its payload.
73///
74/// Every field is a primitive, so an observer never has to name a
75/// per-draft codec type to key on an object. Produced by
76/// [`ObjectFramer`](crate::framer::ObjectFramer).
77#[derive(Debug, Clone, Copy, PartialEq, Eq)]
78pub struct ObjectMeta {
79    /// The draft this stream was parsed as.
80    pub draft: DraftVersion,
81    /// Whether this object came from a subgroup or a fetch stream.
82    pub stream_kind: DataStreamType,
83    /// Track alias from the stream header. `None` on fetch streams, whose
84    /// headers carry a request ID instead.
85    pub track_alias: Option<u64>,
86    /// Group ID: from the stream header on subgroup streams, from the
87    /// object itself on fetch streams.
88    pub group_id: u64,
89    /// Subgroup ID. `None` when the frame has none to report, which
90    /// happens two ways.
91    /// On a subgroup stream, when the stream type encodes an implicit subgroup
92    /// ID that this draft never resolves — drafts 11 through 23 define a
93    /// *subgroup ID is the first object's ID* mode that the codec stores as
94    /// zero, and reporting that zero would mis-key any matcher.
95    ///
96    /// On a fetch stream, when the frame carried no Subgroup ID at all:
97    /// from draft-15 a fetch object may be marked as having been forwarded
98    /// over a datagram, which has no subgroup, and an End of Range
99    /// indicator names a Location rather than an object. Both cases reach
100    /// this crate as `has_subgroup_id: false` on the codec's meta, behind
101    /// a subgroup ID field that holds a placeholder — the same zero, and
102    /// the same mis-keying if it were forwarded.
103    pub subgroup_id: Option<u64>,
104    /// Absolute Object ID, resolved from delta encoding on drafts 14-23.
105    pub object_id: u64,
106    /// Publisher priority. `None` when the header set a default-priority
107    /// flag and omitted the field (drafts 15+).
108    pub publisher_priority: Option<u8>,
109    /// Zero-based index of this object within its stream.
110    pub index_in_stream: u64,
111    /// Declared payload length in bytes.
112    pub payload_len: u64,
113    /// Object Status wire code; `None` when a non-empty payload followed.
114    pub status: Option<u64>,
115    /// Which indicator this frame is, or `None` for an object.
116    ///
117    /// Drafts 16-23 let a fetch stream state that a run of Objects was not
118    /// serialized instead of sending them, and draft-23 adds End of Group and
119    /// End of Track, which say the Object before them ends its Group or the
120    /// Track and carry that Object's Location. These frames arrive through
121    /// the same reader call as objects do. They are **not** objects: they
122    /// carry no payload and no content, and one of them standing in a
123    /// count of objects is a count that is wrong. An observer that means
124    /// "objects" filters on this being `None`; one that means "frames"
125    /// does not.
126    ///
127    /// Always `None` on a subgroup stream, and on every fetch stream of
128    /// drafts 07-15, which have no such frame.
129    pub end_of_range: Option<AnyFetchEndOfRange>,
130}
131
132/// Why [`ObjectFramer`](crate::framer::ObjectFramer) stopped parsing a stream.
133#[derive(Debug, Clone, Copy, PartialEq, Eq)]
134#[non_exhaustive]
135pub enum BypassReason {
136    /// The header decoded but the object reader rejected this subgroup
137    /// stream type.
138    UnsupportedSubgroupStreamType,
139    /// This build compiled no object reader for the fetch stream's draft,
140    /// so the stream is forwarded intact from its header on.
141    ///
142    /// Defensive rather than routine. The stream *header* decodes first and
143    /// fails first on a draft that was not compiled, reporting
144    /// [`Self::DecodeError`], so a session reaches this only if the header
145    /// dispatch and the object-reader dispatch ever disagree about which
146    /// drafts this binary speaks.
147    NoFetchObjectCodec,
148    /// A fetch stream on drafts 18-23 naming a request this
149    /// session never saw asked for.
150    ///
151    /// Those drafts write an Object's Group ID as a difference from the
152    /// previous Object's, and the fetch's Group Order decides which way the
153    /// difference points — draft-19 Section 11.4.4.1: "If the Group Order is
154    /// Ascending, the Group ID is the prior Object's Group ID plus the Group
155    /// ID Delta + 1. If the Group Order is Descending, the Group ID is the
156    /// prior Object's Group ID minus the (Group ID Delta + 1)."
157    ///
158    /// Nothing on the data stream states the order. It is on the FETCH the
159    /// stream answers — draft-19 Section 10.2.8: "If omitted from FETCH, the
160    /// receiver uses Ascending (0x1)" — so a session that carried the FETCH
161    /// knows it, files it under that Request ID, and hands it to the framer
162    /// when the response stream opens. See
163    /// [`FetchGroupOrders`](crate::framer::FetchGroupOrders).
164    ///
165    /// What is left for this variant is the stream whose FETCH never came
166    /// past: a publisher answering a request nobody made, a session whose
167    /// control plane is a byte pump because nothing frames its data either,
168    /// or a hook that rewrote a FETCH into bytes that no longer decode.
169    ///
170    /// Guessing would not fail loudly, which is why an unanswered stream is
171    /// bypassed rather than read against the draft's default. A descending
172    /// stream read as ascending decodes every Object and every field of it;
173    /// only the Group IDs are wrong, walking up where the publisher sent them
174    /// walking down. Every event reported off this stream and every shaping
175    /// rule keyed on a group would then be wrong with nothing to say so. The
176    /// bytes are forwarded untouched instead.
177    FetchGroupOrderUnknown,
178    /// An object could not be measured within the buffer cap's reach.
179    ObjectBeyondMeasuringReach,
180    /// A header or object failed to decode. Also reported as
181    /// [`FramerOut::Error`](crate::framer::FramerOut::Error).
182    DecodeError,
183}