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 {
132 let mut buf = bytes;
133 let filter_type = VarInt::decode_moqt::<Wire>(&mut buf).unwrap().into_inner();
134 let mut obj = Map::new();
135 obj.insert("filter_type".into(), vi(filter_type));
136 match filter_type {
137 3 => {
138 let start_group = VarInt::decode_moqt::<Wire>(&mut buf).unwrap().into_inner();
139 let start_object = VarInt::decode_moqt::<Wire>(&mut buf).unwrap().into_inner();
140 obj.insert("start_group".into(), vi(start_group));
141 obj.insert("start_object".into(), vi(start_object));
142 }
143 4 => {
144 let start_group = VarInt::decode_moqt::<Wire>(&mut buf).unwrap().into_inner();
145 let start_object = VarInt::decode_moqt::<Wire>(&mut buf).unwrap().into_inner();
146 let end_group = VarInt::decode_moqt::<Wire>(&mut buf).unwrap().into_inner();
147 obj.insert("start_group".into(), vi(start_group));
148 obj.insert("start_object".into(), vi(start_object));
149 obj.insert("end_group".into(), vi(end_group));
150 }
151 _ => {}
152 }
153 Value::Map(obj)
154}
155
156fn auth_token_to_json_d19(bytes: &[u8]) -> Value {
157 let mut buf = bytes;
158 let alias_type = match VarInt::decode_moqt::<Wire>(&mut buf) {
159 Ok(v) => v,
160 Err(_) => return Value::Bytes(bytes.to_vec()),
161 };
162 let at = alias_type.into_inner();
163 let mut o = Map::new();
164 o.insert("alias_type".into(), vi(at));
165 match at {
166 0 | 2 => {
167 if let Ok(ta) = VarInt::decode_moqt::<Wire>(&mut buf) {
168 o.insert("token_alias".into(), vi(ta.into_inner()));
169 }
170 }
171 1 => {
172 if let Ok(ta) = VarInt::decode_moqt::<Wire>(&mut buf) {
173 o.insert("token_alias".into(), vi(ta.into_inner()));
174 }
175 if let Ok(tt) = VarInt::decode_moqt::<Wire>(&mut buf) {
176 o.insert("token_type".into(), vi(tt.into_inner()));
177 }
178 o.insert("token_value".into(), Value::Bytes(buf.to_vec()));
180 }
181 _ => {
182 if let Ok(tt) = VarInt::decode_moqt::<Wire>(&mut buf) {
183 o.insert("token_type".into(), vi(tt.into_inner()));
184 }
185 o.insert("token_value".into(), Value::Bytes(buf.to_vec()));
186 }
187 }
188 Value::Map(o)
189}
190
191fn decode_largest_object(bytes: &[u8]) -> Value {
192 let mut buf = bytes;
193 let group = VarInt::decode_moqt::<Wire>(&mut buf).unwrap().into_inner();
194 let object = VarInt::decode_moqt::<Wire>(&mut buf).unwrap().into_inner();
195 let mut obj = Map::new();
196 obj.insert("group".into(), vi(group));
197 obj.insert("object".into(), vi(object));
198 Value::Map(obj)
199}
200
201fn decode_track_namespace_prefix(bytes: &[u8]) -> Value {
202 let mut buf = bytes;
203 match TrackNamespace::decode_allow_empty_moqt::<Wire>(&mut buf) {
204 Ok(ns) => ns_to_json(&ns),
205 Err(_) => Value::Bytes(bytes.to_vec()),
206 }
207}
208
209fn params_to_json(params: &[KeyValuePair]) -> Value {
210 let mut obj = Map::new();
211 let mut unknown = Vec::new();
212
213 for p in params {
214 let key = p.key.into_inner();
215 if let Some(name) = d19_param_name(key) {
216 match (&p.value, key) {
217 (KvpValue::Bytes(b), 0x21) => {
218 obj.insert(name.to_string(), decode_location_filter(b));
219 }
220 (KvpValue::Bytes(b), 0x25..=0x29) => {
225 obj.insert(name.to_string(), decode_range_filter(b, key));
226 }
227 (KvpValue::Bytes(b), 0x09) => {
228 obj.insert(name.to_string(), decode_largest_object(b));
229 }
230 (KvpValue::Bytes(b), 0x34) => {
231 obj.insert(name.to_string(), decode_track_namespace_prefix(b));
232 }
233 (KvpValue::Bytes(b), _) if name == "authorization_token" => {
234 obj.insert(name.to_string(), auth_token_to_json_d19(b));
235 }
236 (KvpValue::Varint(v), _) => {
237 obj.insert(name.to_string(), vi(v.into_inner()));
238 }
239 (KvpValue::Bytes(b), _) => {
240 obj.insert(
241 name.to_string(),
242 Value::Text(String::from_utf8_lossy(b).into_owned()),
243 );
244 }
245 }
246 } else {
247 let mut entry = Map::new();
248 entry.insert("id".to_string(), Value::Text(format!("0x{:x}", key)));
249 match &p.value {
250 KvpValue::Varint(v) => {
251 entry.insert("length".to_string(), vi(v.into_inner()));
252 }
253 KvpValue::Bytes(b) => {
254 entry.insert("length".to_string(), vi(b.len() as u64));
255 entry.insert("raw_hex".to_string(), Value::Bytes(b.to_vec()));
256 }
257 }
258 unknown.push(Value::Map(entry));
259 }
260 }
261
262 if !unknown.is_empty() {
263 obj.insert("unknown".to_string(), Value::Array(unknown));
264 }
265
266 Value::Map(obj)
267}
268
269fn options_to_json(options: &[KeyValuePair]) -> Value {
270 let mut obj = Map::new();
271 for p in options {
272 let key = p.key.into_inner();
273 if let Some(name) = d19_option_name(key) {
274 match &p.value {
275 KvpValue::Varint(v) => {
276 obj.insert(name.to_string(), vi(v.into_inner()));
277 }
278 KvpValue::Bytes(b) if name == "authorization_token" => {
279 obj.insert(name.to_string(), auth_token_to_json_d19(b));
280 }
281 KvpValue::Bytes(b) => {
282 obj.insert(
283 name.to_string(),
284 Value::Text(String::from_utf8_lossy(b).into_owned()),
285 );
286 }
287 }
288 }
289 }
290 Value::Map(obj)
291}
292
293fn d19_track_prop_name(key: u64) -> Option<&'static str> {
294 match key {
295 0x02 => Some("object_delivery_timeout"),
296 0x04 => Some("max_cache_duration"),
297 0x06 => Some("subgroup_delivery_timeout"),
298 0x0b => Some("immutable_properties"),
299 0x0e => Some("default_publisher_priority"),
300 0x22 => Some("default_publisher_group_order"),
301 0x30 => Some("dynamic_groups"),
302 _ => None,
303 }
304}
305
306fn track_props_to_json(props: &[KeyValuePair]) -> Value {
307 let mut obj = Map::new();
308 for p in props {
309 let key = p.key.into_inner();
310 let name = d19_track_prop_name(key)
311 .map(|s| s.to_string())
312 .unwrap_or_else(|| format!("0x{:x}", key));
313 match &p.value {
314 KvpValue::Varint(v) => {
315 obj.insert(name, vi(v.into_inner()));
316 }
317 KvpValue::Bytes(b) => {
318 obj.insert(name, Value::Bytes(b.to_vec()));
319 }
320 }
321 }
322 Value::Map(obj)
323}
324
325pub fn message_fields(msg: &ControlMessage) -> Map {
331 let obj = match msg {
332 ControlMessage::Setup(m) => {
333 let mut o = Map::new();
334 o.insert("options".into(), options_to_json(&m.options));
335 o
336 }
337 ControlMessage::GoAway(m) => {
338 let mut o = Map::new();
339 o.insert(
340 "new_session_uri".into(),
341 Value::Text(String::from_utf8_lossy(&m.new_session_uri).into_owned()),
342 );
343 o.insert("timeout".into(), vi(m.timeout.into_inner()));
344 o
345 }
346 ControlMessage::RequestOk(m) => {
347 let mut o = Map::new();
348 o.insert("parameters".into(), params_to_json(&m.parameters));
349 o.insert("track_properties".into(), track_props_to_json(&m.track_properties));
350 o
351 }
352 ControlMessage::RequestError(m) => {
353 let mut o = Map::new();
354 o.insert("error_code".into(), vi(m.error_code.into_inner()));
355 o.insert("retry_interval".into(), vi(m.retry_interval.into_inner()));
356 o.insert(
357 "reason_phrase".into(),
358 Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
359 );
360 if let Some(r) = &m.redirect {
361 let mut r_obj = Map::new();
362 r_obj.insert(
363 "connect_uri".into(),
364 Value::Text(String::from_utf8_lossy(&r.connect_uri).into_owned()),
365 );
366 r_obj.insert("track_namespace".into(), ns_to_json(&r.track_namespace));
367 r_obj.insert(
368 "track_name".into(),
369 Value::Text(String::from_utf8_lossy(&r.track_name).into_owned()),
370 );
371 o.insert("redirect".into(), Value::Map(r_obj));
372 }
373 o
374 }
375 ControlMessage::Subscribe(m) => {
376 let mut o = Map::new();
377 o.insert("request_id".into(), vi(m.request_id.into_inner()));
378 o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
379 o.insert(
380 "track_name".into(),
381 Value::Text(String::from_utf8_lossy(&m.track_name).into_owned()),
382 );
383 o.insert("parameters".into(), params_to_json(&m.parameters));
384 o
385 }
386 ControlMessage::SubscribeOk(m) => {
387 let mut o = Map::new();
388 o.insert("track_alias".into(), vi(m.track_alias.into_inner()));
389 o.insert("parameters".into(), params_to_json(&m.parameters));
390 o.insert("track_properties".into(), track_props_to_json(&m.track_properties));
391 o
392 }
393 ControlMessage::RequestUpdate(m) => {
394 let mut o = Map::new();
395 o.insert("request_id".into(), vi(m.request_id.into_inner()));
396 o.insert("parameters".into(), params_to_json(&m.parameters));
397 o
398 }
399 ControlMessage::Publish(m) => {
400 let mut o = Map::new();
401 o.insert("request_id".into(), vi(m.request_id.into_inner()));
402 o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
403 o.insert(
404 "track_name".into(),
405 Value::Text(String::from_utf8_lossy(&m.track_name).into_owned()),
406 );
407 o.insert("track_alias".into(), vi(m.track_alias.into_inner()));
408 o.insert("parameters".into(), params_to_json(&m.parameters));
409 o.insert("track_properties".into(), track_props_to_json(&m.track_properties));
410 o
411 }
412 ControlMessage::PublishDone(m) => {
413 let mut o = Map::new();
414 o.insert("status_code".into(), vi(m.status_code.into_inner()));
415 o.insert("stream_count".into(), vi(m.stream_count.into_inner()));
416 o.insert(
417 "reason_phrase".into(),
418 Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
419 );
420 o
421 }
422 ControlMessage::PublishNamespace(m) => {
423 let mut o = Map::new();
424 o.insert("request_id".into(), vi(m.request_id.into_inner()));
425 o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
426 o.insert("parameters".into(), params_to_json(&m.parameters));
427 o
428 }
429 ControlMessage::Namespace(m) => {
430 let mut o = Map::new();
431 o.insert("namespace_suffix".into(), ns_to_json(&m.namespace_suffix));
432 o
433 }
434 ControlMessage::NamespaceDone(m) => {
435 let mut o = Map::new();
436 o.insert("namespace_suffix".into(), ns_to_json(&m.namespace_suffix));
437 o
438 }
439 ControlMessage::SubscribeNamespace(m) => {
440 let mut o = Map::new();
441 o.insert("request_id".into(), vi(m.request_id.into_inner()));
442 o.insert("namespace_prefix".into(), ns_to_json(&m.namespace_prefix));
443 o.insert("parameters".into(), params_to_json(&m.parameters));
444 o
445 }
446 ControlMessage::SubscribeTracks(m) => {
447 let mut o = Map::new();
448 o.insert("request_id".into(), vi(m.request_id.into_inner()));
449 o.insert("namespace_prefix".into(), ns_to_json(&m.namespace_prefix));
450 o.insert("parameters".into(), params_to_json(&m.parameters));
451 o
452 }
453 ControlMessage::TrackStatus(m) => {
454 let mut o = Map::new();
455 o.insert("request_id".into(), vi(m.request_id.into_inner()));
456 o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
457 o.insert(
458 "track_name".into(),
459 Value::Text(String::from_utf8_lossy(&m.track_name).into_owned()),
460 );
461 o.insert("parameters".into(), params_to_json(&m.parameters));
462 o
463 }
464 ControlMessage::Fetch(m) => {
465 let mut o = Map::new();
466 o.insert("request_id".into(), vi(m.request_id.into_inner()));
467 o.insert("fetch_type".into(), vi(m.fetch_type as u64));
468 match &m.fetch_payload {
469 crate::draft19::message::FetchPayload::Standalone {
470 track_namespace,
471 track_name,
472 start_group,
473 start_object,
474 end_group,
475 end_object,
476 } => {
477 o.insert("track_namespace".into(), ns_to_json(track_namespace));
478 o.insert(
479 "track_name".into(),
480 Value::Text(String::from_utf8_lossy(track_name).into_owned()),
481 );
482 o.insert("start_group".into(), vi(start_group.into_inner()));
483 o.insert("start_object".into(), vi(start_object.into_inner()));
484 o.insert("end_group".into(), vi(end_group.into_inner()));
485 o.insert("end_object".into(), vi(end_object.into_inner()));
486 }
487 crate::draft19::message::FetchPayload::Joining {
488 joining_request_id,
489 joining_start,
490 } => {
491 o.insert("joining_request_id".into(), vi(joining_request_id.into_inner()));
492 o.insert("joining_start".into(), vi(joining_start.into_inner()));
493 }
494 }
495 o.insert("parameters".into(), params_to_json(&m.parameters));
496 o
497 }
498 ControlMessage::FetchOk(m) => {
499 let mut o = Map::new();
500 o.insert("end_of_track".into(), vi(m.end_of_track as u64));
501 o.insert("end_group".into(), vi(m.end_group.into_inner()));
502 o.insert("end_object".into(), vi(m.end_object.into_inner()));
503 o.insert("parameters".into(), params_to_json(&m.parameters));
504 o.insert("track_properties".into(), track_props_to_json(&m.track_properties));
505 o
506 }
507 ControlMessage::PublishSkipped(m) => {
508 let mut o = Map::new();
509 o.insert("namespace_suffix".into(), ns_to_json(&m.namespace_suffix));
510 o.insert(
511 "track_name".into(),
512 Value::Text(String::from_utf8_lossy(&m.track_name).into_owned()),
513 );
514 o
515 }
516 };
517 obj
518}