fn main() -> Result<()> { let (dev, _cfg) = parse_args()?; let _ = load_interfaces(); let _ = UvcConfig::from_env(); let _ = open_with_retry(&dev)?; anyhow::bail!("coverage harness: control loop disabled"); } #[cfg(coverage)] fn parse_args() -> Result<(String, UvcConfig)> { let args: Vec = env::args().skip(1).collect(); let dev = parse_device_arg(&args) .or_else(|| env::var("LESAVKA_UVC_DEV").ok()) .context("missing --device (or LESAVKA_UVC_DEV)")?; Ok((dev, UvcConfig::from_env())) } #[cfg(coverage)] fn parse_device_arg(args: &[String]) -> Option { args .windows(2) .find_map(|pair| (pair[0] == "--device" || pair[0] == "-d").then(|| pair[1].clone())) .or_else(|| { args.iter() .rev() .find(|arg| { arg.as_str() != "--device" && arg.as_str() != "-d" && arg.starts_with('/') }) .cloned() }) } #[cfg(coverage)] impl UvcConfig { fn from_env() -> Self { let width = env_u32("LESAVKA_UVC_WIDTH", 1280); let height = env_u32("LESAVKA_UVC_HEIGHT", 720); let fps = env_u32("LESAVKA_UVC_FPS", 30).max(1); let frame_size = env_u32("LESAVKA_UVC_FRAME_SIZE", width * height * 2); let interval = env_u32("LESAVKA_UVC_INTERVAL", 0); let bulk = env::var("LESAVKA_UVC_BULK").is_ok(); let mut max_packet = env_u32("LESAVKA_UVC_MAXPACKET", 1024); if let Some(limit) = compute_payload_cap(bulk).map(|cap| cap.limit) { max_packet = max_packet.min(limit); } max_packet = if bulk { max_packet.min(512) } else { max_packet.min(1024) }; let interval = if interval == 0 { 10_000_000 / fps } else { interval }; Self { width, height, fps, interval, max_packet, frame_size, } } } #[cfg(coverage)] impl UvcState { fn new(cfg: UvcConfig) -> Self { let ctrl_len = stream_ctrl_len(); let default = build_streaming_control(&cfg, ctrl_len); Self { cfg, ctrl_len, default, probe: default, commit: default, cfg_snapshot: None, } } } #[cfg(coverage)] fn load_interfaces() -> UvcInterfaces { let control = env_u8("LESAVKA_UVC_CTRL_INTF").unwrap_or(UVC_STRING_CONTROL_IDX); let streaming = env_u8("LESAVKA_UVC_STREAM_INTF").unwrap_or(UVC_STRING_STREAMING_IDX); UvcInterfaces { control, streaming } } #[cfg(coverage)] fn read_interface(path: &str) -> Option { std::fs::read_to_string(path) .ok() .and_then(|v| v.trim().parse::().ok()) } #[cfg(coverage)] fn open_with_retry(path: &str) -> Result { let read_only = uvc_control_read_only(); let mut opts = OpenOptions::new(); opts.read(true); if !read_only { opts.write(true); } if env::var("LESAVKA_UVC_BLOCKING").is_err() { opts.custom_flags(libc::O_NONBLOCK); } opts.open(path).with_context(|| format!("open {path}")) } #[cfg(coverage)] /// Keep coverage-mode UVC control opens read-only unless a test opts into writes. fn uvc_control_read_only() -> bool { env::var("LESAVKA_UVC_CONTROL_READ_ONLY") .ok() .map(|value| { let trimmed = value.trim(); !(trimmed.eq_ignore_ascii_case("0") || trimmed.eq_ignore_ascii_case("false") || trimmed.eq_ignore_ascii_case("no") || trimmed.eq_ignore_ascii_case("off")) }) .unwrap_or(true) } #[cfg(coverage)] /// Returns the bounded UVC request-buffer count used by the helper. /// /// Inputs: `LESAVKA_UVC_BUFFER_COUNT`. Outputs: a value clamped to the safe /// range accepted by the helper. Why: coverage contracts need the same backlog /// bound as the real UVC binary without opening a gadget device. fn uvc_buffer_count() -> u32 { env_u32("LESAVKA_UVC_BUFFER_COUNT", DEFAULT_UVC_BUFFER_COUNT).clamp(1, 8) } #[cfg(coverage)] /// Returns the idle frame-pump sleep interval used when no fresh frame is ready. /// /// Inputs: `LESAVKA_UVC_IDLE_PUMP_MS`. Outputs: a duration in milliseconds. /// Why: this value controls how quickly the UVC helper retries the freshness /// spool when browsers are already streaming. fn uvc_idle_pump_sleep() -> std::time::Duration { std::time::Duration::from_millis(env_u64( "LESAVKA_UVC_IDLE_PUMP_MS", DEFAULT_UVC_IDLE_PUMP_MS, )) } #[cfg(coverage)] /// Returns the optional maximum age for a spooled MJPEG frame. /// /// Inputs: `LESAVKA_UVC_FRAME_MAX_AGE_MS`. Outputs: `None` when the TTL is /// disabled. Why: stale-frame replay must be explicit because it trades /// smoothness against freshness during browser stream recovery. fn frame_spool_max_age() -> Option { match env_u64( "LESAVKA_UVC_FRAME_MAX_AGE_MS", DEFAULT_UVC_FRAME_MAX_AGE_MS, ) { 0 => None, value => Some(std::time::Duration::from_millis(value)), } } #[cfg(coverage)] /// Determines whether a spooled MJPEG frame is too old to replay. /// /// Inputs: frame path and optional age limit. Outputs: true when the frame is /// missing or older than the limit. Why: the coverage harness should guard the /// same freshness cut-off that prevents seconds-old video from re-entering UVC. fn frame_spool_is_stale(path: &std::path::Path, max_age: Option) -> bool { let Some(max_age) = max_age else { return false; }; let Ok(metadata) = std::fs::metadata(path) else { return true; }; let Ok(modified) = metadata.modified() else { return false; }; std::time::SystemTime::now() .duration_since(modified) .map(|age| age > max_age) .unwrap_or(false) } #[cfg(coverage)] /// Parses an unsigned 64-bit environment value with a fallback. /// /// Inputs: variable name and default value. Outputs: parsed value or default. /// Why: UVC freshness settings use millisecond durations that should not be /// truncated to 32-bit just because the coverage harness is lightweight. fn env_u64(name: &str, default: u64) -> u64 { env::var(name) .ok() .and_then(|value| value.parse::().ok()) .unwrap_or(default) }