1use crate::draft19::message::ControlMessage;
2use crate::fields::{FieldMap as Map, FieldValue as Value};
3use crate::kvp::{KeyValuePair, KvpValue};
4use crate::range_filter::RangeFilter;
5use crate::types::*;
6use crate::varint::{Moqt18 as Wire, VarInt};
7
8fn vi(v: u64) -> Value {
9 Value::Uint(v)
10}
11
12fn ns_to_json(ns: &TrackNamespace) -> Value {
13 Value::Array(
14 ns.0.iter().map(|e| Value::Text(String::from_utf8_lossy(e).into_owned())).collect(),
15 )
16}
17
18fn d19_param_name(key: u64) -> Option<&'static str> {
20 match key {
21 0x02 => Some("object_delivery_timeout"),
22 0x03 => Some("authorization_token"),
23 0x04 => Some("rendezvous_timeout"),
24 0x06 => Some("subgroup_delivery_timeout"),
25 0x08 => Some("expires"),
26 0x09 => Some("largest_object"),
27 0x0A => Some("fill_timeout"),
28 0x10 => Some("forward"),
29 0x20 => Some("subscriber_priority"),
30 0x21 => Some("location_filter"),
31 0x22 => Some("group_order"),
32 0x25 => Some("subgroup_filter"),
33 0x26 => Some("objectid_filter"),
34 0x27 => Some("priority_filter"),
35 0x28 => Some("object_property_filter"),
36 0x29 => Some("track_property_filter"),
37 0x32 => Some("new_group_request"),
38 0x34 => Some("track_namespace_prefix"),
39 _ => None,
40 }
41}
42
43fn d19_option_name(key: u64) -> Option<&'static str> {
45 match key {
46 0x01 => Some("path"),
47 0x03 => Some("authorization_token"),
48 0x04 => Some("max_auth_token_cache_size"),
49 0x05 => Some("authority"),
50 0x06 => Some("max_filter_ranges"),
51 0x07 => Some("moqt_implementation"),
52 0x08 => Some("max_request_updates"),
53 _ => None,
54 }
55}
56
57fn decode_range_filter(bytes: &[u8], parameter_type: u64) -> Value {
100 let mut o = Map::new();
101 if bytes.is_empty() {
102 o.insert("removed".into(), Value::Bool(true));
103 return Value::Map(o);
104 }
105 let Ok(filter) = RangeFilter::decode_moqt_structure::<Wire>(parameter_type, bytes) else {
106 return Value::Bytes(bytes.to_vec());
107 };
108 if let Err(broken) = filter.check_its_own_types() {
109 o.insert("violates".into(), Value::Text(broken.to_string()));
110 }
111 o.insert("set_id".into(), vi(filter.set_id as u64));
112 if let Some(property_type) = filter.property_type {
113 o.insert("property_type".into(), vi(property_type));
114 }
115 let ranges = filter
116 .ranges
117 .iter()
118 .map(|range| {
119 let mut r = Map::new();
120 r.insert("start".into(), vi(range.start));
121 if let Some(end) = range.end {
122 r.insert("end".into(), vi(end));
123 }
124 Value::Map(r)
125 })
126 .collect();
127 o.insert("ranges".into(), Value::Array(ranges));
128 Value::Map(o)
129}
130
131fn decode_location_filter(bytes: &[u8]) -> Value {
155 let mut buf = bytes;
156 let Ok(filter_type) = VarInt::decode_moqt::<Wire>(&mut buf) else {
157 return Value::Bytes(bytes.to_vec());
158 };
159 let filter_type = filter_type.into_inner();
160 let mut obj = Map::new();
161 obj.insert("filter_type".into(), vi(filter_type));
162 match filter_type {
163 3 => {
164 let Ok(start_group) = VarInt::decode_moqt::<Wire>(&mut buf) else {
165 return Value::Bytes(bytes.to_vec());
166 };
167 let start_group = start_group.into_inner();
168 let Ok(start_object) = VarInt::decode_moqt::<Wire>(&mut buf) else {
169 return Value::Bytes(bytes.to_vec());
170 };
171 let start_object = start_object.into_inner();
172 obj.insert("start_group".into(), vi(start_group));
173 obj.insert("start_object".into(), vi(start_object));
174 }
175 4 => {
176 let Ok(start_group) = VarInt::decode_moqt::<Wire>(&mut buf) else {
177 return Value::Bytes(bytes.to_vec());
178 };
179 let start_group = start_group.into_inner();
180 let Ok(start_object) = VarInt::decode_moqt::<Wire>(&mut buf) else {
181 return Value::Bytes(bytes.to_vec());
182 };
183 let start_object = start_object.into_inner();
184 let Ok(end_group) = VarInt::decode_moqt::<Wire>(&mut buf) else {
185 return Value::Bytes(bytes.to_vec());
186 };
187 let end_group = end_group.into_inner();
188 obj.insert("start_group".into(), vi(start_group));
189 obj.insert("start_object".into(), vi(start_object));
190 obj.insert("end_group".into(), vi(end_group));
191 }
192 _ => {}
193 }
194 Value::Map(obj)
195}
196
197fn auth_token_to_json_d19(bytes: &[u8]) -> Value {
198 let mut buf = bytes;
199 let alias_type = match VarInt::decode_moqt::<Wire>(&mut buf) {
200 Ok(v) => v,
201 Err(_) => return Value::Bytes(bytes.to_vec()),
202 };
203 let at = alias_type.into_inner();
204 let mut o = Map::new();
205 o.insert("alias_type".into(), vi(at));
206 match at {
207 0 | 2 => {
208 if let Ok(ta) = VarInt::decode_moqt::<Wire>(&mut buf) {
209 o.insert("token_alias".into(), vi(ta.into_inner()));
210 }
211 }
212 1 => {
213 if let Ok(ta) = VarInt::decode_moqt::<Wire>(&mut buf) {
214 o.insert("token_alias".into(), vi(ta.into_inner()));
215 }
216 if let Ok(tt) = VarInt::decode_moqt::<Wire>(&mut buf) {
217 o.insert("token_type".into(), vi(tt.into_inner()));
218 }
219 o.insert("token_value".into(), Value::Bytes(buf.to_vec()));
221 }
222 _ => {
223 if let Ok(tt) = VarInt::decode_moqt::<Wire>(&mut buf) {
224 o.insert("token_type".into(), vi(tt.into_inner()));
225 }
226 o.insert("token_value".into(), Value::Bytes(buf.to_vec()));
227 }
228 }
229 Value::Map(o)
230}
231
232fn decode_largest_object(bytes: &[u8]) -> Value {
245 let mut buf = bytes;
246 let Ok(group) = VarInt::decode_moqt::<Wire>(&mut buf) else {
247 return Value::Bytes(bytes.to_vec());
248 };
249 let Ok(object) = VarInt::decode_moqt::<Wire>(&mut buf) else {
250 return Value::Bytes(bytes.to_vec());
251 };
252 let (group, object) = (group.into_inner(), object.into_inner());
253 let mut obj = Map::new();
254 obj.insert("group".into(), vi(group));
255 obj.insert("object".into(), vi(object));
256 Value::Map(obj)
257}
258
259fn decode_track_namespace_prefix(bytes: &[u8]) -> Value {
260 let mut buf = bytes;
261 match TrackNamespace::decode_allow_empty_moqt::<Wire>(&mut buf) {
262 Ok(ns) => ns_to_json(&ns),
263 Err(_) => Value::Bytes(bytes.to_vec()),
264 }
265}
266
267fn params_to_json(params: &[KeyValuePair]) -> Value {
268 crate::fields::kvp_entries(params, |key, value| {
269 let Some(name) = d19_param_name(key) else {
270 return (None, None);
271 };
272 let rendered = match (value, key) {
273 (KvpValue::Bytes(b), 0x21) => decode_location_filter(b),
274 (KvpValue::Bytes(b), 0x25..=0x29) => decode_range_filter(b, key),
279 (KvpValue::Bytes(b), 0x09) => decode_largest_object(b),
280 (KvpValue::Bytes(b), 0x34) => decode_track_namespace_prefix(b),
281 (KvpValue::Bytes(b), _) if name == "authorization_token" => auth_token_to_json_d19(b),
282 (KvpValue::Varint(v), _) => vi(v.into_inner()),
283 (KvpValue::Bytes(b), _) => Value::Text(String::from_utf8_lossy(b).into_owned()),
284 };
285 (Some(name), Some(rendered))
286 })
287}
288
289pub(crate) fn options_to_json(options: &[KeyValuePair]) -> Value {
290 crate::fields::kvp_entries(options, |key, value| {
291 let Some(name) = d19_option_name(key) else {
292 return (None, None);
293 };
294 let rendered = match value {
295 KvpValue::Varint(v) => vi(v.into_inner()),
296 KvpValue::Bytes(b) if name == "authorization_token" => auth_token_to_json_d19(b),
297 KvpValue::Bytes(b) => Value::Text(String::from_utf8_lossy(b).into_owned()),
298 };
299 (Some(name), Some(rendered))
300 })
301}
302
303fn d19_track_prop_name(key: u64) -> Option<&'static str> {
304 match key {
305 0x02 => Some("object_delivery_timeout"),
306 0x04 => Some("max_cache_duration"),
307 0x06 => Some("subgroup_delivery_timeout"),
308 0x0b => Some("immutable_properties"),
309 0x0e => Some("default_publisher_priority"),
310 0x22 => Some("default_publisher_group_order"),
311 0x30 => Some("dynamic_groups"),
312 _ => None,
313 }
314}
315
316fn track_props_to_json(props: &[KeyValuePair]) -> Value {
317 crate::fields::kvp_entries(props, |key, value| {
318 let name = d19_track_prop_name(key);
319 let rendered = match value {
320 KvpValue::Varint(v) => Some(vi(v.into_inner())),
321 KvpValue::Bytes(_) => None,
325 };
326 (name, rendered)
327 })
328}
329
330pub fn message_fields(msg: &ControlMessage) -> Map {
336 let obj = match msg {
337 ControlMessage::Setup(m) => {
338 let mut o = Map::new();
339 o.insert("options".into(), options_to_json(&m.options));
340 o
341 }
342 ControlMessage::GoAway(m) => {
343 let mut o = Map::new();
344 o.insert(
345 "new_session_uri".into(),
346 Value::Text(String::from_utf8_lossy(&m.new_session_uri).into_owned()),
347 );
348 o.insert("timeout".into(), vi(m.timeout.into_inner()));
349 o
350 }
351 ControlMessage::RequestOk(m) => {
352 let mut o = Map::new();
353 o.insert("parameters".into(), params_to_json(&m.parameters));
354 o.insert("track_properties".into(), track_props_to_json(&m.track_properties));
355 o
356 }
357 ControlMessage::RequestError(m) => {
358 let mut o = Map::new();
359 o.insert("error_code".into(), vi(m.error_code.into_inner()));
360 o.insert("retry_interval".into(), vi(m.retry_interval.into_inner()));
361 o.insert(
362 "reason_phrase".into(),
363 Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
364 );
365 if let Some(r) = &m.redirect {
366 let mut r_obj = Map::new();
367 r_obj.insert(
368 "connect_uri".into(),
369 Value::Text(String::from_utf8_lossy(&r.connect_uri).into_owned()),
370 );
371 r_obj.insert("track_namespace".into(), ns_to_json(&r.track_namespace));
372 r_obj.insert(
373 "track_name".into(),
374 Value::Text(String::from_utf8_lossy(&r.track_name).into_owned()),
375 );
376 o.insert("redirect".into(), Value::Map(r_obj));
377 }
378 o
379 }
380 ControlMessage::Subscribe(m) => {
381 let mut o = Map::new();
382 o.insert("request_id".into(), vi(m.request_id.into_inner()));
383 o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
384 o.insert(
385 "track_name".into(),
386 Value::Text(String::from_utf8_lossy(&m.track_name).into_owned()),
387 );
388 o.insert("parameters".into(), params_to_json(&m.parameters));
389 o
390 }
391 ControlMessage::SubscribeOk(m) => {
392 let mut o = Map::new();
393 o.insert("track_alias".into(), vi(m.track_alias.into_inner()));
394 o.insert("parameters".into(), params_to_json(&m.parameters));
395 o.insert("track_properties".into(), track_props_to_json(&m.track_properties));
396 o
397 }
398 ControlMessage::RequestUpdate(m) => {
399 let mut o = Map::new();
400 o.insert("request_id".into(), vi(m.request_id.into_inner()));
401 o.insert("parameters".into(), params_to_json(&m.parameters));
402 o
403 }
404 ControlMessage::Publish(m) => {
405 let mut o = Map::new();
406 o.insert("request_id".into(), vi(m.request_id.into_inner()));
407 o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
408 o.insert(
409 "track_name".into(),
410 Value::Text(String::from_utf8_lossy(&m.track_name).into_owned()),
411 );
412 o.insert("track_alias".into(), vi(m.track_alias.into_inner()));
413 o.insert("parameters".into(), params_to_json(&m.parameters));
414 o.insert("track_properties".into(), track_props_to_json(&m.track_properties));
415 o
416 }
417 ControlMessage::PublishDone(m) => {
418 let mut o = Map::new();
419 o.insert("status_code".into(), vi(m.status_code.into_inner()));
420 o.insert("stream_count".into(), vi(m.stream_count.into_inner()));
421 o.insert(
422 "reason_phrase".into(),
423 Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
424 );
425 o
426 }
427 ControlMessage::PublishNamespace(m) => {
428 let mut o = Map::new();
429 o.insert("request_id".into(), vi(m.request_id.into_inner()));
430 o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
431 o.insert("parameters".into(), params_to_json(&m.parameters));
432 o
433 }
434 ControlMessage::Namespace(m) => {
435 let mut o = Map::new();
436 o.insert("namespace_suffix".into(), ns_to_json(&m.namespace_suffix));
437 o
438 }
439 ControlMessage::NamespaceDone(m) => {
440 let mut o = Map::new();
441 o.insert("namespace_suffix".into(), ns_to_json(&m.namespace_suffix));
442 o
443 }
444 ControlMessage::SubscribeNamespace(m) => {
445 let mut o = Map::new();
446 o.insert("request_id".into(), vi(m.request_id.into_inner()));
447 o.insert("namespace_prefix".into(), ns_to_json(&m.namespace_prefix));
448 o.insert("parameters".into(), params_to_json(&m.parameters));
449 o
450 }
451 ControlMessage::SubscribeTracks(m) => {
452 let mut o = Map::new();
453 o.insert("request_id".into(), vi(m.request_id.into_inner()));
454 o.insert("namespace_prefix".into(), ns_to_json(&m.namespace_prefix));
455 o.insert("parameters".into(), params_to_json(&m.parameters));
456 o
457 }
458 ControlMessage::TrackStatus(m) => {
459 let mut o = Map::new();
460 o.insert("request_id".into(), vi(m.request_id.into_inner()));
461 o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
462 o.insert(
463 "track_name".into(),
464 Value::Text(String::from_utf8_lossy(&m.track_name).into_owned()),
465 );
466 o.insert("parameters".into(), params_to_json(&m.parameters));
467 o
468 }
469 ControlMessage::Fetch(m) => {
470 let mut o = Map::new();
471 o.insert("request_id".into(), vi(m.request_id.into_inner()));
472 o.insert("fetch_type".into(), vi(m.fetch_type as u64));
473 match &m.fetch_payload {
474 crate::draft19::message::FetchPayload::Standalone {
475 track_namespace,
476 track_name,
477 start_group,
478 start_object,
479 end_group,
480 end_object,
481 } => {
482 o.insert("track_namespace".into(), ns_to_json(track_namespace));
483 o.insert(
484 "track_name".into(),
485 Value::Text(String::from_utf8_lossy(track_name).into_owned()),
486 );
487 o.insert("start_group".into(), vi(start_group.into_inner()));
488 o.insert("start_object".into(), vi(start_object.into_inner()));
489 o.insert("end_group".into(), vi(end_group.into_inner()));
490 o.insert("end_object".into(), vi(end_object.into_inner()));
491 }
492 crate::draft19::message::FetchPayload::Joining {
493 joining_request_id,
494 joining_start,
495 } => {
496 o.insert("joining_request_id".into(), vi(joining_request_id.into_inner()));
497 o.insert("joining_start".into(), vi(joining_start.into_inner()));
498 }
499 }
500 o.insert("parameters".into(), params_to_json(&m.parameters));
501 o
502 }
503 ControlMessage::FetchOk(m) => {
504 let mut o = Map::new();
505 o.insert("end_of_track".into(), vi(m.end_of_track as u64));
506 o.insert("end_group".into(), vi(m.end_group.into_inner()));
507 o.insert("end_object".into(), vi(m.end_object.into_inner()));
508 o.insert("parameters".into(), params_to_json(&m.parameters));
509 o.insert("track_properties".into(), track_props_to_json(&m.track_properties));
510 o
511 }
512 ControlMessage::PublishSkipped(m) => {
513 let mut o = Map::new();
514 o.insert("namespace_suffix".into(), ns_to_json(&m.namespace_suffix));
515 o.insert(
516 "track_name".into(),
517 Value::Text(String::from_utf8_lossy(&m.track_name).into_owned()),
518 );
519 o
520 }
521 };
522 obj
523}