use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex, MutexGuard};
use serde::Serialize;
use serde::de::DeserializeOwned;
use super::{Encoded, Encoder, ProducerConfig};
use crate::Result;
pub struct Producer<T> {
inner: Arc<Mutex<Inner<T>>>,
_marker: PhantomData<fn(T)>,
}
impl<T> Clone for Producer<T> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
_marker: PhantomData,
}
}
}
impl<T> Producer<T> {
pub fn consume(&self) -> moq_net::track::Subscriber {
self.inner.lock().unwrap().track.inner.subscribe(None)
}
pub fn is_used(&self) -> bool {
self.inner
.lock()
.unwrap()
.track
.inner
.poll_unused(&moq_net::kio::Waiter::noop())
.is_pending()
}
}
impl<T: Serialize> Producer<T> {
pub fn new(track: moq_net::track::Producer, config: ProducerConfig) -> Self {
Self {
inner: Arc::new(Mutex::new(Inner {
track: Track {
inner: track,
group: None,
deltas: config.delta_ratio != 0,
},
encoder: Encoder::new(config),
})),
_marker: PhantomData,
}
}
pub fn update(&mut self, value: &T) -> Result<()> {
self.inner.lock().unwrap().update(value)
}
pub fn lock(&mut self) -> Guard<'_, T>
where
T: Default + DeserializeOwned,
{
let inner = self.inner.lock().unwrap();
let value = inner
.encoder
.value()
.and_then(|last| serde_json::from_value(last.clone()).ok())
.unwrap_or_default();
Guard {
inner,
value,
dirty: false,
}
}
pub fn finish(&mut self) -> Result<()> {
self.inner.lock().unwrap().finish()
}
}
pub struct Guard<'a, T: Serialize> {
inner: MutexGuard<'a, Inner<T>>,
value: T,
dirty: bool,
}
impl<T: Serialize> Guard<'_, T> {
pub fn commit(mut self) -> Result<()> {
self.publish()
}
fn publish(&mut self) -> Result<()> {
if !self.dirty {
return Ok(());
}
self.dirty = false;
self.inner.update(&self.value)
}
}
impl<T: Serialize> Deref for Guard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
&self.value
}
}
impl<T: Serialize> DerefMut for Guard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
self.dirty = true;
&mut self.value
}
}
impl<T: Serialize> Drop for Guard<'_, T> {
fn drop(&mut self) {
if let Err(err) = self.publish() {
tracing::warn!(%err, "failed to publish JSON value on guard drop");
}
}
}
struct Inner<T> {
track: Track,
encoder: Encoder<T>,
}
impl<T: Serialize> Inner<T> {
fn update(&mut self, value: &T) -> Result<()> {
let Inner { track, encoder } = self;
let Some(frame) = encoder.update(value)? else {
return Ok(());
};
track.write(&frame)?;
frame.commit();
Ok(())
}
fn finish(&mut self) -> Result<()> {
self.encoder.reset();
self.track.finish()
}
}
struct Track {
inner: moq_net::track::Producer,
group: Option<moq_net::group::Producer>,
deltas: bool,
}
impl Track {
fn write(&mut self, encoded: &Encoded) -> Result<()> {
match encoded.keyframe {
true => self.write_snapshot(encoded.payload.clone()),
false => self.write_delta(encoded.payload.clone()),
}
}
fn write_snapshot(&mut self, payload: bytes::Bytes) -> Result<()> {
if let Some(mut group) = self.group.take() {
group.finish()?;
}
let mut group = self.inner.append_group()?;
if let Err(err) = group.write_frame(moq_net::Timestamp::now(), payload) {
let _ = group.finish();
return Err(err.into());
}
match self.deltas {
true => self.group = Some(group),
false => group.finish()?,
}
Ok(())
}
fn write_delta(&mut self, payload: bytes::Bytes) -> Result<()> {
self.group
.as_mut()
.expect("the encoder only emits a delta after a snapshot opened a group")
.write_frame(moq_net::Timestamp::now(), payload)?;
Ok(())
}
fn finish(&mut self) -> Result<()> {
if let Some(mut group) = self.group.take() {
group.finish()?;
}
self.inner.finish()?;
Ok(())
}
}