From 81b5522942abe4584f84dbf99c848ac93f313ff9 Mon Sep 17 00:00:00 2001 From: Siavash Sameni Date: Mon, 13 Apr 2026 15:40:49 +0400 Subject: [PATCH] refactor: clap CLI parser, safety docs, dead code docs, cross-refs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Audit items 6, 8, 9, 10: #6 - Relay CLI: replaced 154-line manual parse_args() with clap derive (13 flags/options preserved, auto --help, --version from build hash) #8 - wzp-native: added # Safety docs to all 3 unsafe extern "C" fns #9 - wzp-crypto: documented x25519_static_secret/public as reserved for future static-key federation auth (not dead code, intentionally unused) #10 - Cross-references between quality.rs ↔ dred_tuner.rs module docs 368 tests passing, 0 regressions. Co-Authored-By: Claude Opus 4.6 (1M context) --- Cargo.lock | 119 +++++++++++++- crates/wzp-crypto/src/handshake.rs | 8 +- crates/wzp-native/src/lib.rs | 16 ++ crates/wzp-proto/src/dred_tuner.rs | 4 + crates/wzp-proto/src/quality.rs | 2 + crates/wzp-relay/Cargo.toml | 1 + crates/wzp-relay/src/main.rs | 251 ++++++++++++++--------------- 7 files changed, 265 insertions(+), 136 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index db39b7b..779b150 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -88,6 +88,56 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + [[package]] name = "anyhow" version = "1.0.102" @@ -851,7 +901,7 @@ checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ "atty", "bitflags 1.3.2", - "clap_lex", + "clap_lex 0.2.4", "indexmap 1.9.3", "once_cell", "strsim 0.10.0", @@ -859,6 +909,40 @@ dependencies = [ "textwrap", ] +[[package]] +name = "clap" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +dependencies = [ + "anstream", + "anstyle", + "clap_lex 1.1.0", + "strsim 0.11.1", +] + +[[package]] +name = "clap_derive" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "clap_lex" version = "0.2.4" @@ -868,6 +952,12 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + [[package]] name = "cmake" version = "0.1.58" @@ -883,6 +973,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2cefd04ca4a2f096acf5f44da5e5931436d030a620901f1fe8fa773e6b9de65b" +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + [[package]] name = "combine" version = "4.6.7" @@ -2829,6 +2925,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + [[package]] name = "itertools" version = "0.13.0" @@ -3355,7 +3457,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "805d5964d1e7a0006a7fdced7dae75084d66d18b35f1dfe81bd76929b1f8da0c" dependencies = [ "anyhow", - "clap", + "clap 3.2.25", "dasp", "dasp_interpolate", "dasp_ring_buffer", @@ -3632,6 +3734,12 @@ version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + [[package]] name = "opaque-debug" version = "0.3.1" @@ -6560,6 +6668,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "uuid" version = "1.23.0" @@ -7805,6 +7919,7 @@ dependencies = [ "axum 0.7.9", "bytes", "chrono", + "clap 4.6.0", "dashmap", "dirs", "futures-util", diff --git a/crates/wzp-crypto/src/handshake.rs b/crates/wzp-crypto/src/handshake.rs index f2a4a19..0c8e2da 100644 --- a/crates/wzp-crypto/src/handshake.rs +++ b/crates/wzp-crypto/src/handshake.rs @@ -18,10 +18,14 @@ use crate::session::ChaChaSession; pub struct WarzoneKeyExchange { /// Ed25519 signing key (identity). signing_key: SigningKey, - /// X25519 static secret (derived from seed, used for identity encryption). + /// X25519 static secret derived from identity seed. Reserved for future + /// use in static-key federation authentication (not used in current + /// ephemeral-only handshake protocol). #[allow(dead_code)] x25519_static_secret: StaticSecret, - /// X25519 static public key. + /// X25519 static public key derived from identity seed. Reserved for + /// future use in static-key federation authentication (not used in + /// current ephemeral-only handshake protocol). #[allow(dead_code)] x25519_static_public: X25519PublicKey, /// Ephemeral X25519 secret for the current call (set by generate_ephemeral). diff --git a/crates/wzp-native/src/lib.rs b/crates/wzp-native/src/lib.rs index 89f2e1d..aedf881 100644 --- a/crates/wzp-native/src/lib.rs +++ b/crates/wzp-native/src/lib.rs @@ -26,6 +26,11 @@ pub extern "C" fn wzp_native_version() -> i32 { /// Writes a NUL-terminated string into `out` (capped at `cap`) and /// returns bytes written excluding the NUL. +/// +/// # Safety +/// `out` must be a valid pointer to at least `cap` contiguous bytes of +/// writable memory. Passing a null pointer or zero capacity is safe +/// (returns 0), but a dangling non-null pointer is undefined behaviour. #[unsafe(no_mangle)] pub unsafe extern "C" fn wzp_native_hello(out: *mut u8, cap: usize) -> usize { const MSG: &[u8] = b"hello from wzp-native\0"; @@ -273,6 +278,11 @@ pub extern "C" fn wzp_native_audio_capture_available() -> usize { /// Read captured PCM samples from the capture ring. Returns the number /// of `i16` samples actually copied into `out` (may be less than /// `out_len` if the ring is empty). +/// +/// # Safety +/// `out` must be a valid pointer to `out_len` contiguous `i16` values. +/// The caller must ensure no other thread writes to the same buffer +/// concurrently. Passing a null pointer or zero length is safe (returns 0). #[unsafe(no_mangle)] pub unsafe extern "C" fn wzp_native_audio_read_capture(out: *mut i16, out_len: usize) -> usize { if out.is_null() || out_len == 0 { @@ -286,6 +296,12 @@ pub unsafe extern "C" fn wzp_native_audio_read_capture(out: *mut i16, out_len: u /// samples actually enqueued (may be less than `in_len` if the ring /// is nearly full — in practice the caller should pace to 20 ms /// frames and spin briefly if the ring is full). +/// +/// # Safety +/// `input` must be a valid pointer to `in_len` contiguous `i16` values +/// that remain valid for the duration of the call. Passing a null pointer +/// or zero length is safe (returns 0). The caller must not free or mutate +/// the buffer while this function is executing. #[unsafe(no_mangle)] pub unsafe extern "C" fn wzp_native_audio_write_playout(input: *const i16, in_len: usize) -> usize { if input.is_null() || in_len == 0 { diff --git a/crates/wzp-proto/src/dred_tuner.rs b/crates/wzp-proto/src/dred_tuner.rs index 1cd66e3..0370f02 100644 --- a/crates/wzp-proto/src/dred_tuner.rs +++ b/crates/wzp-proto/src/dred_tuner.rs @@ -10,6 +10,10 @@ //! prediction): when jitter variance spikes >30% over a 200 ms window — typical //! of Starlink satellite handovers — it temporarily boosts DRED to the maximum //! allowed for the current codec before packets actually start dropping. +//! +//! See also: [`crate::quality`] for discrete tier classification that drives +//! codec switching. DredTuner operates within a tier, adjusting DRED +//! parameters continuously based on live network metrics. use crate::CodecId; diff --git a/crates/wzp-proto/src/quality.rs b/crates/wzp-proto/src/quality.rs index 23aa7cf..882216e 100644 --- a/crates/wzp-proto/src/quality.rs +++ b/crates/wzp-proto/src/quality.rs @@ -1,3 +1,5 @@ +//! See also: [`crate::dred_tuner`] for continuous DRED tuning within a tier. + use std::collections::VecDeque; use std::time::{Duration, Instant}; diff --git a/crates/wzp-relay/Cargo.toml b/crates/wzp-relay/Cargo.toml index 68704b3..3eb61b7 100644 --- a/crates/wzp-relay/Cargo.toml +++ b/crates/wzp-relay/Cargo.toml @@ -20,6 +20,7 @@ bytes = { workspace = true } serde = { workspace = true } toml = "0.8" anyhow = "1" +clap = { version = "4", features = ["derive"] } reqwest = { version = "0.12", features = ["json"] } serde_json = "1" rustls = { version = "0.23", default-features = false, features = ["ring", "std"] } diff --git a/crates/wzp-relay/src/main.rs b/crates/wzp-relay/src/main.rs index 0250f60..8d93c24 100644 --- a/crates/wzp-relay/src/main.rs +++ b/crates/wzp-relay/src/main.rs @@ -12,6 +12,7 @@ use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; use std::time::Duration; +use clap::Parser; use tokio::sync::Mutex; use tracing::{debug, error, info, warn}; @@ -30,6 +31,72 @@ async fn close_transport(t: &dyn wzp_proto::MediaTransport, context: &str) { } } +/// WarzonePhone relay daemon — SFU, federation, direct-call signaling +#[derive(Parser, Debug)] +#[command(name = "wzp-relay", version = env!("WZP_BUILD_HASH"))] +struct Args { + /// Load config from TOML file (creates example if missing) + #[arg(short = 'c', long = "config")] + config_file: Option, + + /// Identity file path (creates if missing, uses OsRng) + #[arg(short = 'i', long)] + identity: Option, + + /// Listen address for QUIC connections + #[arg(long)] + listen: Option, + + /// Remote relay address for forwarding (disables room mode) + #[arg(long)] + remote: Option, + + /// featherChat auth endpoint (e.g., https://chat.example.com/v1/auth/validate). + /// When set, clients must send a bearer token as first signal message. + #[arg(long)] + auth_url: Option, + + /// Prometheus metrics HTTP port (e.g., 9090). Disabled if not set. + #[arg(long)] + metrics_port: Option, + + /// Peer relay to probe for health monitoring (repeatable) + #[arg(long = "probe")] + probe: Vec, + + /// Enable mesh mode (probes all --probe targets concurrently) + #[arg(long)] + probe_mesh: bool, + + /// Enable trunk batching for outgoing media in room mode + #[arg(long)] + trunking: bool, + + /// WebSocket listener port for browser clients (e.g., 8080) + #[arg(long)] + ws_port: Option, + + /// Directory to serve static files from (HTML/JS/WASM) + #[arg(long)] + static_dir: Option, + + /// Declare a room as global (bridged across federation). Repeatable. + #[arg(long = "global-room")] + global_room: Vec, + + /// Log packet headers for a room ('*' for all rooms) + #[arg(long)] + debug_tap: Option, + + /// JSONL event log file path for protocol analysis + #[arg(long)] + event_log: Option, + + /// Print mesh health table and exit (diagnostic) + #[arg(long)] + mesh_status: bool, +} + /// Parsed CLI result — config + identity path. struct CliResult { config: RelayConfig, @@ -39,25 +106,21 @@ struct CliResult { } fn parse_args() -> CliResult { - let args: Vec = std::env::args().collect(); + let args = Args::parse(); - // First pass: extract --config and --identity - let mut config_file = None; - let mut identity_path = None; - let mut i = 1; - while i < args.len() { - match args[i].as_str() { - "--config" | "-c" => { i += 1; config_file = args.get(i).cloned(); } - "--identity" | "-i" => { i += 1; identity_path = args.get(i).cloned(); } - _ => {} - } - i += 1; + // Handle --mesh-status: print and exit + if args.mesh_status { + let m = RelayMetrics::new(); + print!("{}", wzp_relay::probe::mesh_summary(m.registry())); + std::process::exit(0); } // Track if we need to create the config after identity is known - let config_needs_create = config_file.as_ref().map(|p| !std::path::Path::new(p).exists()).unwrap_or(false); + let config_needs_create = args.config_file.as_ref() + .map(|p| !std::path::Path::new(p).exists()) + .unwrap_or(false); - let mut config = if let Some(ref path) = config_file { + let mut config = if let Some(ref path) = args.config_file { if config_needs_create { // Will be re-created with personalized info after identity is loaded RelayConfig::default() @@ -73,125 +136,49 @@ fn parse_args() -> CliResult { }; // CLI flags override config file values - let mut i = 1; - while i < args.len() { - match args[i].as_str() { - "--config" | "-c" => { i += 1; } // already handled - "--identity" | "-i" => { i += 1; } // already handled - "--listen" => { - i += 1; - config.listen_addr = args.get(i).expect("--listen requires an address") - .parse().expect("invalid --listen address"); - } - "--remote" => { - i += 1; - config.remote_relay = Some( - args.get(i).expect("--remote requires an address") - .parse().expect("invalid --remote address"), - ); - } - "--auth-url" => { - i += 1; - config.auth_url = Some( - args.get(i).expect("--auth-url requires a URL").to_string(), - ); - } - "--metrics-port" => { - i += 1; - config.metrics_port = Some( - args.get(i).expect("--metrics-port requires a port number") - .parse().expect("invalid --metrics-port number"), - ); - } - "--probe" => { - i += 1; - let addr: SocketAddr = args.get(i) - .expect("--probe requires an address") - .parse() - .expect("invalid --probe address"); - config.probe_targets.push(addr); - } - "--probe-mesh" => { - config.probe_mesh = true; - } - "--trunking" => { - config.trunking_enabled = true; - } - "--ws-port" => { - i += 1; - config.ws_port = Some( - args.get(i).expect("--ws-port requires a port number") - .parse().expect("invalid --ws-port number"), - ); - } - "--static-dir" => { - i += 1; - config.static_dir = Some( - args.get(i).expect("--static-dir requires a directory path").to_string(), - ); - } - "--global-room" => { - i += 1; - config.global_rooms.push(wzp_relay::config::GlobalRoomConfig { - name: args.get(i).expect("--global-room requires a room name").to_string(), - }); - } - "--debug-tap" => { - i += 1; - config.debug_tap = Some( - args.get(i).expect("--debug-tap requires a room name (or '*' for all)").to_string(), - ); - } - "--event-log" => { - i += 1; - config.event_log = Some( - args.get(i).expect("--event-log requires a file path").to_string(), - ); - } - "--version" | "-V" => { - println!("wzp-relay {}", env!("WZP_BUILD_HASH")); - std::process::exit(0); - } - "--mesh-status" => { - // Print mesh table from a fresh registry and exit. - // In practice this is useful after the relay has been running; - // here we just demonstrate the formatter with an empty registry. - let m = RelayMetrics::new(); - print!("{}", wzp_relay::probe::mesh_summary(m.registry())); - std::process::exit(0); - } - "--help" | "-h" => { - eprintln!("Usage: wzp-relay [--config ] [--listen ] [--remote ] [--auth-url ] [--metrics-port ] [--probe ]... [--probe-mesh] [--mesh-status]"); - eprintln!(); - eprintln!("Options:"); - eprintln!(" -c, --config Load config from TOML file (creates example if missing)"); - eprintln!(" -i, --identity Identity file path (creates if missing, uses OsRng)"); - eprintln!(" --listen Listen address (default: 0.0.0.0:4433)"); - eprintln!(" --remote Remote relay for forwarding (disables room mode)"); - eprintln!(" --auth-url featherChat auth endpoint (e.g., https://chat.example.com/v1/auth/validate)"); - eprintln!(" When set, clients must send a bearer token as first signal message."); - eprintln!(" --metrics-port Prometheus metrics HTTP port (e.g., 9090). Disabled if not set."); - eprintln!(" --probe Peer relay to probe for health monitoring (repeatable)."); - eprintln!(" --probe-mesh Enable mesh mode (mark config flag, probes all --probe targets)."); - eprintln!(" --mesh-status Print mesh health table and exit (diagnostic)."); - eprintln!(" --trunking Enable trunk batching for outgoing media in room mode."); - eprintln!(" --global-room Declare a room as global (bridged across federation). Repeatable."); - eprintln!(" --debug-tap Log packet headers for a room ('*' for all rooms)."); - eprintln!(" --ws-port WebSocket listener port for browser clients (e.g., 8080)."); - eprintln!(" --static-dir Directory to serve static files from (HTML/JS/WASM)."); - eprintln!(); - eprintln!("Room mode (default):"); - eprintln!(" Clients join rooms by name. Packets forwarded to all others (SFU)."); - std::process::exit(0); - } - other => { - eprintln!("unknown argument: {other}"); - std::process::exit(1); - } - } - i += 1; + if let Some(addr) = args.listen { + config.listen_addr = addr; + } + if let Some(addr) = args.remote { + config.remote_relay = Some(addr); + } + if let Some(url) = args.auth_url { + config.auth_url = Some(url); + } + if let Some(port) = args.metrics_port { + config.metrics_port = Some(port); + } + if !args.probe.is_empty() { + config.probe_targets.extend(args.probe); + } + if args.probe_mesh { + config.probe_mesh = true; + } + if args.trunking { + config.trunking_enabled = true; + } + if let Some(port) = args.ws_port { + config.ws_port = Some(port); + } + if let Some(dir) = args.static_dir { + config.static_dir = Some(dir); + } + for name in args.global_room { + config.global_rooms.push(wzp_relay::config::GlobalRoomConfig { name }); + } + if let Some(tap) = args.debug_tap { + config.debug_tap = Some(tap); + } + if let Some(log) = args.event_log { + config.event_log = Some(log); + } + + CliResult { + config, + identity_path: args.identity, + config_file: args.config_file, + config_needs_create, } - CliResult { config, identity_path, config_file, config_needs_create } } struct RelayStats {