mirror of
https://github.com/nestriness/warp.git
synced 2025-12-11 09:25:39 +02:00
Add `cli` functionality
This commit is contained in:
124
Cargo.lock
generated
124
Cargo.lock
generated
@@ -41,6 +41,54 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
|
||||
dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.78"
|
||||
@@ -338,6 +386,62 @@ dependencies = [
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcfab8ba68f3668e89f6ff60f5b205cea56aa7b769451a59f34b8682f51c056d"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.43",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
|
||||
|
||||
[[package]]
|
||||
name = "clap_mangen"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10b5db60b3310cdb376fbeb8826e875a38080d0c61bdec0a91a3da8338948736"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"roff",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "2.4.0"
|
||||
@@ -1545,6 +1649,12 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "roff"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.23"
|
||||
@@ -1786,6 +1896,12 @@ version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
@@ -2057,6 +2173,12 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.0"
|
||||
@@ -2092,6 +2214,8 @@ name = "warp"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"clap_mangen",
|
||||
"env_logger",
|
||||
"gst-plugin-fmp4",
|
||||
"gstreamer",
|
||||
|
||||
@@ -30,3 +30,9 @@ mp4 = "0.13"
|
||||
moq-transport = { git = "https://github.com/kixelated/moq-rs", version = "0.2.0" }
|
||||
serde_json = "1"
|
||||
rfc6381-codec = "0.1"
|
||||
clap = { version = "4", features = ["derive"] }
|
||||
|
||||
[build-dependencies]
|
||||
clap = { version = "4", features = ["derive"] }
|
||||
clap_mangen = "0.2"
|
||||
url = "2"
|
||||
|
||||
15
build.rs
Normal file
15
build.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
include!("src/cli.rs");
|
||||
|
||||
use clap::CommandFactory;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let out_dir = std::path::PathBuf::from(
|
||||
std::env::var_os("OUT_DIR").ok_or(std::io::Error::new(std::io::ErrorKind::NotFound, "OUT_DIR not found"))?,
|
||||
);
|
||||
let cmd = Config::command();
|
||||
let man = clap_mangen::Man::new(cmd);
|
||||
let mut buffer: Vec<u8> = Default::default();
|
||||
man.render(&mut buffer)?;
|
||||
std::fs::write(out_dir.join("moq-pub.1"), buffer)?;
|
||||
Ok(())
|
||||
}
|
||||
48
src/cli.rs
Normal file
48
src/cli.rs
Normal file
@@ -0,0 +1,48 @@
|
||||
use clap::Parser;
|
||||
use std::{net, path};
|
||||
use url::Url;
|
||||
|
||||
#[derive(Parser, Clone, Debug)]
|
||||
pub struct Config {
|
||||
/// Listen for UDP packets on the given address.
|
||||
#[arg(long, default_value = "[::]:0")]
|
||||
pub bind: net::SocketAddr,
|
||||
|
||||
/// Advertise this frame rate in the catalog (informational)
|
||||
// TODO auto-detect this from the input when not provided
|
||||
#[arg(long, default_value = "24")]
|
||||
pub fps: u8,
|
||||
|
||||
/// Advertise this bit rate in the catalog (informational)
|
||||
// TODO auto-detect this from the input when not provided
|
||||
#[arg(long, default_value = "1500000")]
|
||||
pub bitrate: u32,
|
||||
|
||||
/// Connect to the given URL starting with https://
|
||||
#[arg(value_parser = moq_url)]
|
||||
pub url: Url,
|
||||
|
||||
/// Use the TLS root CA at this path, encoded as PEM.
|
||||
///
|
||||
/// This value can be provided multiple times for multiple roots.
|
||||
/// If this is empty, system roots will be used instead
|
||||
#[arg(long)]
|
||||
pub tls_root: Vec<path::PathBuf>,
|
||||
|
||||
/// Danger: Disable TLS certificate verification.
|
||||
///
|
||||
/// Fine for local development, but should be used in caution in production.
|
||||
#[arg(long)]
|
||||
pub tls_disable_verify: bool,
|
||||
}
|
||||
|
||||
fn moq_url(s: &str) -> Result<Url, String> {
|
||||
let url = Url::try_from(s).map_err(|e| e.to_string())?;
|
||||
|
||||
// Make sure the scheme is moq
|
||||
if url.scheme() != "https" {
|
||||
return Err("url scheme must be https:// for WebTransport".to_string());
|
||||
}
|
||||
|
||||
Ok(url)
|
||||
}
|
||||
69
src/main.rs
69
src/main.rs
@@ -1,14 +1,16 @@
|
||||
use anyhow::Context;
|
||||
use url::Url;
|
||||
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
use std::{fs, io, sync::Arc, time};
|
||||
|
||||
use moq_transport::cache::broadcast;
|
||||
use clap::Parser;
|
||||
|
||||
mod cli;
|
||||
use cli::*;
|
||||
|
||||
mod media;
|
||||
use media::*;
|
||||
|
||||
//TODO: add audio pipeline
|
||||
// TODO: clap complete
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
env_logger::init();
|
||||
@@ -19,6 +21,8 @@ async fn main() -> anyhow::Result<()> {
|
||||
.finish();
|
||||
tracing::subscriber::set_global_default(tracer).unwrap();
|
||||
|
||||
let config = Config::parse();
|
||||
|
||||
let (publisher, subscriber) = broadcast::new("");
|
||||
|
||||
// Create a list of acceptable root certificates.
|
||||
@@ -26,10 +30,27 @@ async fn main() -> anyhow::Result<()> {
|
||||
|
||||
// Add the platform's native root certificates.
|
||||
// Add the platform's native root certificates.
|
||||
for cert in rustls_native_certs::load_native_certs().context("could not load platform certs")? {
|
||||
roots
|
||||
.add(&rustls::Certificate(cert.0))
|
||||
.context("failed to add root cert")?;
|
||||
if config.tls_root.is_empty() {
|
||||
// Add the platform's native root certificates.
|
||||
for cert in
|
||||
rustls_native_certs::load_native_certs().context("could not load platform certs")?
|
||||
{
|
||||
roots
|
||||
.add(&rustls::Certificate(cert.0))
|
||||
.context("failed to add root cert")?;
|
||||
}
|
||||
} else {
|
||||
// Add the specified root certificates.
|
||||
for root in &config.tls_root {
|
||||
let root = fs::File::open(root).context("failed to open root cert file")?;
|
||||
let mut root = io::BufReader::new(root);
|
||||
|
||||
let root = rustls_pemfile::certs(&mut root).context("failed to read root cert")?;
|
||||
anyhow::ensure!(root.len() == 1, "expected a single root cert");
|
||||
let root = rustls::Certificate(root[0].to_owned());
|
||||
|
||||
roots.add(&root).context("failed to add root cert")?;
|
||||
}
|
||||
}
|
||||
|
||||
let mut tls_config = rustls::ClientConfig::builder()
|
||||
@@ -37,20 +58,26 @@ async fn main() -> anyhow::Result<()> {
|
||||
.with_root_certificates(roots)
|
||||
.with_no_client_auth();
|
||||
|
||||
// Allow disabling TLS verification altogether.
|
||||
if config.tls_disable_verify {
|
||||
let noop = NoCertificateVerification {};
|
||||
tls_config
|
||||
.dangerous()
|
||||
.set_certificate_verifier(Arc::new(noop));
|
||||
}
|
||||
|
||||
tls_config.alpn_protocols = vec![webtransport_quinn::ALPN.to_vec()]; // this one is important
|
||||
|
||||
let arc_tls_config = std::sync::Arc::new(tls_config);
|
||||
let quinn_client_config = quinn::ClientConfig::new(arc_tls_config);
|
||||
|
||||
let mut endpoint =
|
||||
quinn::Endpoint::client(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0))?;
|
||||
quinn::Endpoint::client(config.bind)?;
|
||||
endpoint.set_default_client_config(quinn_client_config);
|
||||
|
||||
let url = Url::try_from("https://localhost:4443").context("Could not get url")?;
|
||||
log::info!("connecting to relay: url={}", config.url);
|
||||
|
||||
log::info!("connecting to relay: url={}", url);
|
||||
|
||||
let session = webtransport_quinn::connect(&endpoint, &url)
|
||||
let session = webtransport_quinn::connect(&endpoint, &config.url)
|
||||
.await
|
||||
.context("failed to create WebTransport session")?;
|
||||
|
||||
@@ -65,3 +92,19 @@ async fn main() -> anyhow::Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub struct NoCertificateVerification {}
|
||||
|
||||
impl rustls::client::ServerCertVerifier for NoCertificateVerification {
|
||||
fn verify_server_cert(
|
||||
&self,
|
||||
_end_entity: &rustls::Certificate,
|
||||
_intermediates: &[rustls::Certificate],
|
||||
_server_name: &rustls::ServerName,
|
||||
_scts: &mut dyn Iterator<Item = &[u8]>,
|
||||
_ocsp_response: &[u8],
|
||||
_now: time::SystemTime,
|
||||
) -> Result<rustls::client::ServerCertVerified, rustls::Error> {
|
||||
Ok(rustls::client::ServerCertVerified::assertion())
|
||||
}
|
||||
}
|
||||
@@ -118,7 +118,7 @@ impl GST {
|
||||
pub async fn run(mut broadcast: broadcast::Publisher) -> anyhow::Result<()> {
|
||||
gst::init()?;
|
||||
|
||||
//FIXME: Get this value from commandline argument
|
||||
//FIXME: add audio pipeline
|
||||
|
||||
gstfmp4::plugin_register_static()?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user