196 lines
6.4 KiB
Rust
196 lines
6.4 KiB
Rust
use super::super::{clipboard::send_clipboard_text_to_remote, power::reset_usb_gadget};
|
|
use futures::stream;
|
|
use lesavka_common::lesavka::{
|
|
AudioPacket, CalibrationRequest, CalibrationState, CapturePowerState, Empty, KeyboardReport,
|
|
MonitorRequest, MouseReport, PasteReply, PasteRequest, ResetUsbReply, SetCapturePowerRequest,
|
|
VideoPacket,
|
|
relay_server::{Relay, RelayServer},
|
|
};
|
|
use serial_test::serial;
|
|
use std::{
|
|
pin::Pin,
|
|
sync::{Arc, Mutex},
|
|
time::Duration,
|
|
};
|
|
use tonic::{Request, Response, Status};
|
|
|
|
type KeyboardStream = Pin<Box<dyn futures::Stream<Item = Result<KeyboardReport, Status>> + Send>>;
|
|
type MouseStream = Pin<Box<dyn futures::Stream<Item = Result<MouseReport, Status>> + Send>>;
|
|
type VideoStream = Pin<Box<dyn futures::Stream<Item = Result<VideoPacket, Status>> + Send>>;
|
|
type AudioStream = Pin<Box<dyn futures::Stream<Item = Result<AudioPacket, Status>> + Send>>;
|
|
type EmptyStream = Pin<Box<dyn futures::Stream<Item = Result<Empty, Status>> + Send>>;
|
|
|
|
#[derive(Clone)]
|
|
struct UtilityRelay {
|
|
paste_count: Arc<Mutex<usize>>,
|
|
reset_count: Arc<Mutex<usize>>,
|
|
reset_ok: bool,
|
|
}
|
|
|
|
impl UtilityRelay {
|
|
fn new(reset_ok: bool) -> Self {
|
|
Self {
|
|
paste_count: Arc::new(Mutex::new(0)),
|
|
reset_count: Arc::new(Mutex::new(0)),
|
|
reset_ok,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[tonic::async_trait]
|
|
impl Relay for UtilityRelay {
|
|
type StreamKeyboardStream = KeyboardStream;
|
|
type StreamMouseStream = MouseStream;
|
|
type CaptureVideoStream = VideoStream;
|
|
type CaptureAudioStream = AudioStream;
|
|
type StreamMicrophoneStream = EmptyStream;
|
|
type StreamCameraStream = EmptyStream;
|
|
|
|
async fn stream_keyboard(
|
|
&self,
|
|
_request: Request<tonic::Streaming<KeyboardReport>>,
|
|
) -> Result<Response<Self::StreamKeyboardStream>, Status> {
|
|
Ok(Response::new(Box::pin(stream::empty())))
|
|
}
|
|
|
|
async fn stream_mouse(
|
|
&self,
|
|
_request: Request<tonic::Streaming<MouseReport>>,
|
|
) -> Result<Response<Self::StreamMouseStream>, Status> {
|
|
Ok(Response::new(Box::pin(stream::empty())))
|
|
}
|
|
|
|
async fn capture_video(
|
|
&self,
|
|
_request: Request<MonitorRequest>,
|
|
) -> Result<Response<Self::CaptureVideoStream>, Status> {
|
|
Ok(Response::new(Box::pin(stream::empty())))
|
|
}
|
|
|
|
async fn capture_audio(
|
|
&self,
|
|
_request: Request<MonitorRequest>,
|
|
) -> Result<Response<Self::CaptureAudioStream>, Status> {
|
|
Ok(Response::new(Box::pin(stream::empty())))
|
|
}
|
|
|
|
async fn stream_microphone(
|
|
&self,
|
|
_request: Request<tonic::Streaming<AudioPacket>>,
|
|
) -> Result<Response<Self::StreamMicrophoneStream>, Status> {
|
|
Ok(Response::new(Box::pin(stream::empty())))
|
|
}
|
|
|
|
async fn stream_camera(
|
|
&self,
|
|
_request: Request<tonic::Streaming<VideoPacket>>,
|
|
) -> Result<Response<Self::StreamCameraStream>, Status> {
|
|
Ok(Response::new(Box::pin(stream::empty())))
|
|
}
|
|
|
|
async fn paste_text(
|
|
&self,
|
|
_request: Request<PasteRequest>,
|
|
) -> Result<Response<PasteReply>, Status> {
|
|
*self.paste_count.lock().expect("paste count") += 1;
|
|
Ok(Response::new(PasteReply {
|
|
ok: true,
|
|
error: String::new(),
|
|
}))
|
|
}
|
|
|
|
async fn reset_usb(&self, _request: Request<Empty>) -> Result<Response<ResetUsbReply>, Status> {
|
|
*self.reset_count.lock().expect("reset count") += 1;
|
|
Ok(Response::new(ResetUsbReply { ok: self.reset_ok }))
|
|
}
|
|
|
|
async fn get_capture_power(
|
|
&self,
|
|
_request: Request<Empty>,
|
|
) -> Result<Response<CapturePowerState>, Status> {
|
|
Ok(Response::new(CapturePowerState::default()))
|
|
}
|
|
|
|
async fn set_capture_power(
|
|
&self,
|
|
_request: Request<SetCapturePowerRequest>,
|
|
) -> Result<Response<CapturePowerState>, Status> {
|
|
Ok(Response::new(CapturePowerState::default()))
|
|
}
|
|
|
|
async fn get_calibration(
|
|
&self,
|
|
_request: Request<Empty>,
|
|
) -> Result<Response<CalibrationState>, Status> {
|
|
Ok(Response::new(CalibrationState::default()))
|
|
}
|
|
|
|
async fn calibrate(
|
|
&self,
|
|
_request: Request<CalibrationRequest>,
|
|
) -> Result<Response<CalibrationState>, Status> {
|
|
Ok(Response::new(CalibrationState::default()))
|
|
}
|
|
}
|
|
|
|
fn serve(relay: UtilityRelay) -> (tokio::runtime::Runtime, String) {
|
|
let rt = tokio::runtime::Runtime::new().expect("runtime");
|
|
let addr = rt.block_on(async {
|
|
let listener = std::net::TcpListener::bind("127.0.0.1:0").expect("bind relay");
|
|
let addr = listener.local_addr().expect("relay addr");
|
|
drop(listener);
|
|
tokio::spawn(async move {
|
|
let _ = tonic::transport::Server::builder()
|
|
.add_service(RelayServer::new(relay))
|
|
.serve(addr)
|
|
.await;
|
|
});
|
|
addr
|
|
});
|
|
std::thread::sleep(Duration::from_millis(50));
|
|
(rt, format!("http://{addr}"))
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn clipboard_action_delivers_text_over_rpc_when_key_is_available() {
|
|
temp_env::with_vars(
|
|
[
|
|
(
|
|
"LESAVKA_PASTE_KEY",
|
|
Some("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"),
|
|
),
|
|
("LESAVKA_PASTE_KEY_FILE", None::<&str>),
|
|
("LESAVKA_CLIPBOARD_TIMEOUT_MS", Some("1500")),
|
|
],
|
|
|| {
|
|
let relay = UtilityRelay::new(true);
|
|
let paste_count = Arc::clone(&relay.paste_count);
|
|
let (_rt, addr) = serve(relay);
|
|
|
|
let result =
|
|
send_clipboard_text_to_remote(&addr, "hello from launcher").expect("clipboard RPC");
|
|
|
|
assert_eq!(result, "Clipboard delivered to remote");
|
|
assert_eq!(*paste_count.lock().expect("paste count"), 1);
|
|
},
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn recover_usb_action_reports_relay_success_and_failure() {
|
|
let relay = UtilityRelay::new(true);
|
|
let reset_count = Arc::clone(&relay.reset_count);
|
|
let (_rt, addr) = serve(relay);
|
|
reset_usb_gadget(&addr).expect("successful reset");
|
|
assert_eq!(*reset_count.lock().expect("reset count"), 1);
|
|
|
|
let relay = UtilityRelay::new(false);
|
|
let reset_count = Arc::clone(&relay.reset_count);
|
|
let (_rt, addr) = serve(relay);
|
|
let err = reset_usb_gadget(&addr).expect_err("reset failure");
|
|
assert!(format!("{err:#}").contains("relay reported USB reset failure"));
|
|
assert_eq!(*reset_count.lock().expect("reset count"), 1);
|
|
}
|