lesavka: pace live keyboard reports and show build ids

This commit is contained in:
Brad Stein 2026-04-16 16:21:44 -03:00
parent 29944a5fd7
commit 4a88535960
6 changed files with 71 additions and 6 deletions

View File

@ -1,3 +1,28 @@
use std::process::Command;
fn main() { fn main() {
println!("cargo:rustc-check-cfg=cfg(coverage)"); println!("cargo:rustc-check-cfg=cfg(coverage)");
println!("cargo:rerun-if-changed=../.git/HEAD");
println!("cargo:rerun-if-changed=../.git/index");
println!(
"cargo:rustc-env=LESAVKA_GIT_SHA={}",
git_sha().unwrap_or_else(|| "nogit".to_string())
);
}
fn git_sha() -> Option<String> {
let output = Command::new("git")
.args(["-C", "..", "rev-parse", "--short", "HEAD"])
.output()
.ok()?;
if !output.status.success() {
return None;
}
let sha = String::from_utf8(output.stdout).ok()?;
let trimmed = sha.trim();
if trimmed.is_empty() {
None
} else {
Some(trimmed.to_string())
}
} }

View File

@ -147,7 +147,7 @@ pub fn build_launcher_view(
build_status_chip_with_light("Inputs", "Local"); build_status_chip_with_light("Inputs", "Local");
let (gpio_chip, gpio_light, gpio_value) = build_status_chip_with_light("GPIO", "Unknown"); let (gpio_chip, gpio_light, gpio_value) = build_status_chip_with_light("GPIO", "Unknown");
let (shortcut_chip, shortcut_value) = build_status_chip("Swap Key", "Pause"); let (shortcut_chip, shortcut_value) = build_status_chip("Swap Key", "Pause");
stabilize_chip(&relay_chip, 104); stabilize_chip(&relay_chip, 136);
stabilize_chip(&routing_chip, 84); stabilize_chip(&routing_chip, 84);
stabilize_chip(&gpio_chip, 84); stabilize_chip(&gpio_chip, 84);
stabilize_chip(&shortcut_chip, 88); stabilize_chip(&shortcut_chip, 88);

View File

@ -2,7 +2,7 @@
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
pub const VERSION: &str = env!("CARGO_PKG_VERSION"); pub const VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), "+", env!("LESAVKA_GIT_SHA"));
pub mod app; pub mod app;
mod app_support; mod app_support;

View File

@ -1,3 +1,28 @@
use std::process::Command;
fn main() { fn main() {
println!("cargo:rustc-check-cfg=cfg(coverage)"); println!("cargo:rustc-check-cfg=cfg(coverage)");
println!("cargo:rerun-if-changed=../.git/HEAD");
println!("cargo:rerun-if-changed=../.git/index");
println!(
"cargo:rustc-env=LESAVKA_GIT_SHA={}",
git_sha().unwrap_or_else(|| "nogit".to_string())
);
}
fn git_sha() -> Option<String> {
let output = Command::new("git")
.args(["-C", "..", "rev-parse", "--short", "HEAD"])
.output()
.ok()?;
if !output.status.success() {
return None;
}
let sha = String::from_utf8(output.stdout).ok()?;
let trimmed = sha.trim();
if trimmed.is_empty() {
None
} else {
Some(trimmed.to_string())
}
} }

View File

@ -1,6 +1,6 @@
// server/src/lib.rs // server/src/lib.rs
pub const VERSION: &str = env!("CARGO_PKG_VERSION"); pub const VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), "+", env!("LESAVKA_GIT_SHA"));
pub mod audio; pub mod audio;
pub mod camera; pub mod camera;

View File

