impl Handler { async fn paste_text_reply( &self, req: Request, ) -> Result, Status> { let req = req.into_inner(); let text = paste::decrypt(&req).map_err(|e| Status::unauthenticated(format!("{e}")))?; if let Err(e) = paste::type_text(&self.kb, &hid_endpoint(0), &text).await { return Ok(Response::new(PasteReply { ok: false, error: format!("{e}"), })); } Ok(Response::new(PasteReply { ok: true, error: String::new(), })) } async fn reset_usb_reply(&self) -> Result, Status> { #[cfg(not(coverage))] info!("🔴 explicit ResetUsb() called"); match self.gadget.recover_enumeration() { Ok(_) => { if let Err(e) = self.reopen_hid().await { #[cfg(not(coverage))] error!("💥 reopen HID failed: {e:#}"); return Err(Status::internal(e.to_string())); } if let Err(e) = restart_uvc_helper() { #[cfg(not(coverage))] error!("💥 restart UVC helper failed: {e:#}"); return Err(Status::internal(e.to_string())); } match current_controller_state_after_recovery() { Ok((ctrl, state)) if UsbGadget::host_enumerated_state(&state) => { #[cfg(not(coverage))] info!( "✅ USB host enumerated gadget after recovery ctrl={ctrl} state={state}" ); } Ok((ctrl, state)) => { let message = format!( "USB gadget recovery ran, but UDC {ctrl} is still {state}; the controlled host has not enumerated the relay HID/audio/video gadget" ); #[cfg(not(coverage))] warn!("⚠️ {message}"); return Err(Status::failed_precondition(message)); } Err(err) => { let message = format!( "USB gadget recovery ran, but the relay cannot read UDC state: {err:#}" ); #[cfg(not(coverage))] warn!("⚠️ {message}"); return Err(Status::failed_precondition(message)); } } Ok(Response::new(ResetUsbReply { ok: true })) } Err(e) => { #[cfg(not(coverage))] error!("💥 USB recovery failed: {e:#}"); let message = format!("{e:#}"); if message.contains("still not attached") || message.contains("not attached") { Err(Status::failed_precondition(message)) } else { Err(Status::internal(message)) } } } } async fn get_capture_power_reply(&self) -> Result, Status> { let state = self .capture_power .snapshot() .await .map_err(|e| Status::internal(format!("{e:#}")))?; Ok(Response::new( self.with_detected_capture_devices(state).await, )) } async fn set_capture_power_reply( &self, req: Request, ) -> Result, Status> { let req = req.into_inner(); let result = match CapturePowerCommand::try_from(req.command) .unwrap_or(CapturePowerCommand::Unspecified) { CapturePowerCommand::Auto => self.capture_power.set_auto().await, CapturePowerCommand::ForceOn => self.capture_power.set_manual(true).await, CapturePowerCommand::ForceOff => self.capture_power.set_manual(false).await, CapturePowerCommand::Unspecified => self.capture_power.set_manual(req.enabled).await, }; let state = result.map_err(|e| Status::internal(format!("{e:#}")))?; Ok(Response::new( self.with_detected_capture_devices(state).await, )) } async fn get_calibration_reply(&self) -> Result, Status> { Ok(Response::new(self.calibration.current())) } async fn calibrate_reply( &self, req: Request, ) -> Result, Status> { self.calibration .apply(req.into_inner()) .map(Response::new) .map_err(|e| Status::internal(format!("{e:#}"))) } }