Skip to main content

moqtap_codec/draft13/
fields.rs

1use crate::draft13::message::*;
2use crate::fields::{FieldMap as Map, FieldValue as Value};
3use crate::kvp::{KeyValuePair, KvpValue};
4use crate::types::*;
5use crate::varint::VarInt;
6
7fn vi(v: u64) -> Value {
8    Value::Uint(v)
9}
10
11fn ns_to_json(ns: &TrackNamespace) -> Value {
12    Value::Array(
13        ns.0.iter().map(|e| Value::Text(String::from_utf8_lossy(e).into_owned())).collect(),
14    )
15}
16
17fn loc_to_json(loc: &Location) -> Value {
18    let mut o = Map::new();
19    o.insert("group".into(), vi(loc.group.into_inner()));
20    o.insert("object".into(), vi(loc.object.into_inner()));
21    Value::Map(o)
22}
23
24/// Parse an authorization_token byte value into JSON.
25///
26/// # What a value it cannot read renders as
27///
28/// The raw bytes, as `fields::params` and every other draft's renderer do, and
29/// a field the value ran out before is simply absent. Field extraction runs on
30/// a message that has already decoded, so it has no refusal to give: what a
31/// peer sent is what there is to show.
32///
33/// That the bytes are a Token at all is not something this can assume. This
34/// function is reached from `setup_option_name`, whose whole purpose is asking
35/// a second draft about a parameter that arrived under a first — precisely
36/// where nothing has validated it against this draft's rules.
37/// `setup_option_name(13, &KeyValuePair { key: 0x03, value:
38/// KvpValue::Bytes(vec![]) })` is a public call with an empty value.
39fn auth_token_to_json(bytes: &[u8]) -> Value {
40    let mut buf = bytes;
41    let Ok(alias_type) = VarInt::decode(&mut buf) else {
42        return Value::Bytes(bytes.to_vec());
43    };
44    let at = alias_type.into_inner();
45    let mut o = Map::new();
46    o.insert("alias_type".into(), vi(at));
47    match at {
48        // DELETE, USE_ALIAS: only token_alias
49        0 | 2 => {
50            if let Ok(token_alias) = VarInt::decode(&mut buf) {
51                o.insert("token_alias".into(), vi(token_alias.into_inner()));
52            }
53        }
54        // REGISTER: token_alias + token_type + token_value
55        1 => {
56            if let Ok(token_alias) = VarInt::decode(&mut buf) {
57                o.insert("token_alias".into(), vi(token_alias.into_inner()));
58            }
59            if let Ok(token_type) = VarInt::decode(&mut buf) {
60                o.insert("token_type".into(), vi(token_type.into_inner()));
61            }
62            o.insert("token_value".into(), Value::Bytes(buf.to_vec()));
63        }
64        // USE_VALUE (3) or other: token_type + token_value
65        _ => {
66            if let Ok(token_type) = VarInt::decode(&mut buf) {
67                o.insert("token_type".into(), vi(token_type.into_inner()));
68            }
69            o.insert("token_value".into(), Value::Bytes(buf.to_vec()));
70        }
71    }
72    Value::Map(o)
73}
74
75pub(crate) fn kvp_to_json_setup(params: &[KeyValuePair]) -> Value {
76    crate::fields::kvp_entries(params, |key, value| match (key, value) {
77        (0x01, KvpValue::Bytes(b)) => {
78            (Some("path"), Some(Value::Text(String::from_utf8_lossy(b).into_owned())))
79        }
80        (0x02, KvpValue::Varint(v)) => (Some("max_request_id"), Some(vi(v.into_inner()))),
81        (0x03, KvpValue::Bytes(b)) => (Some("authorization_token"), Some(auth_token_to_json(b))),
82        (0x04, KvpValue::Varint(v)) => {
83            (Some("max_auth_token_cache_size"), Some(vi(v.into_inner())))
84        }
85        _ => (None, None),
86    })
87}
88
89fn kvp_to_json_msg(params: &[KeyValuePair]) -> Value {
90    crate::fields::kvp_entries(params, |key, value| match (key, value) {
91        (0x03, KvpValue::Bytes(b)) => (Some("authorization_token"), Some(auth_token_to_json(b))),
92        (0x02, KvpValue::Varint(v)) => (Some("delivery_timeout"), Some(vi(v.into_inner()))),
93        (0x04, KvpValue::Varint(v)) => (Some("max_cache_duration"), Some(vi(v.into_inner()))),
94        _ => (None, None),
95    })
96}
97
98/// This draft's field names for a decoded control message.
99///
100/// Keys are the names this draft gives its fields, in the order it defines
101/// them. An optional field the message did not carry is absent rather than
102/// zero.
103pub fn message_fields(msg: &ControlMessage) -> Map {
104    let obj = match msg {
105        ControlMessage::ClientSetup(m) => {
106            let mut o = Map::new();
107            o.insert(
108                "supported_versions".into(),
109                Value::Array(m.supported_versions.iter().map(|v| vi(v.into_inner())).collect()),
110            );
111            o.insert("parameters".into(), kvp_to_json_setup(&m.parameters));
112            o
113        }
114        ControlMessage::ServerSetup(m) => {
115            let mut o = Map::new();
116            o.insert("selected_version".into(), vi(m.selected_version.into_inner()));
117            o.insert("parameters".into(), kvp_to_json_setup(&m.parameters));
118            o
119        }
120        ControlMessage::GoAway(m) => {
121            let mut o = Map::new();
122            o.insert(
123                "new_session_uri".into(),
124                Value::Text(String::from_utf8_lossy(&m.new_session_uri).into_owned()),
125            );
126            o
127        }
128        ControlMessage::MaxRequestId(m) => {
129            let mut o = Map::new();
130            o.insert("request_id".into(), vi(m.request_id.into_inner()));
131            o
132        }
133        ControlMessage::RequestsBlocked(m) => {
134            let mut o = Map::new();
135            o.insert("maximum_request_id".into(), vi(m.maximum_request_id.into_inner()));
136            o
137        }
138        ControlMessage::Subscribe(m) => {
139            let mut o = Map::new();
140            o.insert("request_id".into(), vi(m.request_id.into_inner()));
141            o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
142            o.insert(
143                "track_name".into(),
144                Value::Text(String::from_utf8_lossy(&m.track_name).into_owned()),
145            );
146            o.insert("subscriber_priority".into(), vi(m.subscriber_priority as u64));
147            o.insert("group_order".into(), vi(m.group_order as u64));
148            o.insert("forward".into(), vi(m.forward as u64));
149            o.insert("filter_type".into(), vi(m.filter_type as u64));
150            if let Some(sg) = &m.start_group {
151                o.insert("start_group".into(), vi(sg.into_inner()));
152            }
153            if let Some(so) = &m.start_object {
154                o.insert("start_object".into(), vi(so.into_inner()));
155            }
156            if let Some(eg) = &m.end_group {
157                o.insert("end_group".into(), vi(eg.into_inner()));
158            }
159            o.insert("parameters".into(), kvp_to_json_msg(&m.parameters));
160            o
161        }
162        ControlMessage::SubscribeOk(m) => {
163            let mut o = Map::new();
164            o.insert("request_id".into(), vi(m.request_id.into_inner()));
165            o.insert("track_alias".into(), vi(m.track_alias.into_inner()));
166            o.insert("expires".into(), vi(m.expires.into_inner()));
167            o.insert("group_order".into(), vi(m.group_order as u64));
168            o.insert("content_exists".into(), vi(m.content_exists as u64));
169            if let Some(loc) = &m.largest_location {
170                o.insert("largest_location".into(), loc_to_json(loc));
171            }
172            o.insert("parameters".into(), kvp_to_json_msg(&m.parameters));
173            o
174        }
175        ControlMessage::SubscribeError(m) => {
176            let mut o = Map::new();
177            o.insert("request_id".into(), vi(m.request_id.into_inner()));
178            o.insert("error_code".into(), vi(m.error_code.into_inner()));
179            o.insert(
180                "reason_phrase".into(),
181                Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
182            );
183            o
184        }
185        ControlMessage::SubscribeUpdate(m) => {
186            let mut o = Map::new();
187            o.insert("request_id".into(), vi(m.request_id.into_inner()));
188            o.insert("start_group".into(), vi(m.start_group.into_inner()));
189            o.insert("start_object".into(), vi(m.start_object.into_inner()));
190            o.insert("end_group".into(), vi(m.end_group.into_inner()));
191            o.insert("subscriber_priority".into(), vi(m.subscriber_priority as u64));
192            o.insert("forward".into(), vi(m.forward as u64));
193            o.insert("parameters".into(), kvp_to_json_msg(&m.parameters));
194            o
195        }
196        ControlMessage::SubscribeDone(m) => {
197            let mut o = Map::new();
198            o.insert("request_id".into(), vi(m.request_id.into_inner()));
199            o.insert("status_code".into(), vi(m.status_code.into_inner()));
200            o.insert("stream_count".into(), vi(m.stream_count.into_inner()));
201            o.insert(
202                "reason_phrase".into(),
203                Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
204            );
205            o
206        }
207        ControlMessage::Unsubscribe(m) => {
208            let mut o = Map::new();
209            o.insert("request_id".into(), vi(m.request_id.into_inner()));
210            o
211        }
212        ControlMessage::Announce(m) => {
213            let mut o = Map::new();
214            o.insert("request_id".into(), vi(m.request_id.into_inner()));
215            o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
216            o.insert("parameters".into(), kvp_to_json_msg(&m.parameters));
217            o
218        }
219        ControlMessage::AnnounceOk(m) => {
220            let mut o = Map::new();
221            o.insert("request_id".into(), vi(m.request_id.into_inner()));
222            o
223        }
224        ControlMessage::AnnounceError(m) => {
225            let mut o = Map::new();
226            o.insert("request_id".into(), vi(m.request_id.into_inner()));
227            o.insert("error_code".into(), vi(m.error_code.into_inner()));
228            o.insert(
229                "reason_phrase".into(),
230                Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
231            );
232            o
233        }
234        ControlMessage::AnnounceCancel(m) => {
235            let mut o = Map::new();
236            o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
237            o.insert("error_code".into(), vi(m.error_code.into_inner()));
238            o.insert(
239                "reason_phrase".into(),
240                Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
241            );
242            o
243        }
244        ControlMessage::Unannounce(m) => {
245            let mut o = Map::new();
246            o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
247            o
248        }
249        ControlMessage::SubscribeNamespace(m) => {
250            let mut o = Map::new();
251            o.insert("request_id".into(), vi(m.request_id.into_inner()));
252            o.insert("track_namespace_prefix".into(), ns_to_json(&m.track_namespace_prefix));
253            o.insert("parameters".into(), kvp_to_json_msg(&m.parameters));
254            o
255        }
256        ControlMessage::SubscribeNamespaceOk(m) => {
257            let mut o = Map::new();
258            o.insert("request_id".into(), vi(m.request_id.into_inner()));
259            o
260        }
261        ControlMessage::SubscribeNamespaceError(m) => {
262            let mut o = Map::new();
263            o.insert("request_id".into(), vi(m.request_id.into_inner()));
264            o.insert("error_code".into(), vi(m.error_code.into_inner()));
265            o.insert(
266                "reason_phrase".into(),
267                Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
268            );
269            o
270        }
271        ControlMessage::UnsubscribeNamespace(m) => {
272            let mut o = Map::new();
273            o.insert("track_namespace_prefix".into(), ns_to_json(&m.track_namespace_prefix));
274            o
275        }
276        ControlMessage::TrackStatus(m) => {
277            let mut o = Map::new();
278            o.insert("request_id".into(), vi(m.request_id.into_inner()));
279            o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
280            o.insert(
281                "track_name".into(),
282                Value::Text(String::from_utf8_lossy(&m.track_name).into_owned()),
283            );
284            o.insert("subscriber_priority".into(), vi(m.subscriber_priority as u64));
285            o.insert("group_order".into(), vi(m.group_order as u64));
286            o.insert("forward".into(), vi(m.forward as u64));
287            o.insert("filter_type".into(), vi(m.filter_type as u64));
288            if let Some(sg) = &m.start_group {
289                o.insert("start_group".into(), vi(sg.into_inner()));
290            }
291            if let Some(so) = &m.start_object {
292                o.insert("start_object".into(), vi(so.into_inner()));
293            }
294            if let Some(eg) = &m.end_group {
295                o.insert("end_group".into(), vi(eg.into_inner()));
296            }
297            o.insert("parameters".into(), kvp_to_json_msg(&m.parameters));
298            o
299        }
300        ControlMessage::TrackStatusOk(m) => {
301            let mut o = Map::new();
302            o.insert("request_id".into(), vi(m.request_id.into_inner()));
303            o.insert("track_alias".into(), vi(m.track_alias.into_inner()));
304            o.insert("expires".into(), vi(m.expires.into_inner()));
305            o.insert("group_order".into(), vi(m.group_order as u64));
306            o.insert("content_exists".into(), vi(m.content_exists as u64));
307            if let Some(loc) = &m.largest_location {
308                o.insert("largest_location".into(), loc_to_json(loc));
309            }
310            o.insert("parameters".into(), kvp_to_json_msg(&m.parameters));
311            o
312        }
313        ControlMessage::TrackStatusError(m) => {
314            let mut o = Map::new();
315            o.insert("request_id".into(), vi(m.request_id.into_inner()));
316            o.insert("error_code".into(), vi(m.error_code.into_inner()));
317            o.insert(
318                "reason_phrase".into(),
319                Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
320            );
321            o
322        }
323        ControlMessage::Fetch(m) => {
324            let mut o = Map::new();
325            o.insert("request_id".into(), vi(m.request_id.into_inner()));
326            o.insert("subscriber_priority".into(), vi(m.subscriber_priority as u64));
327            o.insert("group_order".into(), vi(m.group_order as u64));
328            o.insert("fetch_type".into(), vi(m.fetch_type as u64));
329            match &m.fetch_payload {
330                FetchPayload::Standalone {
331                    track_namespace,
332                    track_name,
333                    start_group,
334                    start_object,
335                    end_group,
336                    end_object,
337                } => {
338                    o.insert("track_namespace".into(), ns_to_json(track_namespace));
339                    o.insert(
340                        "track_name".into(),
341                        Value::Text(String::from_utf8_lossy(track_name).into_owned()),
342                    );
343                    o.insert("start_group".into(), vi(start_group.into_inner()));
344                    o.insert("start_object".into(), vi(start_object.into_inner()));
345                    o.insert("end_group".into(), vi(end_group.into_inner()));
346                    o.insert("end_object".into(), vi(end_object.into_inner()));
347                }
348                FetchPayload::Joining { joining_request_id, joining_start } => {
349                    // The key is the corpus's spelling, not this draft's. The
350                    // draft renamed the field to Joining Request ID; the shared
351                    // vector files still say joining_subscribe_id, and they are
352                    // maintained elsewhere, so the name is translated here
353                    // rather than changed there.
354                    o.insert("joining_subscribe_id".into(), vi(joining_request_id.into_inner()));
355                    o.insert("joining_start".into(), vi(joining_start.into_inner()));
356                }
357            }
358            o.insert("parameters".into(), kvp_to_json_msg(&m.parameters));
359            o
360        }
361        ControlMessage::FetchOk(m) => {
362            let mut o = Map::new();
363            o.insert("request_id".into(), vi(m.request_id.into_inner()));
364            o.insert("group_order".into(), vi(m.group_order as u64));
365            o.insert("end_of_track".into(), vi(m.end_of_track as u64));
366            o.insert("end_location".into(), loc_to_json(&m.end_location));
367            o.insert("parameters".into(), kvp_to_json_msg(&m.parameters));
368            o
369        }
370        ControlMessage::FetchError(m) => {
371            let mut o = Map::new();
372            o.insert("request_id".into(), vi(m.request_id.into_inner()));
373            o.insert("error_code".into(), vi(m.error_code.into_inner()));
374            o.insert(
375                "reason_phrase".into(),
376                Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
377            );
378            o
379        }
380        ControlMessage::FetchCancel(m) => {
381            let mut o = Map::new();
382            o.insert("request_id".into(), vi(m.request_id.into_inner()));
383            o
384        }
385        ControlMessage::Publish(m) => {
386            let mut o = Map::new();
387            o.insert("request_id".into(), vi(m.request_id.into_inner()));
388            o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
389            o.insert(
390                "track_name".into(),
391                Value::Text(String::from_utf8_lossy(&m.track_name).into_owned()),
392            );
393            o.insert("track_alias".into(), vi(m.track_alias.into_inner()));
394            o.insert("group_order".into(), vi(m.group_order as u64));
395            o.insert("content_exists".into(), vi(m.content_exists as u64));
396            if let Some(loc) = &m.largest_location {
397                o.insert("largest_location".into(), loc_to_json(loc));
398            }
399            o.insert("forward".into(), vi(m.forward as u64));
400            o.insert("parameters".into(), kvp_to_json_msg(&m.parameters));
401            o
402        }
403        ControlMessage::PublishOk(m) => {
404            let mut o = Map::new();
405            o.insert("request_id".into(), vi(m.request_id.into_inner()));
406            o.insert("forward".into(), vi(m.forward as u64));
407            o.insert("subscriber_priority".into(), vi(m.subscriber_priority as u64));
408            o.insert("group_order".into(), vi(m.group_order as u64));
409            o.insert("filter_type".into(), vi(m.filter_type as u64));
410            if let Some(sg) = &m.start_group {
411                o.insert("start_group".into(), vi(sg.into_inner()));
412            }
413            if let Some(so) = &m.start_object {
414                o.insert("start_object".into(), vi(so.into_inner()));
415            }
416            if let Some(eg) = &m.end_group {
417                o.insert("end_group".into(), vi(eg.into_inner()));
418            }
419            o.insert("parameters".into(), kvp_to_json_msg(&m.parameters));
420            o
421        }
422        ControlMessage::PublishError(m) => {
423            let mut o = Map::new();
424            o.insert("request_id".into(), vi(m.request_id.into_inner()));
425            o.insert("error_code".into(), vi(m.error_code.into_inner()));
426            o.insert(
427                "reason_phrase".into(),
428                Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
429            );
430            o
431        }
432    };
433    obj
434}