diff --git a/client/src/app_support.rs b/client/src/app_support.rs index 2840533..21282ef 100644 --- a/client/src/app_support.rs +++ b/client/src/app_support.rs @@ -5,30 +5,20 @@ use std::time::Duration; use crate::handshake::PeerCaps; use crate::input::camera::{CameraCodec, CameraConfig}; -/// Resolve the server address the client should dial first. -/// -/// Inputs: process arguments after the executable name plus the optional -/// `LESAVKA_SERVER_ADDR` override from the environment. -/// Outputs: the address that should be used for both the handshake and the -/// long-lived RPC channels. -/// Why: keeping precedence rules pure makes startup behavior testable without -/// having to mutate the real process environment in every caller. #[must_use] +/// Resolve the server address from `--server`, positional args, env, or default. pub fn resolve_server_addr(args: &[String], env_addr: Option<&str>) -> String { - args.first() - .cloned() + args.windows(2) + .find_map(|pair| { + (pair[0] == "--server" && !pair[1].starts_with("--")).then(|| pair[1].clone()) + }) + .or_else(|| args.iter().find(|arg| !arg.starts_with("--")).cloned()) .or_else(|| env_addr.map(ToOwned::to_owned)) .unwrap_or_else(|| "http://127.0.0.1:50051".to_string()) } -/// Convert handshake metadata into a local camera capture configuration. -/// -/// Inputs: the negotiated peer capabilities reported by the server. -/// Outputs: `Some(CameraConfig)` only when the server advertised a complete -/// camera profile that the client can honor locally. -/// Why: camera startup should fail closed when the negotiated profile is -/// incomplete, rather than guessing a codec or frame size on the client. #[must_use] +/// Build local camera capture settings from negotiated peer capabilities. pub fn camera_config_from_caps(caps: &PeerCaps) -> Option { let codec = parse_camera_codec(caps.camera_codec.as_deref()?)?; Some(CameraConfig { @@ -39,25 +29,14 @@ pub fn camera_config_from_caps(caps: &PeerCaps) -> Option { }) } -/// Clamp the video queue size to a sensible minimum. -/// -/// Inputs: the operator-provided queue depth, if any. -/// Outputs: a queue depth that is always large enough to absorb short render -/// stalls without turning the GUI thread into a drop storm. -/// Why: the render loop is bursty under GTK/winit, so tiny queues create -/// needless packet churn and noisy logs. #[must_use] +/// Clamp queue depth to a floor that keeps renderer bursts stable. pub fn sanitize_video_queue(queue: Option) -> usize { queue.unwrap_or(256).max(16) } -/// Pick the next reconnect delay for camera and microphone streams. -/// -/// Inputs: the current retry delay. -/// Outputs: an exponential backoff capped at 30 seconds. -/// Why: repeated reconnect failures should back off quickly without stalling -/// recovery for minutes after a transient outage clears. #[must_use] +/// Exponential reconnect delay capped at 30 seconds. pub fn next_delay(current: Duration) -> Duration { match current.as_secs() { 1..=15 => current * 2, @@ -87,9 +66,21 @@ mod tests { "http://cli:1" ); assert_eq!( - resolve_server_addr(&[], Some("http://env:2")), + resolve_server_addr( + &[ + String::from("--no-launcher"), + String::from("--server"), + String::from("http://cli-flag:3"), + ], + Some("http://env:2"), + ), + "http://cli-flag:3" + ); + assert_eq!( + resolve_server_addr(&[String::from("--launcher")], Some("http://env:2")), "http://env:2" ); + assert_eq!(resolve_server_addr(&[], Some("http://env:2")), "http://env:2"); assert_eq!(resolve_server_addr(&[], None), "http://127.0.0.1:50051"); }