From 3c1f647b047dac7c4b9799db13d95323e711686f Mon Sep 17 00:00:00 2001 From: Brad Stein Date: Tue, 6 Jan 2026 11:48:36 -0300 Subject: [PATCH] server: supervise uvc helper --- server/src/main.rs | 78 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 24 deletions(-) diff --git a/server/src/main.rs b/server/src/main.rs index 8d384bb..89d3bcd 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -7,8 +7,8 @@ use futures_util::{Stream, StreamExt}; use gstreamer as gst; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; -use std::{backtrace::Backtrace, panic, pin::Pin, process::Command, sync::Arc}; -use tokio::{fs::OpenOptions, io::AsyncWriteExt, sync::Mutex}; +use std::{backtrace::Backtrace, panic, pin::Pin, sync::Arc}; +use tokio::{fs::OpenOptions, io::AsyncWriteExt, process::Command, sync::Mutex}; use tokio_stream::wrappers::ReceiverStream; use tonic::transport::Server; use tonic::{Request, Response, Status}; @@ -164,9 +164,12 @@ fn pick_uvc_device() -> anyhow::Result { )) } -fn spawn_uvc_control(uvc_dev: &str) -> anyhow::Result { - let bin = std::env::var("LESAVKA_UVC_CTRL_BIN") - .unwrap_or_else(|_| "/usr/local/bin/lesavka-uvc".to_string()); +fn uvc_ctrl_bin() -> String { + std::env::var("LESAVKA_UVC_CTRL_BIN") + .unwrap_or_else(|_| "/usr/local/bin/lesavka-uvc".to_string()) +} + +fn spawn_uvc_control(bin: &str, uvc_dev: &str) -> anyhow::Result { Command::new(bin) .arg("--device") .arg(uvc_dev) @@ -174,6 +177,48 @@ fn spawn_uvc_control(uvc_dev: &str) -> anyhow::Result { .context("spawning lesavka-uvc") } +async fn supervise_uvc_control(bin: String) { + let mut waiting_logged = false; + loop { + let uvc_dev = match pick_uvc_device() { + Ok(dev) => { + if waiting_logged { + info!(%dev, "📷 UVC device discovered"); + waiting_logged = false; + } + dev + } + Err(e) => { + if !waiting_logged { + warn!("⚠️ UVC device not ready: {e:#}"); + waiting_logged = true; + } + tokio::time::sleep(Duration::from_secs(2)).await; + continue; + } + }; + + match spawn_uvc_control(&bin, &uvc_dev) { + Ok(mut child) => { + info!(%uvc_dev, "📷 UVC control helper started"); + match child.wait().await { + Ok(status) => { + warn!(%uvc_dev, "⚠️ lesavka-uvc exited: {status}"); + } + Err(e) => { + warn!(%uvc_dev, "⚠️ lesavka-uvc wait failed: {e:#}"); + } + } + } + Err(e) => { + warn!(%uvc_dev, "⚠️ failed to start lesavka-uvc: {e:#}"); + } + } + + tokio::time::sleep(Duration::from_secs(2)).await; + } +} + /*──────────────── Handler ───────────────────*/ struct Handler { kb: Arc>, @@ -401,27 +446,12 @@ async fn main() -> anyhow::Result<()> { })); let gadget = UsbGadget::new("lesavka"); - let _uvc_ctrl = if std::env::var("LESAVKA_DISABLE_UVC").is_err() { - match pick_uvc_device() { - Ok(uvc_dev) => match spawn_uvc_control(&uvc_dev) { - Ok(child) => { - info!(%uvc_dev, "📷 UVC control helper started"); - Some(child) - } - Err(e) => { - warn!("⚠️ failed to start lesavka-uvc: {e:#}"); - None - } - }, - Err(e) => { - warn!("⚠️ UVC device not ready: {e:#}"); - None - } - } + if std::env::var("LESAVKA_DISABLE_UVC").is_err() { + let bin = uvc_ctrl_bin(); + tokio::spawn(supervise_uvc_control(bin)); } else { info!("📷 UVC disabled (LESAVKA_DISABLE_UVC set)"); - None - }; + } let handler = Handler::new(gadget.clone()).await?; info!("🌐 lesavka-server listening on 0.0.0.0:50051");