96 lines
3.4 KiB
Rust
96 lines
3.4 KiB
Rust
// Server binary for relay RPCs, HID/audio/video gadget IO, and capture leasing.
|
|
#[allow(clippy::useless_attribute)]
|
|
#[forbid(unsafe_code)]
|
|
use anyhow::Context;
|
|
use futures_util::{Stream, StreamExt};
|
|
use std::collections::HashMap;
|
|
use std::collections::HashSet;
|
|
use std::net::SocketAddr;
|
|
use std::os::unix::fs::FileTypeExt;
|
|
use std::process::Command;
|
|
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
|
use std::{backtrace::Backtrace, panic, pin::Pin, sync::Arc, time::Duration};
|
|
use tokio::sync::{Mutex, broadcast};
|
|
use tokio_stream::wrappers::ReceiverStream;
|
|
use tonic::transport::Server;
|
|
use tonic::{Request, Response, Status};
|
|
use tonic_reflection::server::Builder as ReflBuilder;
|
|
use tracing::{debug, error, info, warn};
|
|
|
|
use lesavka_common::lesavka::{
|
|
AudioPacket, CapturePowerCommand, CapturePowerState, Empty, KeyboardReport, MonitorRequest,
|
|
MouseReport, PasteReply, PasteRequest, ResetUsbReply, SetCapturePowerRequest, VideoPacket,
|
|
relay_server::{Relay, RelayServer},
|
|
};
|
|
|
|
use lesavka_server::{
|
|
camera, camera_runtime::CameraRuntime, capture_power::CapturePowerManager, gadget::UsbGadget,
|
|
handshake::HandshakeSvc, paste, runtime_support, runtime_support::init_tracing, uvc_runtime,
|
|
video,
|
|
};
|
|
|
|
/*──────────────── constants ────────────────*/
|
|
const PKG_NAME: &str = env!("CARGO_PKG_NAME");
|
|
|
|
type VideoStream = Pin<Box<dyn Stream<Item = Result<VideoPacket, Status>> + Send>>;
|
|
type AudioStream = Pin<Box<dyn Stream<Item = Result<AudioPacket, Status>> + Send>>;
|
|
|
|
fn hid_endpoint(index: u8) -> String {
|
|
std::env::var("LESAVKA_HID_DIR")
|
|
.map(|dir| format!("{dir}/hidg{index}"))
|
|
.unwrap_or_else(|_| format!("/dev/hidg{index}"))
|
|
}
|
|
|
|
fn live_keyboard_report_delay() -> Duration {
|
|
std::env::var("LESAVKA_LIVE_KEYBOARD_REPORT_DELAY_MS")
|
|
.ok()
|
|
.and_then(|value| value.parse::<u64>().ok())
|
|
.map(Duration::from_millis)
|
|
.unwrap_or_else(|| Duration::from_millis(8))
|
|
}
|
|
|
|
fn server_bind_addr() -> anyhow::Result<SocketAddr> {
|
|
// LESAVKA_SERVER_BIND_ADDR lets tests and constrained lab benches avoid
|
|
// colliding with another live relay while keeping the field default stable.
|
|
let raw =
|
|
std::env::var("LESAVKA_SERVER_BIND_ADDR").unwrap_or_else(|_| "0.0.0.0:50051".to_string());
|
|
raw.parse::<SocketAddr>()
|
|
.with_context(|| format!("parsing LESAVKA_SERVER_BIND_ADDR={raw:?}"))
|
|
}
|
|
|
|
/*──────────────── Handler ───────────────────*/
|
|
struct Handler {
|
|
kb: Arc<Mutex<Option<tokio::fs::File>>>,
|
|
ms: Arc<Mutex<Option<tokio::fs::File>>>,
|
|
gadget: UsbGadget,
|
|
did_cycle: Arc<AtomicBool>,
|
|
camera_rt: Arc<CameraRuntime>,
|
|
capture_power: CapturePowerManager,
|
|
eye_hubs: Arc<Mutex<HashMap<EyeHubKey, Arc<EyeHub>>>>,
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
|
struct EyeHubKey {
|
|
source_id: u32,
|
|
requested_width: u32,
|
|
requested_height: u32,
|
|
requested_fps: u32,
|
|
}
|
|
|
|
struct EyeHub {
|
|
tx: broadcast::Sender<VideoPacket>,
|
|
running: Arc<AtomicBool>,
|
|
subscribers: Arc<AtomicUsize>,
|
|
abort: tokio::task::AbortHandle,
|
|
}
|
|
|
|
include!("main/handler_startup.rs");
|
|
include!("main/eye_video.rs");
|
|
include!("main/rpc_helpers.rs");
|
|
|
|
include!("main/usb_recovery_helpers.rs");
|
|
include!("main/eye_hub.rs");
|
|
include!("main/relay_service.rs");
|
|
include!("main/relay_service_coverage.rs");
|
|
include!("main/entrypoint.rs");
|