use moq_native_ietf::quic;
use anyhow::Context;
mod cli;
mod clock;
use clap::Parser;
use cli::Cli;
use moq_transport::{
coding::TrackNamespace,
serve,
session::{Publisher, Subscriber},
};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info,quinn=warn")),
)
.init();
let config = Cli::parse();
let tls = config.tls.load()?;
let quic = quic::Endpoint::new(quic::Config::new(config.bind, None, tls)?)?;
tracing::info!("connecting to server: url={}", config.url);
let (session, connection_id, transport) = quic.client.connect(&config.url, None).await?;
tracing::info!(
"connected with CID: {} (use this to look up qlog/mlog on server)",
connection_id
);
if config.publish {
let (session, mut publisher) = Publisher::connect(session, transport)
.await
.context("failed to create MoQ Transport session")?;
if config.datagrams {
tracing::info!("publishing clock via datagrams");
let (mut tracks_writer, _, tracks_reader) = serve::Tracks {
namespace: TrackNamespace::from_utf8_path(&config.namespace),
}
.produce();
let track_writer = tracks_writer.create(&config.track).unwrap();
let clock_publisher = clock::Publisher::new_datagram(track_writer.datagrams()?);
tokio::select! {
res = session.run() => res.context("session error")?,
res = clock_publisher.run() => res.context("clock error")?,
res = publisher.publish_namespace(tracks_reader) => res.context("failed to serve tracks")?,
}
} else {
tracing::info!("publishing clock via streams");
let (mut tracks_writer, _, tracks_reader) = serve::Tracks {
namespace: TrackNamespace::from_utf8_path(&config.namespace),
}
.produce();
let track_writer = tracks_writer.create(&config.track).unwrap();
let clock_publisher = clock::Publisher::new(track_writer.subgroups()?);
tokio::select! {
res = session.run() => res.context("session error")?,
res = clock_publisher.run() => res.context("clock error")?,
res = publisher.publish_namespace(tracks_reader) => res.context("failed to serve tracks")?,
}
}
} else {
let (session, mut subscriber) = Subscriber::connect(session, transport)
.await
.context("failed to create MoQ Transport session")?;
let track_namespace = TrackNamespace::from_utf8_path(&config.namespace);
if config.track_status {
subscriber.track_status(&track_namespace, &config.track);
}
let (track_writer, track_reader) =
serve::Track::new(track_namespace, config.track).produce();
let clock_subscriber = clock::Subscriber::new(track_reader);
tokio::select! {
res = session.run() => res.context("session error")?,
res = clock_subscriber.run() => res.context("clock error")?,
res = subscriber.subscribe(track_writer) => res.context("failed to subscribe to track")?,
}
}
Ok(())
}