Files
RemoteDesk/docs/architecture.md
T
曾志威 19a8e03a83
ci / rust (push) Canceled after 0s
ci / web (push) Canceled after 0s
ci / package-preview (push) Canceled after 0s
ci / package-installer (push) Canceled after 0s
ci / linux-agent (push) Canceled after 0s
ci / edge-service (push) Canceled after 0s
ci / coturn-pop (push) Canceled after 0s
ci / package-windows-host (push) Canceled after 0s
Document all-Rust migration and extend native media stack
2026-08-14 14:31:57 +08:00

370 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# RemoteDesk 总体架构
> 当前生效的目标架构以 [ADR 0001](adr/0001-all-rust-runtime.md) 为准:
> Agent、Client、协议和实时通信运行时全部使用 Rust,客户端采用
> winit、wgpu、egui,实时传输采用 str0m WebRTC。下文若出现 Tauri、
> WebView、Go、Hysteria2、兼容模式或独立 Edge,均视为迁移历史。
## 1. 目标和边界
RemoteDesk 解决两个问题:
1. 用 Windows 客户端连接 Windows RDP 和现代 Linux 被控端。
2. 在不依赖 VDI 的前提下,连接长期存在的固定工作站。
项目以单用户和小规模设备列表为第一目标。连接目标是长期存在的固定机器,不负责创建桌面、分配用户或回收虚拟机。Linux 只作为被控端,不构建 Linux 客户端。
## 2. 为什么采用双通道
Windows 的 RDP 服务成熟,重复实现服务端没有价值。现代 Linux 的桌面栈以 Wayland 为主,而 xrdp 通常建立独立 Xorg 会话,不能准确复现当前桌面状态,也容易丢失 GPU 加速、桌面扩展和音频体验。Linux 被控端因此固定使用自研 Agent,不依赖桌面环境自带的 RDP 服务。
因此客户端统一,协议不强行统一:
| 目标 | 首选通道 | 说明 |
|---|---|---|
| Windows 11 Pro/Enterprise、Windows Server | RDP | 使用 Windows 系统服务 |
| GNOME/KDE 等 Wayland 桌面 | Native Desktop | Agent + Portal/PipeWire/libei |
| Xorg 桌面 | Native Desktop | Agent + XComposite/DRI3/XDamage/XTest |
| 无图形桌面的 Linux | Native Terminal | Agent + PAM/PTY |
| Linux 登录界面 | Console fallback | 后续按合成器适配 |
所有连接在 UI 中表现为相同的“主机配置”,具体通道由配置和能力探测决定。
## 3. 系统组件
### 3.1 Windows Desktop Client
Windows 客户端负责:
- 管理连接配置、收藏和最近连接。
- 使用系统密钥库读取凭据。
- 创建 RDP 或 Native 会话。
- 渲染远程画面并发送输入。
- 处理剪贴板、音频、显示器和文件传输。
- 展示延迟、帧率、码率和丢包等质量指标。
客户端内部按能力拆分:
```text
Tauri UI (React/TypeScript)
|
Session Controller ---- Profile Store ---- Secret Store
|
+----------+--------------+-------------+
| | |
RDP Helper Native Video Terminal/Edge
| | |
IronRDP GStreamer xterm.js
```
客户端使用 Tauri 2 + React/TypeScript 构建主界面,终端使用 xterm.js。Linux 桌面在独立 GStreamer/D3D11 原生 helper 中完成 WebRTC、硬件解码和呈现,原始帧不进入 Tauri/WebView。Windows RDP 在另一个独立 Rust helper 中使用 IronRDP/D3D11。
### 3.2 RDP Adapter
RDP helper 封装 IronRDP,不向 Tauri UI 暴露 IronRDP 数据结构或图形帧。主要职责:
- NLA/TLS 认证与证书校验。
- 图形更新、动态分辨率和多显示器布局。
- 键盘布局、鼠标、Unicode 输入和组合键。
- 音频播放、麦克风和剪贴板通道。
- 本地目录重定向,默认关闭。
- 会话断开原因映射和有限次数重连。
渲染层将 IronRDP 图形更新映射为 D3D11 脏矩形上传。IronRDP 的 NLA、动态分辨率、虚拟通道和 RDP UDP multitransport 必须先通过技术验证;关键能力不足时,MVP 以系统 mstsc 作为隔离回退。
主程序与 helper 通过当前用户 ACL 限制的 Named Pipe 交换版本化控制消息。凭据不进入命令行,视频帧不进入 IPC。
### 3.3 Linux Agent
Linux Agent 是 Linux 唯一的被控端组件,不调用 GNOME Remote Desktop、KRdp 或 xrdp,也不提供发起远程连接的客户端界面。Agent 使用 Rust 实现,媒体管线通过 GStreamer 及其 Rust bindings 接入。
Agent 分为两个进程和权限层:
```text
remotedesk-agent-session (graphical user)
├── Wayland: Portal/PipeWire/libei
├── Xorg: XComposite/DRI3/XDamage/XTestXShm 仅兼容模式
├── 编码与会话信令
└── 用户音频与剪贴板
remotedesk-shell-session (target user)
├── PTY 与登录 Shell
├── 终端尺寸、信号与环境
└── 可靠 DataChannel
remotedesk-agentd (system)
├── 开机启动、设备配对和客户端授权
├── 发现已登录用户并联络会话进程
├── 更新与版本兼容检查
├── 可选的受控 uinput Helper
└── 受限 Unix Socket IPC
```
`agentd` 不捕获桌面、不编码媒体,也不读取剪贴板或终端内容。所有桌面处理保留在普通用户会话中。命令行会话由独立进程在完成 PAM/设备授权后降权到目标 UID,再创建 PTY。可选的 uinput Helper 必须代码面尽量小,并通过固定消息类型、调用方身份验证和最小设备权限限制风险。
### 3.4 Edge Relay
远程链路支持 Direct、Single Edge 和 Dual Edge。默认同时测量直连和 CDN 路径;当双边缘路径更优时,客户端与 Agent 分别进入最近 TURN POPPOP 间通过 CDN 私有/优质骨干传输。TURN 只转发 DTLS-SRTP/SCTP 密文,不解码、不转码、不缓存远程内容。
Agent 通过出站 TLS WebSocket 连接最近的 Rendezvous Gateway,客户端以已配对设备密钥签名会话请求。控制面只负责在线路由、信令和短期 TURN credential,不替 Agent 授权桌面或终端。详细设计见 [CDN 与边缘中继](edge-relay.md)。
Windows RDP 不使用 ICE/TURN。其 CDN 加速需要目标网络中的出站 L4 Edge Connector,在两端 POP 间透明转发 RDP TCP/UDPRDP TLS/NLA 仍由 IronRDP 与目标 Windows 端到端完成。
### 3.5 Windows Headless Native Endpoint
Windows 被控端的高性能桌面会话使用 IDD/IddCx 创建 Headless SDR 虚拟显示器。IDD 只负责虚拟显示器、显示模式和 swap-chain 生命周期,不负责编码、网络或业务授权。当前产品约束为 SDR 8-bitIDD 不作为 HDR10/10-bit 采集源。
正式组件边界如下:
Windows Service / Go Backend
- session、认证、配置和生命周期
- 输入路由(独立高优先级控制面)
- Hysteria2 路径和媒体策略
Windows Capture WorkerRust/C++ 原生 helper
- IDD frame 或 Desktop Duplication 兼容捕获
- BGRA8 GPU texture -> NV12 GPU conversion
- NVENC / AMF(VCE/VCN) / Quick Sync
- x264 / x265 / SVT-AV1 软件兜底
- 独立视频和音频队列
- 有界媒体 datagram / 控制流
IDD Driver
- Headless SDR 虚拟显示器和 4K/120 模式
Windows Headless 主路径优先直接消费 IDD GPU frame;第一阶段允许使用 Desktop Duplication 复制已存在的虚拟 output 作为兼容实现。两种路径都必须在同一 DXGI Adapter 上完成 GPU 处理,原始 BGRA8 不得进入 Go、JSON、Tauri IPC 或网络队列。
Windows Headless 视频默认支持 H.264/AVC、H.265/HEVC 和 AV1。编码器先尝试同 Adapter 的硬件后端:NVIDIA 使用 NVENCAMD 使用 AMF/VCE/VCNIntel 使用 Quick Sync;硬件能力验证失败时按协商结果切换 x264、x265 或 SVT-AV1。软件编码只能作为明确的兼容性降级,并自动降低分辨率、帧率或并发上限。
Windows Headless 音频独立使用 WASAPI loopback 或配置的虚拟音频 endpoint 采集,编码为 Opus,通过独立音频流发送。音频和视频使用同一会话单调时钟;输入不等待任何音频、视频帧、编码器或呈现确认。
无硬件 GPU 时启用 compatibility 模式。启动阶段依次探测硬件 DXGI Adapter、IDD/DDA output、WARP/Basic Display Adapter、硬件编码器和软件编码器;如果只有软件路径可用,允许 DDA/IDD 继续采集,但把像素路径标记为 software,并按 CPU 实测上限自动降低分辨率、帧率和并发数。compatibility 模式不得继续宣称 zero-copy、hardware_encode 或多路 4K/120 保证;strict 性能模式则在硬件编码器不可用时拒绝请求。
## 4. Linux 会话模式
Wayland 不允许普通进程静默截屏和任意注入输入,这是安全边界,不应通过默认 root 运行 Agent 来绕过。
### 4.1 Assisted Session
适合已经登录且有人可确认授权的桌面:
1. Agent 请求 `RemoteDesktop``ScreenCast` Portal 会话。
2. 桌面弹出系统授权窗口。
3. Portal 返回 PipeWire 节点和 libei/EIS 输入通道。
4. Agent 编码画面并建立 WebRTC 会话。
5. 用户结束共享或锁屏后,根据桌面策略暂停连接。
这是跨桌面环境最标准的模式,应优先实现。
### 4.2 Paired Unattended Session
目标是在用户首次本地授权后允许同一设备再次连接:
- Agent 保存 Portal 返回的恢复令牌和已授权显示器信息。
- 后续连接尝试恢复 Portal 会话,并继续使用 PipeWire/libei。
- 若合成器拒绝恢复或要求再次确认,Agent 必须返回明确状态,不能静默降级到 root 抓屏。
- 不同发行版和合成器对持久授权的支持不同,能力探测结果必须展示给用户。
该模式仍由自研 Agent 实现,只复用 Wayland/Portal 提供的安全接口。
### 4.3 Pre-login And Lock Screen
登录前没有普通用户的 Portal/PipeWire 会话。通用实现需要 DRM/KMS 捕获、虚拟显示、uinput 和显示管理器集成,容易与合成器、安全策略及显卡驱动冲突。因此首期规则如下:
- 已登录会话锁屏后的行为按桌面能力检测,不承诺跨桌面一致。
- 物理机登录界面控制属于后续按发行版适配的实验能力。
- 不能通过让整个 Agent 以 root 运行来绕过限制。
### 4.4 Xorg Desktop Session
Xorg 会话 Agent 以当前图形用户身份运行,并读取该用户的 Xauthority
- 使用 XDamage 获取变化区域,减少静态桌面复制。
- 默认通过 XComposite 获取 pixmap,并用 DRI3 导出 DMA-BUF 直达同 GPU 编码器。
- XShm/XImage 只在用户显式 compatibility 模式中启用。
- 使用 XTest 注入键盘和鼠标事件。
- 使用 XRandR 获取显示器拓扑和分辨率变化。
- 音频统一从 PipeWire 获取,不建立另一套音频协议。
Agent 只能连接自己所属用户的 Xorg 会话,不复制其他用户的 Xauthority,也不通过关闭 X server 访问控制来简化部署。
### 4.5 Command-line Session
纯命令行模式不需要 Wayland、Xorg 或 PipeWire
1. 已配对客户端请求目标普通用户的终端权限。
2. `agentd` 验证设备权限,并通过 PAM 建立受审计的用户会话。
3. 独立 `remotedesk-shell-session` 进程完成组、GID、UID 和环境降权。
4. 进程创建 PTY 并执行该用户允许的登录 Shell。
5. Windows 客户端使用终端控件显示 UTF-8 输出并发送输入、窗口尺寸和信号。
Linux 终端允许在配对授权中明确加入 `root` 用户。Agent 仍通过 PAM、独立会话进程和授权用户列表校验目标身份,不保存提权密码;未获授权的用户仍会被拒绝。
## 5. Native 协议
Native 通道用于 Linux Agent。第一版采用 WebRTC,避免自行设计媒体拥塞控制、时钟同步和加密传输。
### 5.1 通道划分
| 通道 | 内容 | 可靠性 |
|---|---|---|
| Video RTP | H.264/HEVC/AV1 视频 | 允许丢包 |
| Audio RTP | Opus 音频 | 允许少量丢包 |
| Input DataChannel | 键盘、鼠标、触控 | 有序,低延迟 |
| Control DataChannel | 显示器、质量、心跳 | 可靠有序 |
| Clipboard DataChannel | 文本、图片元数据 | 可靠有序 |
| File channel | 分块文件数据 | 可靠,可取消 |
| Terminal DataChannel | UTF-8 字节流、尺寸、信号 | 可靠有序 |
会话优先使用直连 candidate,并同时支持由边缘 Allocator 签发的短期 TURN candidate。公网模式通过 Rendezvous 转发信令;本地模式可以直接连接 Agent。两种模式共享相同设备身份、Session Ticket 和端到端 DTLS-SRTP。
### 5.2 差网络自适应
WebRTC 内置拥塞控制负责估算可用带宽,RemoteDesk 在其上增加会话策略:
- 使用 TWCC/GCC、RTT、抖动、NACK、PLI 和丢包 EWMA 判断链路等级。
- 协商 NACK/RTX;FEC 仅在双方支持且收益高于带宽成本时启用。
- 丢包上升时依次降低视频码率、帧率和分辨率,恢复时缓慢升档并设置迟滞。
- Opus 音频可启用 in-band FEC/DTX,优先级高于视频。
- 键盘、鼠标按键和控制消息可靠发送;高频鼠标移动只保留最新状态。
- 剪贴板和文件传输限流,严重丢包时暂停,不能阻塞输入。
- 解码端丢弃过时视频帧,连续解码失败时请求关键帧。
策略不以单次丢包采样立即切档,而使用短期/中期滑动窗口和恢复迟滞,避免画质频繁震荡。详细规则见 [差网络自适应设计](network-adaptation.md)。
### 5.3 会话状态机
```text
Idle
-> Resolving
-> Authenticating
-> Negotiating
-> Connected
-> Reconnecting
-> Connected | Failed | Closed
```
所有 Adapter 必须映射到同一状态机和错误类型,UI 不根据协议拼接错误字符串。
### 5.4 编码策略
- 默认 H.264,优先硬件编码,保证最大兼容性。
- HEVC 和 AV1 仅在双方能力协商成功时启用。
- 办公模式优先清晰度和文字边缘,限制静态画面的无效刷新。
- 动态模式优先低延迟和帧率。
- 分辨率变化应触发编码器重配置,不重建整个会话。
- 严格模式下硬件编码器或 GPU surface 导入不可用时拒绝图形会话;软件编码仅允许在用户显式开启的兼容模式中使用。
### 5.5 零拷贝边界
Linux Wayland 的默认发送路径为 `PipeWire DMA-BUF -> GPU conversion/scale -> hardware encoder`Xorg 默认尝试 `XComposite pixmap -> DRI3 DMA-BUF -> hardware encoder`。Windows 默认接收路径为 `hardware decoder -> GstD3D11Memory -> d3d11videosink`。两端原始像素都不得经过 Rust `Vec<u8>`、GStreamer `appsink`、JavaScript、Tauri IPC 或其他 CPU 映射。
压缩后的 H.264/HEVC/AV1 码流、RTP 包和控制消息进入普通内存不属于原始帧复制。默认策略 `required_end_to_end` 要求 Agent 和客户端 helper 都报告经过验证的 `zero_copy`,否则返回 `CAPABILITY_ZERO_COPY_UNAVAILABLE`。跨 GPU Adapter、PipeWire memory frame、XShm/XImage、软件编解码、WebView2 opaque path 和 IronRDP CPU bitmap 均不满足该策略。用户只有显式选择 `compatibility` 才允许这些路径。
## 6. 认证与安全
### 6.1 RDP
- 默认启用 NLA 和 TLS。
- 首次连接不要求用户配置或确认服务器证书指纹。
- 证书变化必须阻断自动连接并提示用户重新确认。
- 密码只保存到系统密钥库,SQLite 仅保存凭据引用。
- 磁盘、剪贴板、麦克风重定向按连接配置单独授权。
### 6.2 Linux Agent
- 首次配对由 Agent 生成一次性短码和设备公钥。
- 客户端与 Agent 交换长期设备公钥,配对码只用于确认本次配对。
- 后续使用双向设备认证和 TLS 1.3。
- Agent 保存允许连接的客户端公钥,可本机撤销。
- 会话开始和结束必须有可见系统通知。
- 日志不得记录密码、剪贴板内容、文件内容或配对私钥。
### 6.3 本地数据
SQLite 保存:
- 主机名、地址、端口和协议类型。
- 显示、音频、剪贴板和质量选项。
- 证书指纹、Agent 设备 ID 和密钥库引用。
- 最近连接时间与非敏感错误摘要。
数据库不保存明文密码或私钥。
## 7. 用户体验
主界面直接展示远程主机列表,不设置营销首页。核心工作流:
1. 新建主机,选择“Windows RDP”或“Linux Agent”,Linux 可选自动桌面、Wayland、Xorg 或命令行模式。
2. 执行能力检测并给出可用通道。
3. 点击连接并等待目标服务就绪。
4. 进入独立会话窗口,工具栏默认自动隐藏。
5. 断开后返回原主机条目,并保留可诊断的结束原因。
会话工具栏提供显示器、分辨率、全屏、本地缩放、画质、剪贴板、文件传输、统计和断开按钮。分辨率和本地缩放是两个独立设置:前者控制 RDP 会话尺寸或 Linux 编码尺寸,后者只控制客户端如何把收到的画面放入窗口。危险操作如发送安全注意序列、重启远端应放入菜单并二次确认。
分辨率支持以下模式:
- 自动跟随:默认。窗口稳定后发送新的目标尺寸,并使用防抖避免拖动时反复重配。
- 原始分辨率:保持远端显示器/桌面源尺寸,客户端只做本地缩放。
- 固定档位:720p、1080p、1440p、4K,以及经过能力校验的自定义宽高。
RDP 通过 Display Control/动态分辨率修改远程会话桌面;不支持时可提示重连后应用初始尺寸。Linux Wayland/Xorg 默认保持实体桌面模式不变,只在捕获与编码之间缩放。这样调整串流清晰度不会改变被控端显示器布局、打乱本地窗口或触发合成器权限问题。
## 8. 性能目标
首个稳定版本的工程目标:
| 场景 | 目标 |
|---|---|
| 办公静态桌面 | 文字清晰、低带宽、无持续满帧编码 |
| 1080p 动态画面 | 60 fps,局域环境端到端延迟可感知但不拖沓 |
| 4K 办公 | 30/60 fps 可配置,优先硬件编解码 |
| 输入 | 不因视频帧阻塞输入发送 |
| 重连 | 短时中断自动恢复,超过阈值明确失败 |
实际延迟与显卡、编码器、桌面合成器和网络条件有关,测试报告必须记录完整环境,不能只给出单个延迟数字。
## 9. 可观测性和诊断
- 客户端提供可导出的结构化诊断包。
- 诊断包包含版本、能力、会话状态转换和非敏感错误。
- Native 会话记录 RTT、抖动、丢包、码率、编码/解码时间和丢帧。
- RDP 会话记录协商能力、重定向通道、IronRDP 错误和 UDP multitransport 状态。
- 日志默认滚动保存并限制大小。
- 导出前对用户名、地址和路径进行可选脱敏。
## 10. 测试矩阵
最低覆盖:
- Windows 11 Pro 与 Windows Server 的 RDP。
- Ubuntu/Fedora 当前稳定版 GNOME Wayland 上的自研 Agent。
- KDE neon 或主流发行版 Plasma 6 Wayland 上的自研 Agent。
- 至少一种 GNOME/KDE Xorg 会话。
- 无图形环境的 Debian/Ubuntu Server 命令行会话。
- NVIDIA、AMD 和 Intel 至少各一种硬件编解码环境。
- 单显示器、双显示器、HiDPI 和动态分辨率。
- 中文输入、剪贴板、大文件和音频。
- 证书变化、错误密码、锁屏、休眠、VM 重启和断网重连。
测试分层为核心状态机单元测试、协议适配集成测试、虚拟机端到端测试和长时间稳定性测试。
## 11. 主要风险
| 风险 | 应对 |
|---|---|
| IronRDP 关键 RDP 能力不足 | M0 设置功能门槛,保留 mstsc 隔离回退 Adapter |
| WebView2 GPU 无法证明内部 surface 路径 | Linux 桌面默认使用原生 video helperWebView2 仅显式兼容模式 |
| 驱动或桌面不提供可导入的 GPU surface | 默认拒绝图形会话;用户显式启用 compatibility 后才允许回退 |
| Tauri 与原生 helper 生命周期不一致 | Named Pipe heartbeat、generation、独立崩溃恢复和幂等关闭 |
| Web 输入无法覆盖系统组合键/Raw Input | 系统组合键走 Rust command,高要求场景切换原生 helper |
| 差网络下视频震荡或输入阻塞 | WebRTC GCC + 分层退化 + 有界独立队列 + 恢复迟滞 |
| Wayland Portal 行为随桌面变化 | 维护能力探测和发行版测试矩阵 |
| Xorg 捕获权限配置错误 | 只使用目标用户 Xauthority,禁止关闭 X 访问控制 |
| PTY 远程终端扩大权限面 | PAM 建立会话、强制降权、设备权限独立控制 |
| 无人值守 Linux 缺乏统一接口 | 首次授权后尝试 Portal 恢复令牌,登录界面单独适配 |
| 硬件编码器兼容性 | 默认拒绝非零拷贝会话;显式 compatibility 才允许 H.264 软件回退 |
| 输入法和键盘布局错误 | 统一物理键与 Unicode 输入模型,专项测试中英文布局 |
| IronRDP/GStreamer 等依赖安全更新 | 固定版本、生成 SBOM、建立升级回归测试 |