lesavka/server/src/main.rs
2025-06-16 18:11:14 -05:00

134 lines
4.4 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.

//! navka-server — receive HidReport and write to /dev/hidg0
// main.rs
#![forbid(unsafe_code)]
use std::{pin::Pin, sync::Arc};
use tokio::{fs::{File, OpenOptions}, io::AsyncWriteExt, sync::Mutex};
use tokio_stream::{wrappers::ReceiverStream, Stream, StreamExt};
use tonic::{transport::Server, Request, Response, Status};
use tracing::{error, info, trace};
use tracing_subscriber::{fmt, EnvFilter};
use navka_common::navka::{
relay_server::{Relay, RelayServer},
hid_report,
HidReport,
};
struct Handler {
kb: Arc<Mutex<File>>,
ms: Arc<Mutex<File>>,
}
#[tonic::async_trait]
impl Relay for Handler {
type StreamStream =
Pin<Box<dyn Stream<Item = Result<HidReport, Status>> + Send + 'static>>;
async fn stream(
&self,
request: Request<tonic::Streaming<HidReport>>,
) -> Result<Response<Self::StreamStream>, Status> {
info!("▶️ new client stream from {:?}", request.remote_addr());
let mut in_stream = request.into_inner();
let kb = self.kb.clone();
let ms = self.ms.clone();
let (tx, rx) = tokio::sync::mpsc::channel(32);
tokio::spawn(async move {
while let Some(msg) = in_stream.next().await.transpose()? {
match msg.kind {
/* ───── KEYBOARD ───── */
Some(hid_report::Kind::KeyboardReport(ref v)) if v.len() == 8 => {
match kb.lock().await.write_all(v).await {
Ok(_) => info!("⌨️ → /dev/hidg0 (8 B)"),
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
trace!("⌨️ /dev/hidg0 busy, dropped packet");
continue;
}
Err(e) => {
error!("⌨️ write error: {e}");
continue;
}
}
}
/* ───── MOUSE ───── */
Some(hid_report::Kind::MouseReport(ref v)) if v.len() == 4 => {
match ms.lock().await.write_all(v).await {
Ok(_) => info!("🖱️ → /dev/hidg1 (4 B)"),
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
trace!("🖱️ /dev/hidg1 busy, dropped packet");
continue;
}
Err(e) => {
error!("🖱️ write error: {e}");
continue;
}
}
}
/* ───── bad / unknown ───── */
_ => {
error!(?msg.kind, "⚠️ malformed packet");
continue;
}
}
// echo back so the client knows were alive
let _ = tx.send(Ok(msg)).await;
}
info!("🔚 client stream closed");
Ok::<_, Status>(())
});
Ok(Response::new(Box::pin(ReceiverStream::new(rx))))
}
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
fmt().with_env_filter(
// honour RUST_LOG but fall back to very chatty defaults
EnvFilter::try_from_default_env().unwrap_or_else(|_| {
EnvFilter::new(
"navka_client=trace,\
navka_server=trace,\
tonic=debug,\
h2=debug,\
tower=debug",
)
}),
)
.with_target(true)
.with_thread_ids(true)
.with_file(true)
.init();
let kb = OpenOptions::new()
.write(true)
.read(true)
.custom_flags(libc::O_NONBLOCK)
.open("/dev/hidg0")
.await?;
let ms = OpenOptions::new()
.write(true)
.read(true)
.custom_flags(libc::O_NONBLOCK)
.open("/dev/hidg1")
.await?;
let handler = Handler {
kb: Arc::new(Mutex::new(kb)),
ms: Arc::new(Mutex::new(ms)),
};
println!("🌐 navka-server listening on 0.0.0.0:50051");
Server::builder()
.add_service(RelayServer::new(handler))
.serve(([0, 0, 0, 0], 50051).into())
.await?;
Ok(())
}