lesavka/client/src/app.rs

77 lines
2.6 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use anyhow::{Context, Result};
use tokio::sync::mpsc;
use tokio::time::{timeout, Duration};
use tokio_stream::wrappers::ReceiverStream;
use tonic::Request;
use tracing::info;
use navka_common::navka::{relay_client::RelayClient, HidReport};
use crate::input::keyboard::KeyboardAggregator;
pub struct NavkaClientApp {
server_addr: String,
dev_mode: bool,
}
impl NavkaClientApp {
pub fn new() -> Result<Self> {
let dev_mode = std::env::var("NAVKA_DEV_MODE").is_ok();
let addr = std::env::args()
.nth(1)
.or_else(|| std::env::var("NAVKA_SERVER_ADDR").ok())
.unwrap_or_else(|| "http://127.0.0.1:50051".to_owned());
Ok(Self {
server_addr: addr,
dev_mode,
})
}
pub async fn run(&mut self) -> Result<()> {
// 1) Connect to navka-server
let mut client = RelayClient::connect(self.server_addr.clone())
.await
.with_context(|| format!("failed to connect to {}", self.server_addr))?;
// 2) Create a bidirectional streaming stub
let (tx, rx) = mpsc::channel::<HidReport>(32);
let outbound = ReceiverStream::new(rx);
let response = client.stream(Request::new(outbound)).await?;
let mut inbound = response.into_inner();
// 3) Start reading from all keyboards in a background task
let mut aggregator = KeyboardAggregator::new(tx.clone());
aggregator.init_devices()?; // discover & grab
let input_task = tokio::spawn(async move {
if let Err(e) = aggregator.run().await {
tracing::error!("KeyboardAggregator failed: {e}");
}
});
// 4) Add 30 second suicide for dev mode
if self.dev_mode {
// dev mode: we do a 30-second kill
info!("NAVKA_DEV_MODE: aggregator will time out in 30 seconds");
match timeout(Duration::from_secs(30), aggregator_task).await {
Ok(_) => {
info!("aggregator finished within 30s");
}
Err(_) => {
tracing::warn!("dev mode: aggregator didnt finish in 30s -> kill navka-client");
}
}
std::process::exit(0);
} else {
// normal mode: read aggregator forever
}
// 5) Inbound loop: we do something with reports from the server, e.g. logging:
while let Some(report) = inbound.message().await? {
tracing::info!(?report.data, "echo from server");
}
// 6) If inbound stream ends, stop the input task
input_task.abort();
Ok(())
}
}