@ -4,7 +4,7 @@
#[forbid(unsafe_code)] #[forbid(unsafe_code)]
use futures_util::{Stream, StreamExt}; use futures_util::{Stream, StreamExt};
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
use std::{backtrace::Backtrace, panic, pin::Pin, sync::Arc}; use std::{backtrace::Backtrace, panic, pin::Pin, sync::Arc, time::Duration};
use tokio::sync::Mutex; use tokio::sync::Mutex;
use tokio_stream::wrappers::ReceiverStream; use tokio_stream::wrappers::ReceiverStream;
use tonic::transport::Server; use tonic::transport::Server;
@ -25,7 +25,6 @@ use lesavka_server::{
}; };
/*──────────────── constants ────────────────*/ /*──────────────── constants ────────────────*/
const VERSION: &str = env!("CARGO_PKG_VERSION");
const PKG_NAME: &str = env!("CARGO_PKG_NAME"); const PKG_NAME: &str = env!("CARGO_PKG_NAME");
type VideoStream = Pin<Box<dyn Stream<Item = Result<VideoPacket, Status>> + Send>>; type VideoStream = Pin<Box<dyn Stream<Item = Result<VideoPacket, Status>> + Send>>;
@ -37,6 +36,14 @@ fn hid_endpoint(index: u8) -> String {
.unwrap_or_else(|_| format!("/dev/hidg{index}")) .unwrap_or_else(|_| format!("/dev/hidg{index}"))
} }
fn live_keyboard_report_delay() -> Duration {
std::env::var("LESAVKA_LIVE_KEYBOARD_REPORT_DELAY_MS")
.ok()
.and_then(|value| value.parse::<u64>().ok())
.map(Duration::from_millis)
.unwrap_or_else(|| Duration::from_millis(8))
}
/*──────────────── Handler ───────────────────*/ /*──────────────── Handler ───────────────────*/
struct Handler { struct Handler {
kb: Arc<Mutex<tokio::fs::File>>, kb: Arc<Mutex<tokio::fs::File>>,
@ -238,6 +245,7 @@ impl Relay for Handler {
let gadget = self.gadget.clone(); let gadget = self.gadget.clone();
let did_cycle = self.did_cycle.clone(); let did_cycle = self.did_cycle.clone();
let session_lease = self.capture_power.acquire_session().await; let session_lease = self.capture_power.acquire_session().await;
let report_delay = live_keyboard_report_delay();
tokio::spawn(async move { tokio::spawn(async move {
let _session_lease = session_lease; let _session_lease = session_lease;
@ -259,6 +267,9 @@ impl Relay for Handler {
} }
} }
tx.send(Ok(pkt)).await.ok(); tx.send(Ok(pkt)).await.ok();
if !report_delay.is_zero() {
tokio::time::sleep(report_delay).await;
}
} }
info!(rpc_id, "⌨️ stream_keyboard closed"); info!(rpc_id, "⌨️ stream_keyboard closed");
Ok::<(), Status>(()) Ok::<(), Status>(())
@ -451,12 +462,16 @@ impl Relay for Handler {
) -> Result<Response<Self::StreamKeyboardStream>, Status> { ) -> Result<Response<Self::StreamKeyboardStream>, Status> {
let (tx, rx) = tokio::sync::mpsc::channel(32); let (tx, rx) = tokio::sync::mpsc::channel(32);
let kb = self.kb.clone(); let kb = self.kb.clone();
let report_delay = live_keyboard_report_delay();
tokio::spawn(async move { tokio::spawn(async move {
let mut s = req.into_inner(); let mut s = req.into_inner();
while let Some(pkt) = s.next().await.transpose()? { while let Some(pkt) = s.next().await.transpose()? {
let _ = runtime_support::write_hid_report(&kb, &pkt.data).await; let _ = runtime_support::write_hid_report(&kb, &pkt.data).await;
tx.send(Ok(pkt)).await.ok(); tx.send(Ok(pkt)).await.ok();
if !report_delay.is_zero() {
tokio::time::sleep(report_delay).await;
}
} }
Ok::<(), Status>(()) Ok::<(), Status>(())
}); });
@ -545,7 +560,7 @@ impl Relay for Handler {
#[tokio::main(worker_threads = 4)] #[tokio::main(worker_threads = 4)]
async fn main() -> anyhow::Result<()> { async fn main() -> anyhow::Result<()> {
let _guard = init_tracing()?; let _guard = init_tracing()?;
info!("🚀 {} v{} starting up", PKG_NAME, VERSION); info!("🚀 {} v{} starting up", PKG_NAME, lesavka_server::VERSION);
panic::set_hook(Box::new(|p| { panic::set_hook(Box::new(|p| {
let bt = Backtrace::force_capture(); let bt = Backtrace::force_capture();