use std::net;
use anyhow::Context;
use clap::{Parser, Subcommand};
use url::Url;
use moq_karp::{cmaf, produce};
use moq_native::quic;
#[derive(Parser, Clone)]
struct Cli {
#[arg(long, default_value = "[::]:0")]
pub bind: net::SocketAddr,
#[command(flatten)]
pub log: moq_native::log::Args,
#[command(flatten)]
pub tls: moq_native::tls::Args,
#[arg(long, default_value = "https://relay.quic.video")]
pub url: Url,
#[arg(long, required = true)]
pub path: Vec<String>,
#[command(subcommand)]
pub command: Command,
}
#[derive(Subcommand, Clone)]
pub enum Command {
Publish,
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let cli = Cli::parse();
cli.log.init();
let tls = cli.tls.load()?;
let quic = quic::Endpoint::new(quic::Config { bind: cli.bind, tls })?;
tracing::info!(url = %cli.url, "connecting");
let session = quic.client.connect(&cli.url).await?;
let session = moq_transfork::Session::connect(session).await?;
let path = moq_transfork::Path::new(cli.path);
match cli.command {
Command::Publish => publish(session, path).await,
}
}
#[tracing::instrument("publish", skip_all, err, fields(?path))]
async fn publish(mut session: moq_transfork::Session, path: moq_transfork::Path) -> anyhow::Result<()> {
let broadcast = produce::Resumable::new(path).broadcast();
let mut input = tokio::io::stdin();
let mut import = cmaf::Import::new(broadcast);
import.init_from(&mut input).await.context("failed to initialize")?;
tracing::info!(catalog = ?import.catalog());
import.publish(&mut session)?;
tokio::select! {
res = import.read_from(&mut input) => Ok(res?),
res = session.closed() => Err(res.into()),
}
}