1use crate::draft20::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 d20_param_name(key: u64) -> Option<&'static str> {
22 match key {
23 0x02 => Some("object_delivery_timeout"),
24 0x03 => Some("authorization_token"),
25 0x04 => Some("rendezvous_timeout"),
26 0x06 => Some("subgroup_delivery_timeout"),
27 0x08 => Some("expires"),
28 0x09 => Some("largest_object"),
29 0x0A => Some("fill_timeout"),
30 0x10 => Some("forward"),
31 0x20 => Some("subscriber_priority"),
32 0x21 => Some("location_filter"),
33 0x22 => Some("group_order"),
34 0x23 => Some("fill_parameters"),
35 0x25 => Some("subgroup_filter"),
36 0x26 => Some("objectid_filter"),
37 0x27 => Some("priority_filter"),
38 0x28 => Some("object_property_filter"),
39 0x29 => Some("track_property_filter"),
40 0x32 => Some("new_group_request"),
41 0x34 => Some("track_namespace_prefix"),
42 0x35 => Some("include_properties"),
43 _ => None,
44 }
45}
46
47fn d20_option_name(key: u64) -> Option<&'static str> {
49 match key {
50 0x01 => Some("path"),
51 0x03 => Some("authorization_token"),
52 0x04 => Some("max_auth_token_cache_size"),
53 0x05 => Some("authority"),
54 0x06 => Some("max_filter_ranges"),
55 0x07 => Some("moqt_implementation"),
56 0x08 => Some("max_request_updates"),
57 _ => None,
58 }
59}
60
61fn decode_range_filter(bytes: &[u8], parameter_type: u64) -> Value {
109 let mut o = Map::new();
110 if bytes.is_empty() {
111 o.insert("removed".into(), Value::Bool(true));
112 return Value::Map(o);
113 }
114 let Ok(filter) = RangeFilter::decode_moqt_structure::<Wire>(parameter_type, bytes) else {
115 return Value::Bytes(bytes.to_vec());
116 };
117 if let Err(broken) = filter.check_its_own_types() {
118 o.insert("violates".into(), Value::Text(broken.to_string()));
119 }
120 o.insert("set_id".into(), vi(filter.set_id as u64));
121 if let Some(property_type) = filter.property_type {
122 o.insert("property_type".into(), vi(property_type));
123 }
124 let ranges = filter
125 .ranges
126 .iter()
127 .map(|range| {
128 let mut r = Map::new();
129 r.insert("start".into(), vi(range.start));
130 if let Some(end) = range.end {
131 r.insert("end".into(), vi(end));
132 }
133 Value::Map(r)
134 })
135 .collect();
136 o.insert("ranges".into(), Value::Array(ranges));
137 Value::Map(o)
138}
139
140fn decode_location_filter(bytes: &[u8]) -> Value {
152 const NAMES: [&str; 4] = ["start_group", "start_object", "end_group_delta", "end_object"];
153 let fields = crate::draft20::message::decode_location_filter(bytes)
154 .expect("the decoder accepted this parameter, so its value parses");
155 let mut obj = Map::new();
156 if fields.is_empty() {
157 obj.insert("removed".into(), Value::Bool(true));
158 return Value::Map(obj);
159 }
160 for (name, value) in NAMES.iter().zip(fields) {
161 obj.insert((*name).to_string(), vi(value));
162 }
163 Value::Map(obj)
164}
165
166fn decode_fill_parameters(bytes: &[u8]) -> Value {
173 let nested = crate::draft20::message::decode_fill_parameters(bytes)
174 .expect("the decoder accepted this parameter, so its value parses");
175 params_to_json(&nested)
176}
177
178fn auth_token_to_json_d20(bytes: &[u8]) -> Value {
179 let mut buf = bytes;
180 let alias_type = match VarInt::decode_moqt::<Wire>(&mut buf) {
181 Ok(v) => v,
182 Err(_) => return Value::Bytes(bytes.to_vec()),
183 };
184 let at = alias_type.into_inner();
185 let mut o = Map::new();
186 o.insert("alias_type".into(), vi(at));
187 match at {
188 0 | 2 => {
189 if let Ok(ta) = VarInt::decode_moqt::<Wire>(&mut buf) {
190 o.insert("token_alias".into(), vi(ta.into_inner()));
191 }
192 }
193 1 => {
194 if let Ok(ta) = VarInt::decode_moqt::<Wire>(&mut buf) {
195 o.insert("token_alias".into(), vi(ta.into_inner()));
196 }
197 if let Ok(tt) = VarInt::decode_moqt::<Wire>(&mut buf) {
198 o.insert("token_type".into(), vi(tt.into_inner()));
199 }
200 o.insert("token_value".into(), Value::Bytes(buf.to_vec()));
203 }
204 _ => {
205 if let Ok(tt) = VarInt::decode_moqt::<Wire>(&mut buf) {
206 o.insert("token_type".into(), vi(tt.into_inner()));
207 }
208 o.insert("token_value".into(), Value::Bytes(buf.to_vec()));
209 }
210 }
211 Value::Map(o)
212}
213
214fn decode_largest_object(bytes: &[u8]) -> Value {
215 let mut buf = bytes;
216 let group = VarInt::decode_moqt::<Wire>(&mut buf).unwrap().into_inner();
217 let object = VarInt::decode_moqt::<Wire>(&mut buf).unwrap().into_inner();
218 let mut obj = Map::new();
219 obj.insert("group".into(), vi(group));
220 obj.insert("object".into(), vi(object));
221 Value::Map(obj)
222}
223
224fn decode_track_namespace_prefix(bytes: &[u8]) -> Value {
225 let mut buf = bytes;
226 match TrackNamespace::decode_allow_empty_moqt::<Wire>(&mut buf) {
227 Ok(ns) => ns_to_json(&ns),
228 Err(_) => Value::Bytes(bytes.to_vec()),
229 }
230}
231
232fn params_to_json(params: &[KeyValuePair]) -> Value {
233 let mut obj = Map::new();
234 let mut unknown = Vec::new();
235
236 for p in params {
237 let key = p.key.into_inner();
238 if let Some(name) = d20_param_name(key) {
239 match (&p.value, key) {
240 (KvpValue::Bytes(b), 0x21) => {
241 obj.insert(name.to_string(), decode_location_filter(b));
242 }
243 (KvpValue::Bytes(b), 0x23) => {
244 obj.insert(name.to_string(), decode_fill_parameters(b));
245 }
246 (KvpValue::Bytes(b), 0x25..=0x29) => {
251 obj.insert(name.to_string(), decode_range_filter(b, key));
252 }
253 (KvpValue::Bytes(b), 0x09) => {
254 obj.insert(name.to_string(), decode_largest_object(b));
255 }
256 (KvpValue::Bytes(b), 0x34) => {
257 obj.insert(name.to_string(), decode_track_namespace_prefix(b));
258 }
259 (KvpValue::Bytes(b), _) if name == "authorization_token" => {
260 obj.insert(name.to_string(), auth_token_to_json_d20(b));
261 }
262 (KvpValue::Varint(v), _) => {
263 obj.insert(name.to_string(), vi(v.into_inner()));
264 }
265 (KvpValue::Bytes(b), _) => {
266 obj.insert(
267 name.to_string(),
268 Value::Text(String::from_utf8_lossy(b).into_owned()),
269 );
270 }
271 }
272 } else {
273 let mut entry = Map::new();
274 entry.insert("id".to_string(), Value::Text(format!("0x{:x}", key)));
275 match &p.value {
276 KvpValue::Varint(v) => {
277 entry.insert("length".to_string(), vi(v.into_inner()));
278 }
279 KvpValue::Bytes(b) => {
280 entry.insert("length".to_string(), vi(b.len() as u64));
281 entry.insert("raw_hex".to_string(), Value::Bytes(b.to_vec()));
282 }
283 }
284 unknown.push(Value::Map(entry));
285 }
286 }
287
288 if !unknown.is_empty() {
289 obj.insert("unknown".to_string(), Value::Array(unknown));
290 }
291
292 Value::Map(obj)
293}
294
295fn options_to_json(options: &[KeyValuePair]) -> Value {
296 let mut obj = Map::new();
297 for p in options {
298 let key = p.key.into_inner();
299 if let Some(name) = d20_option_name(key) {
300 match &p.value {
301 KvpValue::Varint(v) => {
302 obj.insert(name.to_string(), vi(v.into_inner()));
303 }
304 KvpValue::Bytes(b) if name == "authorization_token" => {
305 obj.insert(name.to_string(), auth_token_to_json_d20(b));
306 }
307 KvpValue::Bytes(b) => {
308 obj.insert(
309 name.to_string(),
310 Value::Text(String::from_utf8_lossy(b).into_owned()),
311 );
312 }
313 }
314 }
315 }
316 Value::Map(obj)
317}
318
319fn d20_track_prop_name(key: u64) -> Option<&'static str> {
320 match key {
321 0x02 => Some("object_delivery_timeout"),
322 0x04 => Some("max_cache_duration"),
323 0x06 => Some("subgroup_delivery_timeout"),
324 0x0b => Some("immutable_properties"),
325 0x0e => Some("default_publisher_priority"),
326 0x22 => Some("default_publisher_group_order"),
327 0x30 => Some("dynamic_groups"),
328 _ => None,
329 }
330}
331
332fn track_props_to_json(props: &[KeyValuePair]) -> Value {
333 let mut obj = Map::new();
334 for p in props {
335 let key = p.key.into_inner();
336 let name = d20_track_prop_name(key)
337 .map(|s| s.to_string())
338 .unwrap_or_else(|| format!("0x{:x}", key));
339 match &p.value {
340 KvpValue::Varint(v) => {
341 obj.insert(name, vi(v.into_inner()));
342 }
343 KvpValue::Bytes(b) => {
344 obj.insert(name, Value::Bytes(b.to_vec()));
345 }
346 }
347 }
348 Value::Map(obj)
349}
350
351pub fn message_fields(msg: &ControlMessage) -> Map {
357 let obj = match msg {
358 ControlMessage::Setup(m) => {
359 let mut o = Map::new();
360 o.insert("options".into(), options_to_json(&m.options));
361 o
362 }
363 ControlMessage::GoAway(m) => {
364 let mut o = Map::new();
365 o.insert(
366 "new_session_uri".into(),
367 Value::Text(String::from_utf8_lossy(&m.new_session_uri).into_owned()),
368 );
369 o.insert("timeout".into(), vi(m.timeout.into_inner()));
370 o
371 }
372 ControlMessage::RequestOk(m) => {
373 let mut o = Map::new();
374 o.insert("parameters".into(), params_to_json(&m.parameters));
375 o.insert("track_properties".into(), track_props_to_json(&m.track_properties));
376 o
377 }
378 ControlMessage::RequestError(m) => {
379 let mut o = Map::new();
380 o.insert("error_code".into(), vi(m.error_code.into_inner()));
381 o.insert("retry_interval".into(), vi(m.retry_interval.into_inner()));
382 o.insert(
383 "reason_phrase".into(),
384 Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
385 );
386 if let Some(r) = &m.redirect {
387 let mut r_obj = Map::new();
388 r_obj.insert(
389 "connect_uri".into(),
390 Value::Text(String::from_utf8_lossy(&r.connect_uri).into_owned()),
391 );
392 r_obj.insert("track_namespace".into(), ns_to_json(&r.track_namespace));
393 r_obj.insert(
394 "track_name".into(),
395 Value::Text(String::from_utf8_lossy(&r.track_name).into_owned()),
396 );
397 o.insert("redirect".into(), Value::Map(r_obj));
398 }
399 o
400 }
401 ControlMessage::Subscribe(m) => {
402 let mut o = Map::new();
403 o.insert("request_id".into(), vi(m.request_id.into_inner()));
404 o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
405 o.insert(
406 "track_name".into(),
407 Value::Text(String::from_utf8_lossy(&m.track_name).into_owned()),
408 );
409 o.insert("parameters".into(), params_to_json(&m.parameters));
410 o
411 }
412 ControlMessage::SubscribeOk(m) => {
413 let mut o = Map::new();
414 o.insert("track_alias".into(), vi(m.track_alias.into_inner()));
415 o.insert("parameters".into(), params_to_json(&m.parameters));
416 o.insert("track_properties".into(), track_props_to_json(&m.track_properties));
417 o
418 }
419 ControlMessage::RequestUpdate(m) => {
420 let mut o = Map::new();
421 o.insert("request_id".into(), vi(m.request_id.into_inner()));
422 o.insert("parameters".into(), params_to_json(&m.parameters));
423 o
424 }
425 ControlMessage::Publish(m) => {
426 let mut o = Map::new();
427 o.insert("request_id".into(), vi(m.request_id.into_inner()));
428 o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
429 o.insert(
430 "track_name".into(),
431 Value::Text(String::from_utf8_lossy(&m.track_name).into_owned()),
432 );
433 o.insert("track_alias".into(), vi(m.track_alias.into_inner()));
434 o.insert("parameters".into(), params_to_json(&m.parameters));
435 o.insert("track_properties".into(), track_props_to_json(&m.track_properties));
436 o
437 }
438 ControlMessage::PublishStateNotify(m) => {
441 let mut o = Map::new();
442 o.insert("parameters".into(), params_to_json(&m.parameters));
443 o
444 }
445 ControlMessage::PublishDone(m) => {
446 let mut o = Map::new();
447 o.insert("status_code".into(), vi(m.status_code.into_inner()));
448 o.insert("stream_count".into(), vi(m.stream_count.into_inner()));
449 o.insert(
450 "reason_phrase".into(),
451 Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
452 );
453 o
454 }
455 ControlMessage::PublishNamespace(m) => {
456 let mut o = Map::new();
457 o.insert("request_id".into(), vi(m.request_id.into_inner()));
458 o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
459 o.insert("parameters".into(), params_to_json(&m.parameters));
460 o
461 }
462 ControlMessage::Namespace(m) => {
463 let mut o = Map::new();
464 o.insert("namespace_suffix".into(), ns_to_json(&m.namespace_suffix));
465 o
466 }
467 ControlMessage::NamespaceDone(m) => {
468 let mut o = Map::new();
469 o.insert("namespace_suffix".into(), ns_to_json(&m.namespace_suffix));
470 o
471 }
472 ControlMessage::SubscribeNamespace(m) => {
473 let mut o = Map::new();
474 o.insert("request_id".into(), vi(m.request_id.into_inner()));
475 o.insert("namespace_prefix".into(), ns_to_json(&m.namespace_prefix));
476 o.insert("parameters".into(), params_to_json(&m.parameters));
477 o
478 }
479 ControlMessage::SubscribeTracks(m) => {
480 let mut o = Map::new();
481 o.insert("request_id".into(), vi(m.request_id.into_inner()));
482 o.insert("namespace_prefix".into(), ns_to_json(&m.namespace_prefix));
483 o.insert("parameters".into(), params_to_json(&m.parameters));
484 o
485 }
486 ControlMessage::TrackStatus(m) => {
487 let mut o = Map::new();
488 o.insert("request_id".into(), vi(m.request_id.into_inner()));
489 o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
490 o.insert(
491 "track_name".into(),
492 Value::Text(String::from_utf8_lossy(&m.track_name).into_owned()),
493 );
494 o.insert("parameters".into(), params_to_json(&m.parameters));
495 o
496 }
497 ControlMessage::Fetch(m) => {
500 let mut o = Map::new();
501 o.insert("request_id".into(), vi(m.request_id.into_inner()));
502 o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
503 o.insert(
504 "track_name".into(),
505 Value::Text(String::from_utf8_lossy(&m.track_name).into_owned()),
506 );
507 o.insert("parameters".into(), params_to_json(&m.parameters));
508 o
509 }
510 ControlMessage::FetchOk(m) => {
511 let mut o = Map::new();
512 o.insert("end_of_track".into(), vi(m.end_of_track as u64));
513 o.insert("end_group".into(), vi(m.end_group.into_inner()));
514 o.insert("end_object".into(), vi(m.end_object.into_inner()));
515 o.insert("parameters".into(), params_to_json(&m.parameters));
516 o.insert("track_properties".into(), track_props_to_json(&m.track_properties));
517 o
518 }
519 ControlMessage::PublishSkipped(m) => {
520 let mut o = Map::new();
521 o.insert("namespace_suffix".into(), ns_to_json(&m.namespace_suffix));
522 o.insert(
523 "track_name".into(),
524 Value::Text(String::from_utf8_lossy(&m.track_name).into_owned()),
525 );
526 o
527 }
528 };
529 obj
530}