impl LesavkaClientApp { /*──────────────── paste loop ───────────────*/ #[cfg(not(coverage))] fn paste_loop( ep: Channel, mut rx: mpsc::UnboundedReceiver, ) -> tokio::task::JoinHandle<()> { tokio::spawn(async move { let mut cli = RelayClient::new(ep.clone()); while let Some(text) = rx.recv().await { match paste::build_paste_request(&text) { Ok(req) => match cli.paste_text(Request::new(req)).await { Ok(resp) => { let reply = resp.get_ref(); if !reply.ok { warn!("📋 paste rejected: {}", reply.error); } else { debug!("📋 paste delivered"); } } Err(e) => { warn!("📋 paste failed: {e}"); cli = RelayClient::new(ep.clone()); } }, Err(e) => { warn!("📋 paste build failed: {e}"); } } } }) } /*──────────────── keyboard stream ───────────────*/ #[cfg(not(coverage))] async fn stream_loop_keyboard(&self, ep: Channel) { let mut delay = INPUT_RECONNECT_BASE_DELAY; loop { info!("⌨️🤙 Keyboard dial {}", self.server_addr); let mut cli = RelayClient::new(ep.clone()); let capture_enabled = Arc::clone(&self.remote_capture_enabled); let mut remote_capture_was_enabled = capture_enabled.load(Ordering::Relaxed); let outbound = BroadcastStream::new(self.kbd_tx.subscribe()).filter_map(move |report| { let remote_capture_enabled = capture_enabled.load(Ordering::Relaxed); keyboard_stream_report( report, remote_capture_enabled, &mut remote_capture_was_enabled, ) }); match cli.stream_keyboard(Request::new(outbound)).await { Ok(mut resp) => { delay = INPUT_RECONNECT_BASE_DELAY; while let Some(msg) = resp.get_mut().message().await.transpose() { if let Err(e) = msg { warn!("⌨️ server err: {e}"); break; } } } Err(e) => { warn!("❌⌨️ connect failed: {e}"); delay = app_support::next_delay(delay); } } tokio::time::sleep(delay).await; // retry } } /*──────────────── mouse stream ──────────────────*/ #[cfg(not(coverage))] async fn stream_loop_mouse(&self, ep: Channel) { let mut delay = INPUT_RECONNECT_BASE_DELAY; loop { info!("🖱️🤙 Mouse dial {}", self.server_addr); let mut cli = RelayClient::new(ep.clone()); let capture_enabled = Arc::clone(&self.remote_capture_enabled); let mut remote_capture_was_enabled = capture_enabled.load(Ordering::Relaxed); let outbound = BroadcastStream::new(self.mou_tx.subscribe()).filter_map(move |report| { let remote_capture_enabled = capture_enabled.load(Ordering::Relaxed); mouse_stream_report( report, remote_capture_enabled, &mut remote_capture_was_enabled, ) }); match cli.stream_mouse(Request::new(outbound)).await { Ok(mut resp) => { delay = INPUT_RECONNECT_BASE_DELAY; while let Some(msg) = resp.get_mut().message().await.transpose() { if let Err(e) = msg { warn!("🖱️ server err: {e}"); break; } } } Err(e) => { warn!("❌🖱️ connect failed: {e}"); delay = app_support::next_delay(delay); } } tokio::time::sleep(delay).await; } } } #[cfg(not(coverage))] const INPUT_RECONNECT_BASE_DELAY: Duration = Duration::from_millis(250);