121 lines
3.6 KiB
Rust

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<CapturePowerStatus> {
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<CapturePowerStatus> {
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<F, T>(future: F) -> Result<T>
where
F: std::future::Future<Output = Result<T>>,
{
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.context("building launcher power runtime")?
.block_on(future)
}
async fn connect(server_addr: &str) -> Result<RelayClient<Channel>> {
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,
}
}