use anyhow::Context;
use moq_transport::serve::{
Datagram, DatagramsReader, DatagramsWriter, StreamReader, Subgroup, SubgroupWriter,
SubgroupsReader, SubgroupsWriter, TrackReader, TrackReaderMode,
};
use chrono::prelude::*;
use tokio::task;
pub struct Publisher {
track_subgroups_writer: Option<SubgroupsWriter>,
track_datagrams_writer: Option<DatagramsWriter>,
}
impl Publisher {
pub fn new(track_subgroups_writer: SubgroupsWriter) -> Self {
Self {
track_subgroups_writer: Some(track_subgroups_writer),
track_datagrams_writer: None,
}
}
pub fn new_datagram(track_datagrams_writer: DatagramsWriter) -> Self {
Self {
track_subgroups_writer: None,
track_datagrams_writer: Some(track_datagrams_writer),
}
}
pub async fn run(mut self) -> anyhow::Result<()> {
let start = Utc::now();
let mut now = start;
let mut next_group_id = start.minute();
loop {
let mut next: DateTime<Utc>;
if let Some(track_subgroups_writer) = &mut self.track_subgroups_writer {
let subgroup_writer = track_subgroups_writer
.create(Subgroup {
group_id: next_group_id as u64,
subgroup_id: 0,
priority: 0,
})
.context("failed to create minute segment")?;
tokio::spawn(async move {
if let Err(err) = Self::send_subgroup_objects(subgroup_writer, now).await {
tracing::warn!("failed to send minute: {:?}", err);
}
});
next = now + chrono::Duration::try_minutes(1).unwrap();
next = next.with_second(0).unwrap().with_nanosecond(0).unwrap();
} else if let Some(track_datagrams_writer) = &mut self.track_datagrams_writer {
let time_str = now.format("%Y-%m-%d %H:%M:%S").to_string();
track_datagrams_writer
.write(Datagram {
group_id: next_group_id as u64,
object_id: 0,
priority: 127,
payload: time_str.clone().into_bytes().into(),
extension_headers: Default::default(),
})
.context("failed to write datagram")?;
println!("{}", time_str);
next = now + chrono::Duration::try_seconds(1).unwrap();
next = next.with_nanosecond(0).unwrap();
} else {
return Err(anyhow::anyhow!("no track writer available"));
}
next_group_id += 1;
let delay = (next - now).to_std().unwrap();
tokio::time::sleep(delay).await;
now = next; }
}
async fn send_subgroup_objects(
mut subgroup_writer: SubgroupWriter,
mut now: DateTime<Utc>,
) -> anyhow::Result<()> {
let base = now.format("%Y-%m-%d %H:%M:").to_string();
subgroup_writer
.write(base.clone().into())
.context("failed to write base")?;
loop {
let delta = now.format("%S").to_string();
subgroup_writer
.write(delta.clone().into())
.context("failed to write delta")?;
println!("{base}{delta}");
let next = now + chrono::Duration::try_seconds(1).unwrap();
let next = next.with_nanosecond(0).unwrap();
let delay = (next - now).to_std().unwrap();
tokio::time::sleep(delay).await;
let next = Utc::now();
if next.minute() != now.minute() {
return Ok(());
}
now = next;
}
}
}
pub struct Subscriber {
track_reader: TrackReader,
}
impl Subscriber {
pub fn new(track_reader: TrackReader) -> Self {
Self { track_reader }
}
pub async fn run(self) -> anyhow::Result<()> {
match self
.track_reader
.mode()
.await
.context("failed to get mode")?
{
TrackReaderMode::Stream(stream) => Self::recv_stream(stream).await,
TrackReaderMode::Subgroups(subgroups) => Self::recv_subgroups(subgroups).await,
TrackReaderMode::Datagrams(datagrams) => Self::recv_datagrams(datagrams).await,
}
}
async fn recv_stream(mut stream_reader: StreamReader) -> anyhow::Result<()> {
while let Some(mut stream_group_reader) = stream_reader.next().await? {
while let Some(object) = stream_group_reader.read_next().await? {
let str = String::from_utf8_lossy(&object);
println!("{str}");
}
}
Ok(())
}
async fn recv_subgroups(mut subgroups_reader: SubgroupsReader) -> anyhow::Result<()> {
while let Some(mut subgroup_reader) = subgroups_reader.next().await? {
task::spawn(async move {
if let Err(e) = async {
let base = subgroup_reader
.read_next()
.await
.context("failed to get first object")?
.context("empty subgroup")?;
let base = String::from_utf8_lossy(&base);
while let Some(object) = subgroup_reader.read_next().await? {
let str = String::from_utf8_lossy(&object);
println!("{base}{str}");
}
Ok::<(), anyhow::Error>(())
}
.await
{
eprintln!("Error handling subgroup: {:?}", e);
}
});
}
Ok(())
}
async fn recv_datagrams(mut datagrams_reader: DatagramsReader) -> anyhow::Result<()> {
while let Some(datagram) = datagrams_reader.read().await? {
let str = String::from_utf8_lossy(&datagram.payload);
println!("{str}");
}
Ok(())
}
}