use anyhow::{Context, Result}; use lesavka_common::lesavka::{ CapturePowerCommand, Empty, SetCapturePowerRequest, relay_client::RelayClient, }; use tonic::{Request, transport::Channel}; use super::state::CapturePowerStatus; use crate::relay_transport; pub fn fetch_capture_power(server_addr: &str) -> Result { with_runtime(async move { let mut client = connect(server_addr).await?; let reply = client .get_capture_power(Request::new(Empty {})) .await .context("querying capture power state")? .into_inner(); Ok(map_state(reply)) }) } pub fn set_capture_power_mode( server_addr: &str, command: CapturePowerCommand, ) -> Result { with_runtime(async move { let mut client = connect(server_addr).await?; let reply = client .set_capture_power(Request::new(SetCapturePowerRequest { enabled: matches!(command, CapturePowerCommand::ForceOn), command: command as i32, })) .await .context("setting capture power state")? .into_inner(); Ok(map_state(reply)) }) } pub fn recover_usb_soft(server_addr: &str) -> Result<()> { run_recovery(server_addr, RecoveryKind::Usb) } pub fn recover_uac_soft(server_addr: &str) -> Result<()> { run_recovery(server_addr, RecoveryKind::Uac) } pub fn recover_uvc_soft(server_addr: &str) -> Result<()> { run_recovery(server_addr, RecoveryKind::Uvc) } #[derive(Clone, Copy)] enum RecoveryKind { Usb, Uac, Uvc, } fn run_recovery(server_addr: &str, kind: RecoveryKind) -> Result<()> { with_runtime(async move { let mut client = connect(server_addr).await?; let request = Request::new(Empty {}); let response = match kind { RecoveryKind::Usb => client .recover_usb(request) .await .context("requesting soft USB recovery")?, RecoveryKind::Uac => client .recover_uac(request) .await .context("requesting soft UAC recovery")?, RecoveryKind::Uvc => client .recover_uvc(request) .await .context("requesting soft UVC recovery")?, }; let reply = response.into_inner(); if reply.ok { Ok(()) } else { match kind { RecoveryKind::Usb => anyhow::bail!("relay reported soft USB recovery failure"), RecoveryKind::Uac => anyhow::bail!("relay reported soft UAC recovery failure"), RecoveryKind::Uvc => anyhow::bail!("relay reported soft UVC recovery failure"), } } }) } fn with_runtime(future: F) -> Result where F: std::future::Future>, { tokio::runtime::Builder::new_current_thread() .enable_all() .build() .context("building launcher power runtime")? .block_on(future) } async fn connect(server_addr: &str) -> Result> { let channel = relay_transport::endpoint(server_addr)? .tcp_nodelay(true) .connect() .await .context("connecting launcher to relay host")?; Ok(RelayClient::new(channel)) } fn map_state(reply: lesavka_common::lesavka::CapturePowerState) -> CapturePowerStatus { CapturePowerStatus { available: reply.available, enabled: reply.enabled, unit: reply.unit, detail: reply.detail, active_leases: reply.active_leases, mode: reply.mode, detected_devices: reply.detected_devices, } }