This commit is contained in:
Brad Stein 2025-06-17 20:54:31 -05:00
parent a56a3be347
commit f8ae813750
5 changed files with 191 additions and 293 deletions

View File

@ -1,16 +1,17 @@
// client/src/app.rs // client/src/app.rs
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
use anyhow::Result; use anyhow::Result;
use std::time::Duration; use std::time::Duration;
use tokio::{sync::broadcast, task::JoinHandle}; use tokio::{sync::broadcast, task::JoinHandle};
use tokio_stream::{wrappers::BroadcastStream, StreamExt}; use tokio_stream::{wrappers::BroadcastStream, StreamExt};
use tonic::Request; use tonic::Request;
use tracing::{info, warn, error, debug}; use tracing::{debug, error, info, warn};
use navka_common::navka::{relay_client::RelayClient, KeyboardReport, MouseReport,}; use navka_common::navka::{relay_client::RelayClient, KeyboardReport, MouseReport};
use input::inputs::InputAggregator;
use crate::input::inputs::InputAggregator;
pub struct NavkaClientApp { pub struct NavkaClientApp {
aggregator: Option<InputAggregator>, aggregator: Option<InputAggregator>,
@ -22,134 +23,105 @@ pub struct NavkaClientApp {
impl NavkaClientApp { impl NavkaClientApp {
pub fn new() -> Result<Self> { pub fn new() -> Result<Self> {
info!("Creating navka-client app!"); let dev_mode = std::env::var("NAVKA_DEV_MODE").is_ok();
let dev_mode = std::env::var("NAVKA_DEV_MODE").is_ok(); let server_addr = std::env::args()
let server = std::env::args()
.nth(1) .nth(1)
.or_else(|| std::env::var("NAVKA_SERVER_ADDR").ok()) .or_else(|| std::env::var("NAVKA_SERVER_ADDR").ok())
.unwrap_or_else(|| "http://127.0.0.1:50051".to_owned()); .unwrap_or_else(|| "http://127.0.0.1:50051".into());
let (kbd_tx, _) = broadcast::channel::<KeyboardReport>(1024); let (kbd_tx, _) = broadcast::channel::<KeyboardReport>(1024);
let (mou_tx, _) = broadcast::channel::<MouseReport>(4096); let (mou_tx, _) = broadcast::channel::<MouseReport>(4096);
let mut agg = InputAggregator::new(dev_mode, kbd_tx.clone(), mou_tx.clone());
agg.init()?;
Ok(Self { let mut agg = InputAggregator::new(dev_mode, kbd_tx.clone(), mou_tx.clone());
keyboard: Some(kbd_aggregator), agg.init()?; // grab devices
mouse: Some(mou_aggregator),
server_addr: addr, Ok(Self { aggregator: Some(agg),
dev_mode, server_addr, dev_mode,
tx, kbd_tx, mou_tx })
})
} }
pub async fn run(&mut self) -> Result<()> { pub async fn run(&mut self) -> Result<()> {
info!("Running navka-client app!"); /* detach the aggregator before spawn so `self` is not moved */
/* ─ spawn the input thread ─ */ let aggregator = self.aggregator.take().expect("InputAggregator present");
let agg_task: JoinHandle<Result<()>> = let agg_task = tokio::spawn(async move { aggregator.run().await });
tokio::spawn(async move { self.aggregator.take().unwrap().run().await });
/* ─ stream loops ─ */ /* two networking tasks */
let kbd_loop = self.stream_loop_keyboard(); let kbd_loop = self.stream_loop_keyboard();
let mou_loop = self.stream_loop_mouse(); let mou_loop = self.stream_loop_mouse();
/* ─ suicide timer for DEV mode ─ */ /* optional suicide timer */
let suicide_future = async { let suicide = async {
if self.dev_mode { if self.dev_mode {
info!("DEV-mode: will kill itself in 30s");
tokio::time::sleep(Duration::from_secs(30)).await; tokio::time::sleep(Duration::from_secs(30)).await;
Err::<(), _>(anyhow::anyhow!("dev-mode timer expired - 💀goodbye💀 cruel world...")) warn!("devmode timeout");
} else { std::process::exit(0);
futures::future::pending().await } else { futures::future::pending::<()>().await }
}
}; };
// Combine aggregator + dev + reconnect logic
tokio::select! { tokio::select! {
// aggregator finishes _ = kbd_loop => unreachable!(),
agg_res = aggregator_task => { _ = mou_loop => unreachable!(),
match agg_res { _ = suicide => unreachable!(),
Ok(Ok(())) => { // _ = suicide => { warn!("devmode timeout"); std::process::exit(0) },
error!("Aggregator ended normally, exiting."); r = agg_task => {
std::process::exit(0); error!("aggregator task ended: {r:?}");
} std::process::exit(1)
Ok(Err(e)) => {
error!("Aggregator ended with error: {e}");
std::process::exit(1);
}
Err(join_err) => {
error!("Aggregator task panicked or was cancelled: {join_err}");
std::process::exit(1);
}
}
},
// dev-mode
res = suicide_future => {
warn!("Dev-mode: {res:?}");
std::process::exit(0);
},
// reconnect loop
_ = self.reconnect_loop() => {
warn!("Reconnect loop ended??");
std::process::exit(0);
} }
} }
} }
/*──────────────── keyboard stream ───────────────*/
async fn stream_loop_keyboard(&self) {
loop {
info!("⌨️ connect {}", self.server_addr);
let mut cli = match RelayClient::connect(self.server_addr.clone()).await {
Ok(c) => c,
Err(e) => { error!("connect: {e}"); Self::delay().await; continue }
};
let outbound = BroadcastStream::new(self.kbd_tx.subscribe()).filter_map(|r| r.ok());
let resp = match cli.stream_keyboard(Request::new(outbound)).await {
Ok(r) => r, Err(e) => { error!("stream_keyboard: {e}"); Self::delay().await; continue }
};
let mut inbound = resp.into_inner();
while let Some(m) = inbound.message().await.transpose() {
match m {
Ok(r) => debug!("kbd echo {}B", r.data.len()),
Err(e) => { error!("kbd inbound: {e}"); break }
}
}
warn!("⌨️ disconnected");
Self::delay().await;
}
}
/*──────────────── mouse stream ──────────────────*/
async fn stream_loop_mouse(&self) {
loop {
info!("🖱️ connect {}", self.server_addr);
let mut cli = match RelayClient::connect(self.server_addr.clone()).await {
Ok(c) => c,
Err(e) => { error!("connect: {e}"); Self::delay().await; continue }
};
let outbound = BroadcastStream::new(self.mou_tx.subscribe()).filter_map(|r| r.ok());
let resp = match cli.stream_mouse(Request::new(outbound)).await {
Ok(r) => r, Err(e) => { error!("stream_mouse: {e}"); Self::delay().await; continue }
};
let mut inbound = resp.into_inner();
while let Some(m) = inbound.message().await.transpose() {
match m {
Ok(r) => debug!("mouse echo {}B", r.data.len()),
Err(e) => { error!("mouse inbound: {e}"); break }
}
}
warn!("🖱️ disconnected");
Self::delay().await;
}
}
#[inline(always)] #[inline(always)]
async fn delay() { tokio::time::sleep(Duration::from_secs(1)).await; } async fn delay() { tokio::time::sleep(Duration::from_secs(1)).await; }
/*──────────────────────────────── keyboard stream ─────────────────────────*/
async fn stream_loop_keyboard(&self) {
loop {
info!("⌨️ dial {}", self.server_addr);
let mut cli = match RelayClient::connect(self.server_addr.clone()).await {
Ok(c) => c, Err(e) => { error!("connect: {e}"); delay().await; continue }
};
let outbound = BroadcastStream::new(self.kbd_tx.subscribe())
.filter_map(|r| r.ok());
info!("⌨️ start stream_keyboard()");
let resp = match cli.stream_keyboard(Request::new(outbound)).await {
Ok(r) => r, Err(e) => { error!("stream_keyboard: {e}"); delay().await; continue }
};
let mut inbound = resp.into_inner();
while let Some(m) = inbound.message().await.transpose() {
match m {
Ok(r) => debug!("↩️ kbd echo {}B", r.data.len()),
Err(e) => { error!("kbd inbound: {e}"); break }
}
}
warn!("⌨️ disconnected, retry");
delay().await;
}
}
/*──────────────────────────────── mouse stream ────────────────────────────*/
async fn stream_loop_mouse(&self) {
loop {
info!("🖱️ dial {}", self.server_addr);
let mut cli = match RelayClient::connect(self.server_addr.clone()).await {
Ok(c) => c, Err(e) => { error!("connect: {e}"); delay().await; continue }
};
let outbound = BroadcastStream::new(self.mou_tx.subscribe())
.filter_map(|r| r.ok());
info!("🖱️ start stream_mouse()");
let resp = match cli.stream_mouse(Request::new(outbound)).await {
Ok(r) => r, Err(e) => { error!("stream_mouse: {e}"); delay().await; continue }
};
let mut inbound = resp.into_inner();
while let Some(m) = inbound.message().await.transpose() {
match m {
Ok(r) => debug!("↩️ mouse echo {}B", r.data.len()),
Err(e) => { error!("mouse inbound: {e}"); break }
}
}
warn!("🖱️ disconnected, retry");
delay().await;
}
}
} }

View File

@ -2,46 +2,31 @@
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
use evdev::{Device, EventType, KeyCode, RelativeAxisCode}; use evdev::{Device, EventType, KeyCode, RelativeAxisCode};
use tokio::time::{interval, Duration}; use tokio::{sync::broadcast::Sender, time::{interval, Duration}};
use tokio::sync::broadcast::Sender;
use tracing::{debug, info}; use tracing::{debug, info};
use navka_common::navka::HidReport; use navka_common::navka::{KeyboardReport, MouseReport};
use crate::input::keyboard::KeyboardAggregator; use super::{keyboard::KeyboardAggregator, mouse::MouseAggregator,
use crate::input::mouse::MouseAggregator; camera::CameraCapture, microphone::MicrophoneCapture};
use crate::input::camera::CameraCapture;
use crate::input::microphone::MicrophoneCapture;
/// A top-level aggregator that enumerates /dev/input/event*,
/// classifies them as keyboard vs. mouse vs. other,
/// spawns specialized aggregator objects, and can also
/// create stubs for camera/microphone logic if needed.
pub struct InputAggregator { pub struct InputAggregator {
kbd_tx: Sender<KeyboardReport>, kbd_tx: Sender<KeyboardReport>,
mou_tx: Sender<MouseReport>, mou_tx: Sender<MouseReport>,
pub dev_mode: bool, dev_mode: bool,
keyboards: Vec<KeyboardAggregator>, keyboards: Vec<KeyboardAggregator>,
mice: Vec<MouseAggregator>, mice: Vec<MouseAggregator>,
camera: Option<CameraCapture>, camera: Option<CameraCapture>,
mic: Option<MicrophoneCapture>, mic: Option<MicrophoneCapture>,
} }
impl InputAggregator { impl InputAggregator {
pub fn new( pub fn new(dev_mode: bool,
dev_mode: bool, kbd_tx: Sender<KeyboardReport>,
kbd_tx: Sender<KeyboardReport>, mou_tx: Sender<MouseReport>) -> Self {
mou_tx: Sender<MouseReport>, Self { kbd_tx, mou_tx, dev_mode,
) -> Self { keyboards: Vec::new(), mice: Vec::new(),
Self { camera: None, mic: None }
kbd_tx,
mou_tx,
dev_mode,
keyboards: Vec::new(),
mice: Vec::new(),
camera: None,
mic: None,
}
} }
/// Called once at startup: enumerates input devices, /// Called once at startup: enumerates input devices,
@ -89,7 +74,7 @@ impl InputAggregator {
dev.grab().with_context(|| format!("grabbing mouse {path:?}"))?; dev.grab().with_context(|| format!("grabbing mouse {path:?}"))?;
info!("Grabbed mouse {:?}", dev.name().unwrap_or("UNKNOWN")); info!("Grabbed mouse {:?}", dev.name().unwrap_or("UNKNOWN"));
// let mouse_agg = MouseAggregator::new(dev);np // let mouse_agg = MouseAggregator::new(dev);
let mouse_agg = MouseAggregator::new(dev, self.dev_mode, self.mou_tx.clone()); let mouse_agg = MouseAggregator::new(dev, self.dev_mode, self.mou_tx.clone());
self.mice.push(mouse_agg); self.mice.push(mouse_agg);
found_any = true; found_any = true;

View File

@ -1,18 +1,17 @@
// client/src/input/keyboard.rs // client/src/input/keyboard.rs
use std::collections::HashSet; use std::collections::HashSet;
use evdev::{Device, InputEvent, KeyCode, EventType}; use evdev::{Device, EventType, InputEvent, KeyCode};
use tokio::sync::broadcast::Sender; use tokio::sync::broadcast::Sender;
use tracing::{warn, error, info, debug}; use tracing::{debug, error, info, warn};
use navka_common::navka::KeyboardReport; use navka_common::navka::KeyboardReport;
use crate::input::keymap::{keycode_to_usage, is_modifier}; use super::keymap::{is_modifier, keycode_to_usage};
/// The aggregator logic for a single keyboard device.
pub struct KeyboardAggregator { pub struct KeyboardAggregator {
dev: Device, dev: Device,
tx: Sender<KeyboardReport>, tx: Sender<KeyboardReport>,
dev_mode: bool, dev_mode: bool,
pressed_keys: HashSet<KeyCode>, pressed_keys: HashSet<KeyCode>,
} }
@ -20,46 +19,39 @@ pub struct KeyboardAggregator {
impl KeyboardAggregator { impl KeyboardAggregator {
pub fn new(dev: Device, dev_mode: bool, tx: Sender<KeyboardReport>) -> Self { pub fn new(dev: Device, dev_mode: bool, tx: Sender<KeyboardReport>) -> Self {
let _ = dev.set_nonblocking(true); let _ = dev.set_nonblocking(true);
Self { Self { dev, tx, dev_mode, pressed_keys: HashSet::new() }
dev,
tx,
dev_mode,
pressed_keys: HashSet::new(),
}
} }
#[inline]
fn dev_log(&self, record: impl FnOnce()) {
if self.dev_mode {
record();
}
}
/// Called frequently (e.g. every ~10ms) to fetch + handle events
pub fn process_events(&mut self) { pub fn process_events(&mut self) {
let events: Vec<InputEvent> = match self.dev.fetch_events() { // --- first fetch, then log (avoids aliasing borrow) ---
let result = self.dev.fetch_events();
let events: Vec<InputEvent> = match result {
Ok(it) => it.collect(), Ok(it) => it.collect(),
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => return, Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => return,
Err(e) => { self.d(|| error!("read err: {e}")); return } Err(e) => { if self.dev_mode { error!("read error: {e}"); } return }
}; };
if self.dev_mode && !events.is_empty() { if self.dev_mode && !events.is_empty() {
self.d(|| info!("{} kbd evts from {}", events.len(), info!("{} kbd evts from {}", events.len(), self.dev.name().unwrap_or("?"));
self.dev.name().unwrap_or("???")));
} }
for ev in events { for ev in events {
if ev.event_type() != EventType::KEY { continue } if ev.event_type() != EventType::KEY { continue }
let code = KeyCode::new(ev.code()); let code = KeyCode::new(ev.code());
match ev.value() { match ev.value() {
1 => { self.pressed.insert(code); } // press 1 => { self.pressed_keys.insert(code); } // press
0 => { self.pressed.remove(&code); } // release 0 => { self.pressed_keys.remove(&code); } // release
_ => {} _ => {}
} }
let report = self.build_report(); let report = self.build_report();
self.d(|| debug!(?report, "kbd report")); if self.dev_mode { debug!(?rep, "kbd"); }
self.send_report(report); let _ = self.tx.send(KeyboardReport { data: report.to_vec() });
if self.magic() { warn!("🧙 magic chord, exiting 🪄 AVADA KEDAVRA!!! 💥💀"); std::process::exit(0) }
if self.is_magic() {
warn!("🧙 magic chord exiting 🪄 AVADA KEDAVRA!!! 💥💀");
std::process::exit(0);
}
} }
} }
@ -68,32 +60,19 @@ impl KeyboardAggregator {
let mut mods = 0u8; let mut mods = 0u8;
let mut keys = Vec::new(); let mut keys = Vec::new();
for &kc in &self.pressed { for &kc in &self.pressed_keys {
if let Some(m) = is_modifier(kc) { mods |= m } if let Some(m) = is_modifier(kc) { mods |= m }
else if let Some(u) = keycode_to_usage(kc) { keys.push(u) } else if let Some(u) = keycode_to_usage(kc) { keys.push(u) }
} }
out[0] = mods; out[0] = mods;
for (i, k) in keys.into_iter().take(6).enumerate() { out[2+i] = k } for (i, k) in keys.into_iter().take(6).enumerate() { out[2+i] = k }
out out
} }
fn send_report(&self, report: [u8; 8]) {
let msg = KeyboardReport { data: report.to_vec() }
match self.tx.send(msg.clone()) {
Ok(n) => {
self.dev_log(|| info!("📤 sent HID report → {n} subscriber(s)"));
}
Err(e) => {
self.dev_log(|| warn!("❌ send failed: {e}"));
let _ = self.tx.send(msg);
}
}
}
#[inline] #[inline]
fn magic(&self) -> bool { fn is_magic(&self) -> bool {
self.pressed.contains(&KeyCode::KEY_LEFTCTRL) self.pressed_keys.contains(&KeyCode::KEY_LEFTCTRL)
&& self.pressed.contains(&KeyCode::KEY_ESC) && self.pressed_keys.contains(&KeyCode::KEY_ESC)
} }
} }

View File

@ -1,22 +1,20 @@
// client/src/input/mouse.rs // client/src/input/mouse.rs
use anyhow::Result; use evdev::{Device, EventType, InputEvent, KeyCode, RelativeAxisCode};
use evdev::{Device, InputEvent, EventType, KeyCode, RelativeAxisCode};
use tokio::sync::broadcast::{self, Sender}; use tokio::sync::broadcast::{self, Sender};
use tracing::{debug, error, warn}; use tracing::{debug, error, warn};
use navka_common::navka::MouseReport; use navka_common::navka::MouseReport;
/// Aggregator for a single mouse device
pub struct MouseAggregator { pub struct MouseAggregator {
dev: Device, dev: Device,
tx: Sender<MouseReport>, tx: Sender<MouseReport>,
dev_mode: bool, dev_mode: bool,
buttons: u8, buttons: u8,
last_buttons: u8, last_buttons: u8,
dx: i8, dx: i8,
dy: i8, dy: i8,
wheel: i8, wheel: i8,
} }
@ -25,102 +23,65 @@ impl MouseAggregator {
Self { dev, tx, dev_mode, buttons:0, last_buttons:0, dx:0, dy:0, wheel:0 } Self { dev, tx, dev_mode, buttons:0, last_buttons:0, dx:0, dy:0, wheel:0 }
} }
#[inline] #[inline] fn slog(&self, f: impl FnOnce()) { if self.dev_mode { f() } }
fn dev_log(&self, record: impl FnOnce()) {
if self.dev_mode {
record();
}
}
#[inline]
fn set_btn(&mut self, bit: u8, val: i32) {
if val != 0 {
self.buttons |= 1 << bit;
} else {
self.buttons &= !(1 << bit);
}
}
pub fn process_events(&mut self) { pub fn process_events(&mut self) {
/* 1 ─ read a nonblocking batch */ let result = self.dev.fetch_events();
let events: Vec<InputEvent> = match self.dev.fetch_events() { let evts: Vec<InputEvent> = match result {
Ok(it) => it.collect(), Ok(it) => it.collect(),
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => return, Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => return,
Err(e) => { if self.dev_mode { error!("🖱️ read error: {e}"); } return; } Err(e) => { if self.dev_mode { error!("mouse read err: {e}"); } return }
}; };
if self.dev_mode && !events.is_empty() { if self.dev_mode && !evts.is_empty() {
self.dev_log(|| debug!("🖱️ {} events from {}", events.len(), debug!("🖱️ {} evts from {}", evts.len(), self.dev.name().unwrap_or("?"));
self.dev.name().unwrap_or("UNKNOWN")));
} }
/* 2 ─ aggregate */ for e in evts {
for ev in events { match e.event_type() {
match ev.event_type() { EventType::KEY => match e.code() {
/* ---------- buttons ---------- */ c if c == KeyCode::BTN_LEFT.0 => self.set_btn(0, e.value()),
EventType::KEY => match ev.code() { c if c == KeyCode::BTN_RIGHT.0 => self.set_btn(1, e.value()),
c if c == KeyCode::BTN_LEFT.0 => self.set_btn(0, ev.value()), c if c == KeyCode::BTN_MIDDLE.0 => self.set_btn(2, e.value()),
c if c == KeyCode::BTN_RIGHT.0 => self.set_btn(1, ev.value()),
c if c == KeyCode::BTN_MIDDLE.0 => self.set_btn(2, ev.value()),
_ => {} _ => {}
}, },
EventType::RELATIVE => match e.code() {
/* ----------- axes ------------ */ c if c == RelativeAxisCode::REL_X.0 =>
EventType::RELATIVE => match ev.code() { self.dx = self.dx.saturating_add(e.value().clamp(-127,127) as i8),
c if c == RelativeAxisCode::REL_X.0 => { c if c == RelativeAxisCode::REL_Y.0 =>
self.dx = self.dx.saturating_add(ev.value().clamp(-127, 127) as i8); self.dy = self.dy.saturating_add(e.value().clamp(-127,127) as i8),
} c if c == RelativeAxisCode::REL_WHEEL.0 =>
c if c == RelativeAxisCode::REL_Y.0 => { self.wheel = self.wheel.saturating_add(e.value().clamp(-1,1) as i8),
self.dy = self.dy.saturating_add(ev.value().clamp(-127, 127) as i8);
}
c if c == RelativeAxisCode::REL_WHEEL.0 => {
self.wheel = self.wheel.saturating_add(ev.value().clamp(-1, 1) as i8);
}
_ => {} _ => {}
}, },
EventType::SYNCHRONIZATION => self.flush(),
/* ---- batch delimiter -------- */
EventType::SYNCHRONIZATION => {
// Any sync event is fine we only care about boundaries
self.flush_report();
},
_ => {} _ => {}
} }
} }
} }
/// Build & send HID packet, then clear deltas fn flush(&mut self) {
fn flush_report(&mut self) { if self.dx==0 && self.dy==0 && self.wheel==0 && self.buttons==self.last_buttons {
/* Nothing changed ⇒ nothing to send */
if self.dx == 0
&& self.dy == 0
&& self.wheel == 0
&& self.buttons == self.last_buttons
{
return; return;
} }
let report = [ let pkt = [
self.buttons, self.buttons,
self.dx.clamp(-127, 127) as u8, self.dx.clamp(-127,127) as u8,
self.dy.clamp(-127, 127) as u8, self.dy.clamp(-127,127) as u8,
self.wheel as u8, self.wheel as u8,
]; ];
/* broadcast — this is nonblocking just like `try_send` on mpsc */ if let Err(broadcast::error::SendError(_)) =
if let Err(broadcast::error::SendError(_)) = self.tx.send(MouseReport { self.tx.send(MouseReport { data: pkt.to_vec() })
report.to_vec() { if self.dev_mode { warn!("❌ no HID receiver (mouse)"); } }
}) { else if self.dev_mode { debug!("📤 mouse {:?}", pkt) }
self.dev_log(|| warn!("❌ no HID receiver (mouse)"));
} else {
self.dev_log(|| debug!("📤 HID mouse {:?}", report));
}
/* reset deltas for next frame */ self.dx=0; self.dy=0; self.wheel=0; self.last_buttons=self.buttons;
self.dx = 0; }
self.dy = 0;
self.wheel = 0; #[inline] fn set_btn(&mut self, bit: u8, val: i32) {
self.last_buttons = self.buttons; if val!=0 { self.buttons |= 1<<bit } else { self.buttons &= !(1<<bit) }
} }
} }

View File

@ -12,13 +12,12 @@ use futures_util::FutureExt;
use navka_common::navka::{ use navka_common::navka::{
relay_server::{Relay, RelayServer}, relay_server::{Relay, RelayServer},
hid_report, KeyboardReport, MouseReport,
HidReport,
}; };
struct Handler { struct Handler {
kb: Arc<Mutex<File>>, kb: Arc<Mutex<tokio::fs::File>>,
ms: Arc<Mutex<File>>, ms: Arc<Mutex<tokio::fs::File>>,
} }
#[tonic::async_trait] #[tonic::async_trait]
@ -35,9 +34,9 @@ impl Relay for Handler {
tokio::spawn(async move { tokio::spawn(async move {
let mut s = req.into_inner(); let mut s = req.into_inner();
while let Some(r) = s.message().await.transpose()? { while let Some(pkt) = s.next().await.transpose()? {
kb.lock().await.write_all(&r.data).await?; kb.lock().await.write_all(&pkt.data).await?;
tx.send(Ok(r)).await.ok(); // best-effort echo tx.send(Ok(pkt)).await;//.ok(); // best-effort echo
} }
Ok::<(), Status>(()) Ok::<(), Status>(())
}); });
@ -54,9 +53,9 @@ impl Relay for Handler {
tokio::spawn(async move { tokio::spawn(async move {
let mut s = req.into_inner(); let mut s = req.into_inner();
while let Some(r) = s.message().await.transpose()? { while let Some(pkt) = s.next().await.transpose()? {
ms.lock().await.write_all(&r.data).await?; ms.lock().await.write_all(&pkt.data).await?;
tx.send(Ok(r)).await.ok(); tx.send(Ok(pkt)).await;//.ok();
} }
Ok::<(), Status>(()) Ok::<(), Status>(())
}); });
@ -69,31 +68,33 @@ impl Relay for Handler {
async fn main() -> anyhow::Result<()> { async fn main() -> anyhow::Result<()> {
fmt().with_env_filter( fmt().with_env_filter(
// honour RUST_LOG but fall back to very chatty defaults // honour RUST_LOG but fall back to very chatty defaults
EnvFilter::try_from_default_env().unwrap_or_else(|_| { EnvFilter::try_from_default_env().unwrap_or_else(|_| //{
EnvFilter::new( EnvFilter::new(
"navka_client=trace,\ // "navka_client=trace,\
navka_server=trace,\ // navka_server=trace,\
tonic=debug,\ // tonic=debug,\
h2=debug,\ // h2=debug,\
tower=debug", // tower=debug",
"navka_server=info"
) )
}), //}
),
) )
.with_target(true) // .with_target(true)
.with_thread_ids(true) // .with_thread_ids(true)
.with_file(true) // .with_file(true)
.init(); .init();
let kb = OpenOptions::new() let kb = OpenOptions::new()
.write(true) .write(true)
.read(true) // .read(true)
.custom_flags(libc::O_NONBLOCK) .custom_flags(libc::O_NONBLOCK)
.open("/dev/hidg0") .open("/dev/hidg0")
.await?; .await?;
let ms = OpenOptions::new() let ms = OpenOptions::new()
.write(true) .write(true)
.read(true) // .read(true)
.custom_flags(libc::O_NONBLOCK) .custom_flags(libc::O_NONBLOCK)
.open("/dev/hidg1") .open("/dev/hidg1")
.await?; .await?;