moq-rs/moq-clock/src/clock.rs

149 lines
3.5 KiB
Rust

use std::time;
use anyhow::Context;
use moq_transport::{
cache::{fragment, segment, track},
VarInt,
};
use chrono::prelude::*;
pub struct Publisher {
track: track::Publisher,
}
impl Publisher {
pub fn new(track: track::Publisher) -> Self {
Self { track }
}
pub async fn run(mut self) -> anyhow::Result<()> {
let start = Utc::now();
let mut now = start;
// Just for fun, don't start at zero.
let mut sequence = start.minute();
loop {
let segment = self
.track
.create_segment(segment::Info {
sequence: VarInt::from_u32(sequence),
priority: 0,
expires: Some(time::Duration::from_secs(60)),
})
.context("failed to create minute segment")?;
sequence += 1;
tokio::spawn(async move {
if let Err(err) = Self::send_segment(segment, now).await {
log::warn!("failed to send minute: {:?}", err);
}
});
let next = now + chrono::Duration::minutes(1);
let next = next.with_second(0).unwrap().with_nanosecond(0).unwrap();
let delay = (next - now).to_std().unwrap();
tokio::time::sleep(delay).await;
now = next; // just assume we didn't undersleep
}
}
async fn send_segment(mut segment: segment::Publisher, mut now: DateTime<Utc>) -> anyhow::Result<()> {
// Everything but the second.
let base = now.format("%Y-%m-%d %H:%M:").to_string();
segment
.fragment(VarInt::ZERO, base.len())?
.chunk(base.clone().into())
.context("failed to write base")?;
loop {
let delta = now.format("%S").to_string();
let sequence = VarInt::from_u32(now.second() + 1);
segment
.fragment(sequence, delta.len())?
.chunk(delta.clone().into())
.context("failed to write delta")?;
println!("{}{}", base, delta);
let next = now + chrono::Duration::seconds(1);
let next = next.with_nanosecond(0).unwrap();
let delay = (next - now).to_std().unwrap();
tokio::time::sleep(delay).await;
// Get the current time again to check if we overslept
let next = Utc::now();
if next.minute() != now.minute() {
return Ok(());
}
now = next;
}
}
}
pub struct Subscriber {
track: track::Subscriber,
}
impl Subscriber {
pub fn new(track: track::Subscriber) -> Self {
Self { track }
}
pub async fn run(mut self) -> anyhow::Result<()> {
while let Some(segment) = self.track.segment().await.context("failed to get segment")? {
log::debug!("got segment: {:?}", segment);
tokio::spawn(async move {
if let Err(err) = Self::recv_segment(segment).await {
log::warn!("failed to receive segment: {:?}", err);
}
});
}
Ok(())
}
async fn recv_segment(mut segment: segment::Subscriber) -> anyhow::Result<()> {
let first = segment
.fragment()
.await
.context("failed to get first fragment")?
.context("no fragments in segment")?;
log::debug!("got first: {:?}", first);
if first.sequence.into_inner() != 0 {
anyhow::bail!("first object must be zero; I'm not going to implement a reassembly buffer");
}
let base = Self::recv_fragment(first, Vec::new()).await?;
log::debug!("read base: {:?}", String::from_utf8_lossy(&base));
while let Some(fragment) = segment.fragment().await? {
log::debug!("next fragment: {:?}", fragment);
let value = Self::recv_fragment(fragment, base.clone()).await?;
let str = String::from_utf8(value).context("invalid UTF-8")?;
println!("{}", str);
}
Ok(())
}
async fn recv_fragment(mut fragment: fragment::Subscriber, mut buf: Vec<u8>) -> anyhow::Result<Vec<u8>> {
while let Some(data) = fragment.chunk().await? {
buf.extend_from_slice(&data);
}
Ok(buf)
}
}