mod client;
mod publish;
mod server;
mod web;
use client::*;
use publish::*;
use server::*;
use web::*;
use clap::{Parser, Subcommand};
use std::path::PathBuf;
use std::time::Duration;
use url::Url;
#[derive(Parser, Clone)]
#[command(version = env!("VERSION"))]
pub struct Cli {
#[command(flatten)]
log: moq_native::Log,
#[command(flatten)]
#[cfg(feature = "iroh")]
iroh: moq_native::IrohEndpointConfig,
#[arg(long, default_missing_value = "1", num_args = 0..=1, require_equals = true, value_name = "SECS")]
stats: Option<f64>,
#[command(subcommand)]
command: Command,
}
#[derive(Subcommand, Clone)]
pub enum Command {
Serve {
#[command(flatten)]
config: moq_native::ServerConfig,
#[arg(long)]
name: String,
#[arg(long)]
dir: Option<PathBuf>,
#[command(subcommand)]
format: PublishFormat,
},
Publish {
#[command(flatten)]
config: moq_native::ClientConfig,
#[arg(long)]
url: Url,
#[arg(long)]
name: String,
#[command(subcommand)]
format: PublishFormat,
},
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
rustls::crypto::aws_lc_rs::default_provider()
.install_default()
.expect("failed to install default crypto provider");
let cli = Cli::parse();
cli.log.init();
let publish = Publish::new(match &cli.command {
Command::Serve { format, .. } => format,
Command::Publish { format, .. } => format,
})?;
let stats_interval = cli
.stats
.map(|secs| {
anyhow::ensure!(
secs.is_finite() && secs > 0.0,
"--stats interval must be a positive number"
);
Ok(Duration::from_secs_f64(secs))
})
.transpose()?;
#[cfg(feature = "iroh")]
let iroh = cli.iroh.bind().await?;
match cli.command {
Command::Serve { config, dir, name, .. } => {
let web_bind = config.bind.clone().unwrap_or_else(|| "[::]:443".to_string());
let server = config.init()?;
#[cfg(feature = "iroh")]
let server = server.with_iroh(iroh);
let web_tls = server.tls_info();
tokio::select! {
res = run_server(server, name, publish.consume()) => res,
res = run_web(&web_bind, web_tls, dir) => res,
res = publish.run(stats_interval) => res,
}
}
Command::Publish { config, url, name, .. } => {
let client = config.init()?;
#[cfg(feature = "iroh")]
let client = client.with_iroh(iroh);
run_client(client, url, name, publish, stats_interval).await
}
}
}