lesavka/server/src/main.rs
2025-06-16 00:10:03 -05:00

116 lines
3.6 KiB
Rust
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. 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()? {
info!("📥 packet received");
match msg.kind {
Some(hid_report::Kind::KeyboardReport(ref v)) if v.len() == 8 => {
kb.lock().await.write_all(v).await?;
trace!(" └─ wrote 8B to /dev/hidg0");
}
Some(hid_report::Kind::MouseReport(ref v)) if v.len() == 4 => {
ms.lock().await.write_all(v).await?;
trace!(" └─ wrote 4B to /dev/hidg1");
}
_ => {
error!(?msg.kind, "⚠️ malformed packet");
let _bad_len = match &msg.kind {
Some(hid_report::Kind::KeyboardReport(v)) => v.len(),
Some(hid_report::Kind::MouseReport(v)) => v.len(),
_ => 0,
};
continue;
}
}
info!("HID report forwarded");
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(())
}