2026-04-19 03:28:23 -03:00
|
|
|
use anyhow::{Context, Result, bail};
|
|
|
|
|
use lesavka_common::lesavka::{
|
|
|
|
|
CapturePowerCommand, Empty, SetCapturePowerRequest, relay_client::RelayClient,
|
|
|
|
|
};
|
|
|
|
|
use tonic::{Request, transport::Channel};
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
|
|
|
enum CommandKind {
|
|
|
|
|
Status,
|
|
|
|
|
Auto,
|
|
|
|
|
On,
|
|
|
|
|
Off,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl CommandKind {
|
|
|
|
|
fn parse(value: &str) -> Option<Self> {
|
|
|
|
|
match value {
|
|
|
|
|
"status" | "get" => Some(Self::Status),
|
|
|
|
|
"auto" => Some(Self::Auto),
|
|
|
|
|
"on" | "force-on" => Some(Self::On),
|
|
|
|
|
"off" | "force-off" => Some(Self::Off),
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct Config {
|
|
|
|
|
server: String,
|
|
|
|
|
command: CommandKind,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn usage() -> &'static str {
|
|
|
|
|
"Usage: lesavka-relayctl [--server http://HOST:50051] <status|auto|on|off>"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parse_args() -> Result<Config> {
|
|
|
|
|
let mut args = std::env::args().skip(1);
|
|
|
|
|
let mut server = "http://127.0.0.1:50051".to_string();
|
|
|
|
|
let mut command = None;
|
|
|
|
|
|
|
|
|
|
while let Some(arg) = args.next() {
|
|
|
|
|
match arg.as_str() {
|
|
|
|
|
"--server" => {
|
|
|
|
|
server = args
|
|
|
|
|
.next()
|
|
|
|
|
.context("missing value after --server")?
|
|
|
|
|
.trim()
|
|
|
|
|
.to_string();
|
|
|
|
|
}
|
|
|
|
|
"--help" | "-h" => {
|
|
|
|
|
println!("{}", usage());
|
|
|
|
|
std::process::exit(0);
|
|
|
|
|
}
|
|
|
|
|
_ if command.is_none() => {
|
|
|
|
|
command = CommandKind::parse(arg.as_str());
|
|
|
|
|
if command.is_none() {
|
|
|
|
|
bail!("unknown command `{arg}`\n{}", usage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => bail!("unexpected argument `{arg}`\n{}", usage()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(Config {
|
|
|
|
|
server,
|
|
|
|
|
command: command.unwrap_or(CommandKind::Status),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn connect(server_addr: &str) -> Result<RelayClient<Channel>> {
|
|
|
|
|
let channel = Channel::from_shared(server_addr.to_string())
|
|
|
|
|
.context("invalid relay server address")?
|
|
|
|
|
.tcp_nodelay(true)
|
|
|
|
|
.connect()
|
|
|
|
|
.await
|
|
|
|
|
.with_context(|| format!("connecting to relay at {server_addr}"))?;
|
|
|
|
|
Ok(RelayClient::new(channel))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn print_state(state: lesavka_common::lesavka::CapturePowerState) {
|
|
|
|
|
println!("available={}", state.available);
|
|
|
|
|
println!("enabled={}", state.enabled);
|
|
|
|
|
println!("mode={}", state.mode);
|
2026-04-20 01:41:57 -03:00
|
|
|
println!("detected_devices={}", state.detected_devices);
|
2026-04-19 03:28:23 -03:00
|
|
|
println!("active_leases={}", state.active_leases);
|
|
|
|
|
println!("unit={}", state.unit);
|
|
|
|
|
println!("detail={}", state.detail);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::main(flavor = "current_thread")]
|
|
|
|
|
async fn main() -> Result<()> {
|
|
|
|
|
let config = parse_args()?;
|
|
|
|
|
let mut client = connect(config.server.as_str()).await?;
|
|
|
|
|
|
|
|
|
|
let reply = match config.command {
|
|
|
|
|
CommandKind::Status => client
|
|
|
|
|
.get_capture_power(Request::new(Empty {}))
|
|
|
|
|
.await
|
|
|
|
|
.context("querying capture power state")?
|
|
|
|
|
.into_inner(),
|
|
|
|
|
CommandKind::Auto => client
|
|
|
|
|
.set_capture_power(Request::new(SetCapturePowerRequest {
|
|
|
|
|
enabled: false,
|
|
|
|
|
command: CapturePowerCommand::Auto as i32,
|
|
|
|
|
}))
|
|
|
|
|
.await
|
|
|
|
|
.context("setting capture power to auto")?
|
|
|
|
|
.into_inner(),
|
|
|
|
|
CommandKind::On => client
|
|
|
|
|
.set_capture_power(Request::new(SetCapturePowerRequest {
|
|
|
|
|
enabled: true,
|
|
|
|
|
command: CapturePowerCommand::ForceOn as i32,
|
|
|
|
|
}))
|
|
|
|
|
.await
|
|
|
|
|
.context("forcing capture power on")?
|
|
|
|
|
.into_inner(),
|
|
|
|
|
CommandKind::Off => client
|
|
|
|
|
.set_capture_power(Request::new(SetCapturePowerRequest {
|
|
|
|
|
enabled: false,
|
|
|
|
|
command: CapturePowerCommand::ForceOff as i32,
|
|
|
|
|
}))
|
|
|
|
|
.await
|
|
|
|
|
.context("forcing capture power off")?
|
|
|
|
|
.into_inner(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
print_state(reply);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|