use anyhow::Context;
use clap::Parser;
use futures::{stream::FuturesUnordered, StreamExt};
use std::net;
use moq_native_ietf::{quic, tls};
mod listing;
mod listings;
mod session;
pub use listing::*;
pub use listings::*;
pub use session::*;
#[derive(Clone, clap::Parser)]
pub struct Cli {
#[arg(long, default_value = "[::]:443")]
pub bind: net::SocketAddr,
#[command(flatten)]
pub tls: tls::Args,
#[arg(long, default_value = ".")]
pub namespace: String,
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
env_logger::init();
let tracer = tracing_subscriber::FmtSubscriber::builder()
.with_max_level(tracing::Level::WARN)
.finish();
tracing::subscriber::set_global_default(tracer).unwrap();
let cli = Cli::parse();
let tls = cli.tls.load()?;
let quic = quic::Endpoint::new(quic::Config {
bind: cli.bind,
tls,
})?;
let mut quic = quic.server.context("missing server certificate")?;
let listings = Listings::new(cli.namespace);
let mut tasks = FuturesUnordered::new();
log::info!("listening on {}", quic.local_addr()?);
loop {
tokio::select! {
res = quic.accept() => {
let session = res.context("failed to accept QUIC connection")?;
let session = Session::new(session, listings.clone());
tasks.push(async move {
if let Err(err) = session.run().await {
log::warn!("session terminated: {}", err);
}
});
},
res = tasks.next(), if !tasks.is_empty() => res.unwrap(),
}
}
}