server: supervise uvc helper

This commit is contained in:
Brad Stein 2026-01-06 11:48:36 -03:00
parent f1aaa1743d
commit 3c1f647b04

View File

@ -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<String> {
))
}
fn spawn_uvc_control(uvc_dev: &str) -> anyhow::Result<std::process::Child> {
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<tokio::process::Child> {
Command::new(bin)
.arg("--device")
.arg(uvc_dev)
@ -174,6 +177,48 @@ fn spawn_uvc_control(uvc_dev: &str) -> anyhow::Result<std::process::Child> {
.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<Mutex<tokio::fs::File>>,
@ -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");