1use std::ops::{Deref, DerefMut};
2use std::sync::{Arc, Mutex, MutexGuard};
3
4#[derive(Clone)]
10pub struct CatalogProducer {
11 pub hang_track: moq_lite::TrackProducer,
13
14 pub msf_track: moq_lite::TrackProducer,
16
17 current: Arc<Mutex<hang::Catalog>>,
18}
19
20impl CatalogProducer {
21 pub fn new(broadcast: &mut moq_lite::BroadcastProducer) -> Result<Self, moq_lite::Error> {
23 Self::with_catalog(broadcast, hang::Catalog::default())
24 }
25
26 pub fn with_catalog(
28 broadcast: &mut moq_lite::BroadcastProducer,
29 catalog: hang::Catalog,
30 ) -> Result<Self, moq_lite::Error> {
31 let hang_track = broadcast.create_track(hang::Catalog::default_track())?;
32 let msf_track = broadcast.create_track(moq_lite::Track {
33 name: moq_msf::DEFAULT_NAME.to_string(),
34 priority: 100,
35 })?;
36
37 Ok(Self {
38 hang_track,
39 msf_track,
40 current: Arc::new(Mutex::new(catalog)),
41 })
42 }
43
44 pub fn lock(&mut self) -> CatalogGuard<'_> {
46 CatalogGuard {
47 catalog: self.current.lock().unwrap(),
48 hang_track: &mut self.hang_track,
49 msf_track: &mut self.msf_track,
50 updated: false,
51 }
52 }
53
54 pub fn consume(&self) -> hang::CatalogConsumer {
56 hang::CatalogConsumer::new(self.hang_track.consume())
57 }
58
59 pub fn finish(&mut self) -> Result<(), moq_lite::Error> {
61 self.hang_track.finish()?;
62 self.msf_track.finish()?;
63 Ok(())
64 }
65}
66
67pub struct CatalogGuard<'a> {
73 catalog: MutexGuard<'a, hang::Catalog>,
74 hang_track: &'a mut moq_lite::TrackProducer,
75 msf_track: &'a mut moq_lite::TrackProducer,
76 updated: bool,
77}
78
79impl<'a> Deref for CatalogGuard<'a> {
80 type Target = hang::Catalog;
81
82 fn deref(&self) -> &Self::Target {
83 &self.catalog
84 }
85}
86
87impl<'a> DerefMut for CatalogGuard<'a> {
88 fn deref_mut(&mut self) -> &mut Self::Target {
89 self.updated = true;
90 &mut self.catalog
91 }
92}
93
94impl Drop for CatalogGuard<'_> {
95 fn drop(&mut self) {
96 if !self.updated {
97 return;
98 }
99
100 let Ok(mut group) = self.hang_track.append_group() else {
102 return;
103 };
104 let frame = self.catalog.to_string().expect("invalid catalog");
105 let _ = group.write_frame(frame);
106 let _ = group.finish();
107
108 crate::msf::publish(&self.catalog, self.msf_track);
110 }
111}