refactor: clap CLI parser, safety docs, dead code docs, cross-refs
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) <noreply@anthropic.com>
This commit is contained in:
119
Cargo.lock
generated
119
Cargo.lock
generated
@@ -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",
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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};
|
||||
|
||||
|
||||
@@ -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"] }
|
||||
|
||||
@@ -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<String>,
|
||||
|
||||
/// Identity file path (creates if missing, uses OsRng)
|
||||
#[arg(short = 'i', long)]
|
||||
identity: Option<String>,
|
||||
|
||||
/// Listen address for QUIC connections
|
||||
#[arg(long)]
|
||||
listen: Option<SocketAddr>,
|
||||
|
||||
/// Remote relay address for forwarding (disables room mode)
|
||||
#[arg(long)]
|
||||
remote: Option<SocketAddr>,
|
||||
|
||||
/// 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<String>,
|
||||
|
||||
/// Prometheus metrics HTTP port (e.g., 9090). Disabled if not set.
|
||||
#[arg(long)]
|
||||
metrics_port: Option<u16>,
|
||||
|
||||
/// Peer relay to probe for health monitoring (repeatable)
|
||||
#[arg(long = "probe")]
|
||||
probe: Vec<SocketAddr>,
|
||||
|
||||
/// 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<u16>,
|
||||
|
||||
/// Directory to serve static files from (HTML/JS/WASM)
|
||||
#[arg(long)]
|
||||
static_dir: Option<String>,
|
||||
|
||||
/// Declare a room as global (bridged across federation). Repeatable.
|
||||
#[arg(long = "global-room")]
|
||||
global_room: Vec<String>,
|
||||
|
||||
/// Log packet headers for a room ('*' for all rooms)
|
||||
#[arg(long)]
|
||||
debug_tap: Option<String>,
|
||||
|
||||
/// JSONL event log file path for protocol analysis
|
||||
#[arg(long)]
|
||||
event_log: Option<String>,
|
||||
|
||||
/// 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<String> = 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");
|
||||
if let Some(addr) = args.listen {
|
||||
config.listen_addr = addr;
|
||||
}
|
||||
"--remote" => {
|
||||
i += 1;
|
||||
config.remote_relay = Some(
|
||||
args.get(i).expect("--remote requires an address")
|
||||
.parse().expect("invalid --remote address"),
|
||||
);
|
||||
if let Some(addr) = args.remote {
|
||||
config.remote_relay = Some(addr);
|
||||
}
|
||||
"--auth-url" => {
|
||||
i += 1;
|
||||
config.auth_url = Some(
|
||||
args.get(i).expect("--auth-url requires a URL").to_string(),
|
||||
);
|
||||
if let Some(url) = args.auth_url {
|
||||
config.auth_url = Some(url);
|
||||
}
|
||||
"--metrics-port" => {
|
||||
i += 1;
|
||||
config.metrics_port = Some(
|
||||
args.get(i).expect("--metrics-port requires a port number")
|
||||
.parse().expect("invalid --metrics-port number"),
|
||||
);
|
||||
if let Some(port) = args.metrics_port {
|
||||
config.metrics_port = Some(port);
|
||||
}
|
||||
"--probe" => {
|
||||
i += 1;
|
||||
let addr: SocketAddr = args.get(i)
|
||||
.expect("--probe requires an address")
|
||||
.parse()
|
||||
.expect("invalid --probe address");
|
||||
config.probe_targets.push(addr);
|
||||
if !args.probe.is_empty() {
|
||||
config.probe_targets.extend(args.probe);
|
||||
}
|
||||
"--probe-mesh" => {
|
||||
if args.probe_mesh {
|
||||
config.probe_mesh = true;
|
||||
}
|
||||
"--trunking" => {
|
||||
if args.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"),
|
||||
);
|
||||
if let Some(port) = args.ws_port {
|
||||
config.ws_port = Some(port);
|
||||
}
|
||||
"--static-dir" => {
|
||||
i += 1;
|
||||
config.static_dir = Some(
|
||||
args.get(i).expect("--static-dir requires a directory path").to_string(),
|
||||
);
|
||||
if let Some(dir) = args.static_dir {
|
||||
config.static_dir = Some(dir);
|
||||
}
|
||||
"--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(),
|
||||
});
|
||||
for name in args.global_room {
|
||||
config.global_rooms.push(wzp_relay::config::GlobalRoomConfig { name });
|
||||
}
|
||||
"--debug-tap" => {
|
||||
i += 1;
|
||||
config.debug_tap = Some(
|
||||
args.get(i).expect("--debug-tap requires a room name (or '*' for all)").to_string(),
|
||||
);
|
||||
if let Some(tap) = args.debug_tap {
|
||||
config.debug_tap = Some(tap);
|
||||
}
|
||||
"--event-log" => {
|
||||
i += 1;
|
||||
config.event_log = Some(
|
||||
args.get(i).expect("--event-log requires a file path").to_string(),
|
||||
);
|
||||
if let Some(log) = args.event_log {
|
||||
config.event_log = Some(log);
|
||||
}
|
||||
"--version" | "-V" => {
|
||||
println!("wzp-relay {}", env!("WZP_BUILD_HASH"));
|
||||
std::process::exit(0);
|
||||
|
||||
CliResult {
|
||||
config,
|
||||
identity_path: args.identity,
|
||||
config_file: args.config_file,
|
||||
config_needs_create,
|
||||
}
|
||||
"--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 <path>] [--listen <addr>] [--remote <addr>] [--auth-url <url>] [--metrics-port <port>] [--probe <addr>]... [--probe-mesh] [--mesh-status]");
|
||||
eprintln!();
|
||||
eprintln!("Options:");
|
||||
eprintln!(" -c, --config <path> Load config from TOML file (creates example if missing)");
|
||||
eprintln!(" -i, --identity <path> Identity file path (creates if missing, uses OsRng)");
|
||||
eprintln!(" --listen <addr> Listen address (default: 0.0.0.0:4433)");
|
||||
eprintln!(" --remote <addr> Remote relay for forwarding (disables room mode)");
|
||||
eprintln!(" --auth-url <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 <port> Prometheus metrics HTTP port (e.g., 9090). Disabled if not set.");
|
||||
eprintln!(" --probe <addr> 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 <name> Declare a room as global (bridged across federation). Repeatable.");
|
||||
eprintln!(" --debug-tap <room> Log packet headers for a room ('*' for all rooms).");
|
||||
eprintln!(" --ws-port <port> WebSocket listener port for browser clients (e.g., 8080).");
|
||||
eprintln!(" --static-dir <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;
|
||||
}
|
||||
CliResult { config, identity_path, config_file, config_needs_create }
|
||||
}
|
||||
|
||||
struct RelayStats {
|
||||
|
||||
Reference in New Issue
Block a user