From c65fcd11378c2f465fd65fb3d0163998b14e2310 Mon Sep 17 00:00:00 2001 From: Brad Stein Date: Tue, 21 Apr 2026 13:08:20 -0300 Subject: [PATCH] fix(server): survive unattached HID gadget startup --- client/Cargo.toml | 2 +- client/src/launcher/ui_components.rs | 29 +++-- common/Cargo.toml | 2 +- common/src/cli.rs | 2 +- server/Cargo.toml | 2 +- server/src/main.rs | 38 ++++-- server/src/paste.rs | 25 ++-- server/src/runtime_support.rs | 113 ++++++++++++++---- testing/tests/server_main_binary_contract.rs | 4 +- .../server_main_binary_extra_contract.rs | 8 +- testing/tests/server_main_rpc_contract.rs | 8 +- .../tests/server_runtime_smoke_contract.rs | 24 ++-- 12 files changed, 174 insertions(+), 83 deletions(-) diff --git a/client/Cargo.toml b/client/Cargo.toml index cae93ec..2ce98b4 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -4,7 +4,7 @@ path = "src/main.rs" [package] name = "lesavka_client" -version = "0.11.34" +version = "0.11.35" edition = "2024" [dependencies] diff --git a/client/src/launcher/ui_components.rs b/client/src/launcher/ui_components.rs index ada0a8c..fd6bfc6 100644 --- a/client/src/launcher/ui_components.rs +++ b/client/src/launcher/ui_components.rs @@ -182,7 +182,8 @@ pub fn build_launcher_view( let operations = gtk::Box::new(gtk::Orientation::Vertical, 8); operations.set_size_request(OPERATIONS_RAIL_WIDTH, -1); operations.set_hexpand(false); - operations.set_vexpand(true); + operations.set_vexpand(false); + operations.set_valign(gtk::Align::Start); content.append(&operations); let display_row = gtk::Box::new(gtk::Orientation::Horizontal, 8); @@ -320,14 +321,14 @@ pub fn build_launcher_view( let (preview_panel, preview_body) = build_panel("Device Testing"); preview_panel.set_hexpand(true); - preview_panel.set_vexpand(false); + preview_panel.set_vexpand(true); preview_panel.set_valign(gtk::Align::Fill); - preview_body.set_vexpand(false); + preview_body.set_vexpand(true); preview_body.set_spacing(8); let testing_row = gtk::Box::new(gtk::Orientation::Horizontal, 8); testing_row.set_hexpand(true); - testing_row.set_vexpand(false); - testing_row.set_valign(gtk::Align::Start); + testing_row.set_vexpand(true); + testing_row.set_valign(gtk::Align::Fill); let camera_preview = gtk::Picture::new(); camera_preview.set_can_shrink(false); camera_preview.set_hexpand(false); @@ -363,15 +364,15 @@ pub fn build_launcher_view( camera_preview_shell.append(&camera_preview_frame); let webcam_group = build_subgroup("Webcam Preview"); webcam_group.set_hexpand(true); - webcam_group.set_vexpand(false); - webcam_group.set_valign(gtk::Align::Start); + webcam_group.set_vexpand(true); + webcam_group.set_valign(gtk::Align::Fill); webcam_group.append(&camera_preview_shell); testing_row.append(&webcam_group); let playback_group = build_subgroup("Mic Playback"); playback_group.set_hexpand(false); - playback_group.set_vexpand(false); - playback_group.set_valign(gtk::Align::Start); + playback_group.set_vexpand(true); + playback_group.set_valign(gtk::Align::Fill); playback_group.set_size_request(72, -1); let playback_body = gtk::Box::new(gtk::Orientation::Vertical, 6); playback_body.set_halign(gtk::Align::Center); @@ -512,7 +513,8 @@ pub fn build_launcher_view( let diagnostics_scroll = gtk::ScrolledWindow::builder() .hexpand(true) .vexpand(false) - .min_content_height(190) + .min_content_height(150) + .max_content_height(150) .child(&diagnostics_shell) .build(); diagnostics_body.append(&diagnostics_toolbar); @@ -520,7 +522,7 @@ pub fn build_launcher_view( operations.append(&diagnostics_panel); let (console_panel, console_body) = build_panel("Session Console"); - console_panel.set_vexpand(true); + console_panel.set_vexpand(false); let console_toolbar = gtk::Box::new(gtk::Orientation::Horizontal, 8); console_toolbar.set_homogeneous(true); let console_copy_button = gtk::Button::with_label("Copy Log"); @@ -550,8 +552,9 @@ pub fn build_launcher_view( session_log_view.set_wrap_mode(gtk::WrapMode::WordChar); let log_scroll = gtk::ScrolledWindow::builder() .hexpand(true) - .vexpand(true) - .min_content_height(220) + .vexpand(false) + .min_content_height(150) + .max_content_height(150) .child(&session_log_view) .build(); console_body.append(&console_toolbar); diff --git a/common/Cargo.toml b/common/Cargo.toml index 4f687a1..fadb9f0 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lesavka_common" -version = "0.11.34" +version = "0.11.35" edition = "2024" build = "build.rs" diff --git a/common/src/cli.rs b/common/src/cli.rs index eac65c7..8a5724e 100644 --- a/common/src/cli.rs +++ b/common/src/cli.rs @@ -17,6 +17,6 @@ mod tests { #[test] fn banner_includes_version() { - assert_eq!(banner("0.11.34"), "lesavka-common CLI (v0.11.34)"); + assert_eq!(banner("0.11.35"), "lesavka-common CLI (v0.11.35)"); } } diff --git a/server/Cargo.toml b/server/Cargo.toml index 762aca7..dd32b10 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -10,7 +10,7 @@ bench = false [package] name = "lesavka_server" -version = "0.11.34" +version = "0.11.35" edition = "2024" autobins = false diff --git a/server/src/main.rs b/server/src/main.rs index c863ca8..b1cc90b 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -51,8 +51,8 @@ fn live_keyboard_report_delay() -> Duration { /*──────────────── Handler ───────────────────*/ struct Handler { - kb: Arc>, - ms: Arc>, + kb: Arc>>, + ms: Arc>>, gadget: UsbGadget, did_cycle: Arc, camera_rt: Arc, @@ -91,10 +91,16 @@ impl Handler { } info!("🛠️ opening HID endpoints …"); } - let kb = runtime_support::open_with_retry(&hid_endpoint(0)).await?; - let ms = runtime_support::open_with_retry(&hid_endpoint(1)).await?; + let kb_path = hid_endpoint(0); + let ms_path = hid_endpoint(1); + let kb = runtime_support::open_hid_if_ready(&kb_path).await?; + let ms = runtime_support::open_hid_if_ready(&ms_path).await?; #[cfg(not(coverage))] - info!("✅ HID endpoints ready"); + if kb.is_some() && ms.is_some() { + info!("✅ HID endpoints ready"); + } else { + warn!("⌛ HID endpoints are not ready; relay will keep running and open them lazily"); + } Ok(Self { kb: Arc::new(Mutex::new(kb)), @@ -108,8 +114,8 @@ impl Handler { } async fn reopen_hid(&self) -> anyhow::Result<()> { - let kb_new = runtime_support::open_with_retry(&hid_endpoint(0)).await?; - let ms_new = runtime_support::open_with_retry(&hid_endpoint(1)).await?; + let kb_new = runtime_support::open_hid_if_ready(&hid_endpoint(0)).await?; + let ms_new = runtime_support::open_hid_if_ready(&hid_endpoint(1)).await?; *self.kb.lock().await = kb_new; *self.ms.lock().await = ms_new; Ok(()) @@ -311,7 +317,7 @@ impl Handler { ) -> Result, Status> { let req = req.into_inner(); let text = paste::decrypt(&req).map_err(|e| Status::unauthenticated(format!("{e}")))?; - if let Err(e) = paste::type_text(self.kb.as_ref(), &text).await { + if let Err(e) = paste::type_text(&self.kb, &hid_endpoint(0), &text).await { return Ok(Response::new(PasteReply { ok: false, error: format!("{e}"), @@ -528,6 +534,8 @@ impl Relay for Handler { let (tx, rx) = tokio::sync::mpsc::channel(32); let kb = self.kb.clone(); let ms = self.ms.clone(); + let kb_path = hid_endpoint(0); + let ms_path = hid_endpoint(1); let gadget = self.gadget.clone(); let did_cycle = self.did_cycle.clone(); let session_lease = self.capture_power.acquire_session().await; @@ -537,7 +545,7 @@ impl Relay for Handler { let _session_lease = session_lease; let mut s = req.into_inner(); while let Some(pkt) = s.next().await.transpose()? { - if let Err(e) = runtime_support::write_hid_report(&kb, &pkt.data).await { + if let Err(e) = runtime_support::write_hid_report(&kb, &kb_path, &pkt.data).await { if e.raw_os_error() == Some(libc::EAGAIN) { debug!(rpc_id, "⌨️ write would block (dropped)"); } else { @@ -547,6 +555,8 @@ impl Relay for Handler { gadget.clone(), kb.clone(), ms.clone(), + kb_path.clone(), + ms_path.clone(), did_cycle.clone(), ) .await; @@ -573,6 +583,8 @@ impl Relay for Handler { let (tx, rx) = tokio::sync::mpsc::channel(1024); let ms = self.ms.clone(); let kb = self.kb.clone(); + let kb_path = hid_endpoint(0); + let ms_path = hid_endpoint(1); let gadget = self.gadget.clone(); let did_cycle = self.did_cycle.clone(); let session_lease = self.capture_power.acquire_session().await; @@ -581,7 +593,7 @@ impl Relay for Handler { let _session_lease = session_lease; let mut s = req.into_inner(); while let Some(pkt) = s.next().await.transpose()? { - if let Err(e) = runtime_support::write_hid_report(&ms, &pkt.data).await { + if let Err(e) = runtime_support::write_hid_report(&ms, &ms_path, &pkt.data).await { if e.raw_os_error() == Some(libc::EAGAIN) { debug!(rpc_id, "🖱️ write would block (dropped)"); } else { @@ -591,6 +603,8 @@ impl Relay for Handler { gadget.clone(), kb.clone(), ms.clone(), + kb_path.clone(), + ms_path.clone(), did_cycle.clone(), ) .await; @@ -753,7 +767,7 @@ impl Relay for Handler { tokio::spawn(async move { let mut s = req.into_inner(); 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, &hid_endpoint(0), &pkt.data).await; tx.send(Ok(pkt)).await.ok(); if !report_delay.is_zero() { tokio::time::sleep(report_delay).await; @@ -775,7 +789,7 @@ impl Relay for Handler { tokio::spawn(async move { let mut s = req.into_inner(); while let Some(pkt) = s.next().await.transpose()? { - let _ = runtime_support::write_hid_report(&ms, &pkt.data).await; + let _ = runtime_support::write_hid_report(&ms, &hid_endpoint(1), &pkt.data).await; tx.send(Ok(pkt)).await.ok(); } Ok::<(), Status>(()) diff --git a/server/src/paste.rs b/server/src/paste.rs index 0836b82..12878e1 100644 --- a/server/src/paste.rs +++ b/server/src/paste.rs @@ -4,11 +4,10 @@ use anyhow::{Context, Result}; use chacha20poly1305::aead::{Aead, KeyInit}; use chacha20poly1305::{ChaCha20Poly1305, Key, Nonce}; -use std::path::PathBuf; -use tokio::fs::File; -use tokio::io::AsyncWriteExt; +use std::{path::PathBuf, sync::Arc}; use tokio::sync::Mutex; +use crate::runtime_support; use lesavka_common::hid::{append_char_reports, char_to_usage}; use lesavka_common::lesavka::PasteRequest; use lesavka_common::paste::decode_shared_key; @@ -41,7 +40,11 @@ pub fn decrypt(req: &PasteRequest) -> Result { /// supported character up to the configured maximum. /// Why: paste injection must rate-limit itself so slower hosts do not drop /// HID reports under bursty clipboard loads. -pub async fn type_text(kb: &Mutex, text: &str) -> Result<()> { +pub async fn type_text( + kb: &Arc>>, + hid_path: &str, + text: &str, +) -> Result<()> { let max = std::env::var("LESAVKA_PASTE_MAX") .ok() .and_then(|v| v.parse::().ok()) @@ -59,12 +62,11 @@ pub async fn type_text(kb: &Mutex, text: &str) -> Result<()> { ); } - let mut kb = kb.lock().await; for c in text.chars().take(max) { let mut reports = Vec::with_capacity(4); if append_char_reports(&mut reports, c) { for report in reports { - kb.write_all(&report).await?; + runtime_support::write_hid_report(kb, hid_path, &report).await?; if delay_ms > 0 { tokio::time::sleep(delay).await; } @@ -128,6 +130,7 @@ mod tests { use chacha20poly1305::{ChaCha20Poly1305, Key, Nonce}; use lesavka_common::lesavka::PasteRequest; use serial_test::serial; + use std::sync::Arc; use temp_env::with_var; use tempfile::tempdir; use tokio::fs::{File, OpenOptions}; @@ -183,8 +186,10 @@ mod tests { .open(&path) .await .expect("open temp file"); - let kb = Mutex::new(file); - type_text(&kb, "A!?").await.expect("type text"); + let kb = Arc::new(Mutex::new(Some(file))); + type_text(&kb, path.to_str().unwrap(), "A!?") + .await + .expect("type text"); let mut bytes = Vec::new(); let mut file = File::open(&path).await.expect("reopen temp file"); @@ -218,8 +223,8 @@ mod tests { .open(&path) .await .expect("open temp file"); - let kb = Mutex::new(file); - let err = type_text(&kb, "pw🙂") + let kb = Arc::new(Mutex::new(Some(file))); + let err = type_text(&kb, path.to_str().unwrap(), "pw🙂") .await .expect_err("unsupported char should fail"); assert!(err.to_string().contains("unsupported character")); diff --git a/server/src/runtime_support.rs b/server/src/runtime_support.rs index ffb2b26..a8555dc 100644 --- a/server/src/runtime_support.rs +++ b/server/src/runtime_support.rs @@ -66,10 +66,7 @@ pub fn init_tracing() -> anyhow::Result { /// must wait for readiness instead of failing the whole process immediately. #[cfg(coverage)] pub async fn open_with_retry(path: &str) -> anyhow::Result { - OpenOptions::new() - .write(true) - .custom_flags(libc::O_NONBLOCK) - .open(path) + open_hid_file(path) .await .with_context(|| format!("opening {path}")) } @@ -77,18 +74,16 @@ pub async fn open_with_retry(path: &str) -> anyhow::Result { #[cfg(not(coverage))] pub async fn open_with_retry(path: &str) -> anyhow::Result { for attempt in 1..=200 { - match OpenOptions::new() - .write(true) - .custom_flags(libc::O_NONBLOCK) - .open(path) - .await - { + match open_hid_file(path).await { Ok(file) => { info!("✅ {path} opened on attempt #{attempt}"); return Ok(file); } - Err(error) if error.raw_os_error() == Some(libc::EBUSY) => { - trace!("⏳ {path} busy… retry #{attempt}"); + Err(error) + if hid_endpoint_open_is_temporarily_unavailable(error.raw_os_error()) + || error.raw_os_error() == Some(libc::EBUSY) => + { + trace!("⏳ {path} unavailable ({error})… retry #{attempt}"); tokio::time::sleep(Duration::from_millis(50)).await; } Err(error) => return Err(error).with_context(|| format!("opening {path}")), @@ -98,6 +93,36 @@ pub async fn open_with_retry(path: &str) -> anyhow::Result { Err(anyhow::anyhow!("timeout waiting for {path}")) } +async fn open_hid_file(path: &str) -> std::io::Result { + OpenOptions::new() + .write(true) + .custom_flags(libc::O_NONBLOCK) + .open(path) + .await +} + +pub async fn open_hid_if_ready(path: &str) -> anyhow::Result> { + match open_hid_file(path).await { + Ok(file) => { + info!("✅ {path} opened"); + Ok(Some(file)) + } + Err(error) if hid_endpoint_open_is_temporarily_unavailable(error.raw_os_error()) => { + warn!("⌛ {path} is not ready yet ({error}); relay will retry lazily"); + Ok(None) + } + Err(error) => Err(error).with_context(|| format!("opening {path}")), + } +} + +#[must_use] +pub fn hid_endpoint_open_is_temporarily_unavailable(code: Option) -> bool { + matches!( + code, + Some(libc::ENOENT) | Some(libc::ENODEV) | Some(libc::ENXIO) + ) +} + /// Check whether gadget auto-recovery is enabled. /// /// Inputs: none. @@ -120,7 +145,7 @@ pub fn should_recover_hid_error(code: Option) -> bool { matches!( code, Some(libc::ENOTCONN) | Some(libc::ESHUTDOWN) | Some(libc::EPIPE) - ) + ) || hid_endpoint_open_is_temporarily_unavailable(code) } /// Recover the HID endpoints after a transport failure. @@ -134,8 +159,10 @@ pub fn should_recover_hid_error(code: Option) -> bool { pub async fn recover_hid_if_needed( err: &std::io::Error, gadget: UsbGadget, - kb: Arc>, - ms: Arc>, + kb: Arc>>, + ms: Arc>>, + _kb_path: String, + _ms_path: String, did_cycle: Arc, ) { let code = err.raw_os_error(); @@ -166,8 +193,10 @@ pub async fn recover_hid_if_needed( pub async fn recover_hid_if_needed( err: &std::io::Error, gadget: UsbGadget, - kb: Arc>, - ms: Arc>, + kb: Arc>>, + ms: Arc>>, + kb_path: String, + ms_path: String, did_cycle: Arc, ) { let code = err.raw_os_error(); @@ -198,8 +227,8 @@ pub async fn recover_hid_if_needed( } if let Err(error) = async { - let kb_new = open_with_retry("/dev/hidg0").await?; - let ms_new = open_with_retry("/dev/hidg1").await?; + let kb_new = open_hid_if_ready(&kb_path).await?; + let ms_new = open_hid_if_ready(&ms_path).await?; *kb.lock().await = kb_new; *ms.lock().await = ms_new; Ok::<(), anyhow::Error>(()) @@ -496,16 +525,28 @@ pub fn next_stream_id() -> u64 { /// stalls without blocking the stream task indefinitely. #[cfg(coverage)] pub async fn write_hid_report( - dev: &Arc>, + dev: &Arc>>, + path: &str, data: &[u8], ) -> std::io::Result<()> { let mut file = dev.lock().await; - file.write_all(data).await + if file.is_none() { + *file = Some(open_hid_file(path).await?); + } + if let Some(file) = file.as_mut() { + file.write_all(data).await + } else { + Err(std::io::Error::new( + std::io::ErrorKind::NotConnected, + "HID endpoint is not open", + )) + } } #[cfg(not(coverage))] pub async fn write_hid_report( - dev: &Arc>, + dev: &Arc>>, + path: &str, data: &[u8], ) -> std::io::Result<()> { let attempts = std::env::var("LESAVKA_HID_WRITE_RETRIES") @@ -521,7 +562,22 @@ pub async fn write_hid_report( let mut last_error: Option = None; for attempt in 0..attempts { let mut file = dev.lock().await; - match file.write_all(data).await { + if file.is_none() { + match open_hid_file(path).await { + Ok(opened) => { + info!("✅ {path} opened lazily"); + *file = Some(opened); + } + Err(error) => return Err(error), + } + } + let Some(file_handle) = file.as_mut() else { + return Err(std::io::Error::new( + std::io::ErrorKind::NotConnected, + "HID endpoint is not open", + )); + }; + match file_handle.write_all(data).await { Ok(()) => return Ok(()), Err(error) if error.kind() == std::io::ErrorKind::WouldBlock @@ -529,7 +585,12 @@ pub async fn write_hid_report( { last_error = Some(error); } - Err(error) => return Err(error), + Err(error) => { + if should_recover_hid_error(error.raw_os_error()) { + *file = None; + } + return Err(error); + } } drop(file); tokio::time::sleep(Duration::from_millis((attempt as u64 + 1) * base_delay_ms)).await; @@ -661,9 +722,9 @@ mod tests { .open(tmp.path()) .await .expect("open temp file"); - let shared = Arc::new(Mutex::new(file)); + let shared = Arc::new(Mutex::new(Some(file))); - write_hid_report(&shared, &[1, 2, 3, 4]) + write_hid_report(&shared, tmp.path().to_str().unwrap(), &[1, 2, 3, 4]) .await .expect("write succeeds"); diff --git a/testing/tests/server_main_binary_contract.rs b/testing/tests/server_main_binary_contract.rs index 085553a..6fc1262 100644 --- a/testing/tests/server_main_binary_contract.rs +++ b/testing/tests/server_main_binary_contract.rs @@ -44,8 +44,8 @@ mod server_main_binary { ( dir, Handler { - kb: std::sync::Arc::new(tokio::sync::Mutex::new(kb)), - ms: std::sync::Arc::new(tokio::sync::Mutex::new(ms)), + kb: std::sync::Arc::new(tokio::sync::Mutex::new(Some(kb))), + ms: std::sync::Arc::new(tokio::sync::Mutex::new(Some(ms))), gadget: UsbGadget::new("lesavka"), did_cycle: std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)), camera_rt: std::sync::Arc::new(CameraRuntime::new()), diff --git a/testing/tests/server_main_binary_extra_contract.rs b/testing/tests/server_main_binary_extra_contract.rs index c10d54c..c385717 100644 --- a/testing/tests/server_main_binary_extra_contract.rs +++ b/testing/tests/server_main_binary_extra_contract.rs @@ -86,8 +86,8 @@ mod server_main_binary_extra { ( dir, Handler { - kb: std::sync::Arc::new(tokio::sync::Mutex::new(kb)), - ms: std::sync::Arc::new(tokio::sync::Mutex::new(ms)), + kb: std::sync::Arc::new(tokio::sync::Mutex::new(Some(kb))), + ms: std::sync::Arc::new(tokio::sync::Mutex::new(Some(ms))), gadget: UsbGadget::new("lesavka"), did_cycle: std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)), camera_rt: std::sync::Arc::new(CameraRuntime::new()), @@ -455,8 +455,8 @@ mod server_main_binary_extra { .expect("open hidg1"), ); let handler = Handler { - kb: std::sync::Arc::new(tokio::sync::Mutex::new(kb)), - ms: std::sync::Arc::new(tokio::sync::Mutex::new(ms)), + kb: std::sync::Arc::new(tokio::sync::Mutex::new(Some(kb))), + ms: std::sync::Arc::new(tokio::sync::Mutex::new(Some(ms))), gadget: UsbGadget::new("lesavka"), did_cycle: std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)), camera_rt: std::sync::Arc::new(CameraRuntime::new()), diff --git a/testing/tests/server_main_rpc_contract.rs b/testing/tests/server_main_rpc_contract.rs index 965b14a..735983a 100644 --- a/testing/tests/server_main_rpc_contract.rs +++ b/testing/tests/server_main_rpc_contract.rs @@ -45,8 +45,8 @@ mod server_main_rpc { ( dir, Handler { - kb: std::sync::Arc::new(tokio::sync::Mutex::new(kb)), - ms: std::sync::Arc::new(tokio::sync::Mutex::new(ms)), + kb: std::sync::Arc::new(tokio::sync::Mutex::new(Some(kb))), + ms: std::sync::Arc::new(tokio::sync::Mutex::new(Some(ms))), gadget: UsbGadget::new("lesavka"), did_cycle: std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)), camera_rt: std::sync::Arc::new(CameraRuntime::new()), @@ -399,8 +399,8 @@ mod server_main_rpc { Some(dir.path().join("cfg").to_string_lossy().to_string()), || { let handler = Handler { - kb: std::sync::Arc::new(tokio::sync::Mutex::new(kb)), - ms: std::sync::Arc::new(tokio::sync::Mutex::new(ms)), + kb: std::sync::Arc::new(tokio::sync::Mutex::new(Some(kb))), + ms: std::sync::Arc::new(tokio::sync::Mutex::new(Some(ms))), gadget: UsbGadget::new("lesavka"), did_cycle: std::sync::Arc::new(std::sync::atomic::AtomicBool::new( false, diff --git a/testing/tests/server_runtime_smoke_contract.rs b/testing/tests/server_runtime_smoke_contract.rs index e45823d..53e1ea1 100644 --- a/testing/tests/server_runtime_smoke_contract.rs +++ b/testing/tests/server_runtime_smoke_contract.rs @@ -187,8 +187,8 @@ fn runtime_recover_hid_ignores_non_transport_errors() { .await .expect("open temp ms"); - let kb = Arc::new(Mutex::new(kb)); - let ms = Arc::new(Mutex::new(ms)); + let kb = Arc::new(Mutex::new(Some(kb))); + let ms = Arc::new(Mutex::new(Some(ms))); let did_cycle = Arc::new(AtomicBool::new(false)); let err = std::io::Error::from_raw_os_error(libc::EAGAIN); @@ -197,6 +197,8 @@ fn runtime_recover_hid_ignores_non_transport_errors() { UsbGadget::new("lesavka"), kb, ms, + kb_tmp.path().to_string_lossy().to_string(), + ms_tmp.path().to_string_lossy().to_string(), did_cycle.clone(), ) .await; @@ -227,8 +229,8 @@ fn runtime_recover_hid_short_circuits_when_cycle_already_in_progress() { .await .expect("open temp ms"); - let kb = Arc::new(Mutex::new(kb)); - let ms = Arc::new(Mutex::new(ms)); + let kb = Arc::new(Mutex::new(Some(kb))); + let ms = Arc::new(Mutex::new(Some(ms))); let did_cycle = Arc::new(AtomicBool::new(true)); let err = std::io::Error::from_raw_os_error(libc::EPIPE); @@ -237,6 +239,8 @@ fn runtime_recover_hid_short_circuits_when_cycle_already_in_progress() { UsbGadget::new("lesavka"), kb, ms, + kb_tmp.path().to_string_lossy().to_string(), + ms_tmp.path().to_string_lossy().to_string(), did_cycle.clone(), ) .await; @@ -268,8 +272,8 @@ fn runtime_recover_hid_resets_cycle_flag_after_async_recovery_path() { .await .expect("open temp ms"); - let kb = Arc::new(Mutex::new(kb)); - let ms = Arc::new(Mutex::new(ms)); + let kb = Arc::new(Mutex::new(Some(kb))); + let ms = Arc::new(Mutex::new(Some(ms))); let did_cycle = Arc::new(AtomicBool::new(false)); let err = std::io::Error::from_raw_os_error(libc::EPIPE); @@ -278,6 +282,8 @@ fn runtime_recover_hid_resets_cycle_flag_after_async_recovery_path() { UsbGadget::new("lesavka"), kb.clone(), ms.clone(), + kb_tmp.path().to_string_lossy().to_string(), + ms_tmp.path().to_string_lossy().to_string(), did_cycle.clone(), ) .await; @@ -316,8 +322,8 @@ fn runtime_recover_hid_attempts_cycle_when_enabled() { .await .expect("open temp ms"); - let kb = Arc::new(Mutex::new(kb)); - let ms = Arc::new(Mutex::new(ms)); + let kb = Arc::new(Mutex::new(Some(kb))); + let ms = Arc::new(Mutex::new(Some(ms))); let did_cycle = Arc::new(AtomicBool::new(false)); let err = std::io::Error::from_raw_os_error(libc::EPIPE); @@ -326,6 +332,8 @@ fn runtime_recover_hid_attempts_cycle_when_enabled() { UsbGadget::new("lesavka"), kb.clone(), ms.clone(), + kb_tmp.path().to_string_lossy().to_string(), + ms_tmp.path().to_string_lossy().to_string(), did_cycle.clone(), ) .await;