//! 通用协议与帧封装:控制消息(bincode + 长度前缀)与视频帧格式。 use anyhow::Result; use serde::{Deserialize, Serialize}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; /// 控制通道消息(双向) #[derive(Debug, Clone, Serialize, Deserialize)] pub enum ControlMsg { /// 主控端认证(临时验证码,MVP 明文走 QUIC-TLS 加密通道) Auth { code: String }, AuthOk { width: u32, height: u32 }, AuthFail(String), KeyFrameReq, Ping(u64), /// t=主控端发送时刻(主控时钟),agent_ts=被控端收到时刻(被控时钟) /// 两者配合可估计时钟偏移,进而用帧头 ts_ms 计算端到端延迟 /// lost/sent = agent 发送方向(视频下行)的 QUIC 丢包/发包累计计数(conn.stats().path) Pong { t: u64, agent_ts: u64, lost: u64, sent: u64 }, Input(InputEvent), } #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum MouseButton { Left, Right, Middle, } /// 输入事件。鼠标坐标为虚拟桌面归一化 0..=65535; /// 按键为 Set-1 扫描码,extended 标记扩展键(方向键/Home 等,需要 EXTENDEDKEY 标志)。 #[derive(Debug, Clone, Copy, Serialize, Deserialize)] pub enum InputEvent { MouseMove { x: u16, y: u16 }, MouseDown(MouseButton), MouseUp(MouseButton), Wheel { dy: i32 }, KeyDown { scancode: u16, extended: bool }, KeyUp { scancode: u16, extended: bool }, } /// 视频帧头(载荷为 LZ4 压缩的 BGRA 像素,按行紧凑排列) #[derive(Debug, Clone, Serialize, Deserialize)] pub struct VideoFrameHeader { pub width: u32, pub height: u32, pub ts_ms: u64, } async fn read_u32le(r: &mut R) -> Result { let mut b = [0u8; 4]; r.read_exact(&mut b).await?; Ok(u32::from_le_bytes(b)) } /// 编码一条控制消息为「长度前缀 + bincode」 pub fn encode_control(msg: &ControlMsg) -> Vec { let body = bincode::serialize(msg).expect("serialize control"); let mut out = Vec::with_capacity(body.len() + 4); out.extend_from_slice(&(body.len() as u32).to_le_bytes()); out.extend_from_slice(&body); out } pub async fn write_control( w: &mut W, msg: &ControlMsg, ) -> Result<()> { w.write_all(&encode_control(msg)).await?; Ok(()) } pub async fn read_control(r: &mut R) -> Result { let len = read_u32le(r).await? as usize; anyhow::ensure!(len < 1 << 20, "control frame too large: {len}"); let mut buf = vec![0u8; len]; r.read_exact(&mut buf).await?; Ok(bincode::deserialize(&buf)?) } /// 编码视频帧:[总长 u32][头长 u32][bincode 头][LZ4 载荷] pub fn encode_video_frame(header: &VideoFrameHeader, payload: &[u8]) -> Vec { let hb = bincode::serialize(header).expect("serialize header"); let total = 4 + hb.len() + payload.len(); let mut out = Vec::with_capacity(total + 4); out.extend_from_slice(&(total as u32).to_le_bytes()); out.extend_from_slice(&(hb.len() as u32).to_le_bytes()); out.extend_from_slice(&hb); out.extend_from_slice(payload); out } pub async fn read_video_frame( r: &mut R, ) -> Result<(VideoFrameHeader, Vec)> { let total = read_u32le(r).await? as usize; anyhow::ensure!(total < 256 << 20, "video frame too large: {total}"); let mut buf = vec![0u8; total]; r.read_exact(&mut buf).await?; let hlen = u32::from_le_bytes(buf[0..4].try_into().unwrap()) as usize; let header: VideoFrameHeader = bincode::deserialize(&buf[4..4 + hlen])?; Ok((header, buf[4 + hlen..].to_vec())) }