use std::net;
use anyhow::Context;
use clap::Parser;
use url::Url;
use moq_native_ietf::quic;
use moq_sub::media::Media;
use moq_transport::{coding::TrackNamespace, serve::Tracks};
#[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 out = tokio::io::stdout();
let config = Config::parse();
let tls = config.tls.load()?;
let quic = quic::Endpoint::new(quic::Config::new(config.bind, None, tls)?)?;
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
);
let (session, subscriber) = moq_transport::session::Subscriber::connect(session, transport)
.await
.context("failed to create MoQ Transport session")?;
let tracks = Tracks::new(TrackNamespace::from_utf8_path(&config.name));
let mut media = Media::new(subscriber, tracks, out, config.catalog).await?;
tokio::select! {
res = session.run() => res.context("session error")?,
res = media.run() => res.context("media error")?,
}
Ok(())
}
#[derive(Parser, Clone)]
pub struct Config {
#[arg(long, default_value = "[::]:0")]
pub bind: net::SocketAddr,
#[arg(value_parser = moq_url)]
pub url: Url,
#[arg(long)]
pub name: String,
#[command(flatten)]
pub tls: moq_native_ietf::tls::Args,
#[arg(long)]
pub catalog: bool,
}
fn moq_url(s: &str) -> Result<Url, String> {
let url = Url::try_from(s).map_err(|e| e.to_string())?;
if url.scheme() != "https" && url.scheme() != "moqt" {
return Err("url scheme must be https:// for WebTransport & moqt:// for QUIC".to_string());
}
Ok(url)
}