Niskle互联方案

admin · 8 小时前

Niskle Hub × Niskle Link 互联方案

本目录是「在头显内用 Niskle Link 操作 PC 端 Niskle Hub」这个功能的开发资料。 整个目录可以一起发出去,也可以只发某一端方案和它对应的提示词。


文件说明

文件面向内容
01-互联协议规范-v1.md两端协议的唯一真相源。接口、信封、错误码、鉴权、能力清单、事件流、演进规则、v1 操作清单
02-Niskle Hub 互联方案(PC 端).mdPC 端Hub 端实现方案,末尾附可直接投喂给 AI 的提示词
03-Niskle Link 互联方案(头显端).md头显端Link 端实现方案,末尾附可直接投喂给 AI 的提示词

改动规则:协议层面的变化只改 01,再同步两端。0203 不重复定义协议。


这个功能要解决什么

戴着 VR 头显玩 PCVR 时,改面捕参数、重启体感追踪、看报错信息这些事, 眼下都要摘掉头显走到电脑前用鼠标做。目标是把它们搬进头显里。

这套协议同时也是后续「头显端新功能」的地基。Link 会持续加功能, 所以设计目标是「加功能不用改协议」。


路线图:将来要加串流,这决定了架构

产品路线是 Link 作为头显端串流接收端,Hub 作为 PC 端串流服务端(对标 Virtual Desktop 的两端)。

所以本次只做控制面,但控制面与未来的媒体面需要完全解耦:

平面内容状态
控制面(本次)发现、配对、鉴权、能力协商、状态订阅、操作调用本次实现
媒体面(未来)头显接收 PC 的画面与声音已规划,不在本次范围

这对实现提出两条约束(协议规范 §15 有完整说明):

  1. 控制面的核心逻辑不与 Tauri AppHandle 耦合,拆成 core/(纯逻辑)+ host_app/(Tauri 适配)。 将来串流在 PC 侧大概率需要一个常驻服务,届时 core/ 可以原样搬进 host_service/, 协议和两端实现都不受影响。

  2. stream.* 命名空间现在就在协议里占位(不实现),这样将来加串流是填实现而不是改协议。

端口方面,未来媒体面划定在 UDP 37100–37199,已在协议 §15.5 占位。


关键设计决策(一句话版)

决策结论
头显里长什么样2D 悬浮面板(普通 Android 应用),不做 OpenXR 沉浸式
传输局域网 HTTP/1.1 + JSON,下行推送用 SSE
为什么不用 WebSocket离线构建缓存里没有 tungstenite;SSE 是 HTTP 子集,头显端零新依赖
端口控制 21120/TCP(可配置,以 /v1/infoport 为准);发现信标 37022/UDP(固定)
鉴权PC 显示 6 位配对码 → 头显输入一次 → 换 32 字节长期令牌
能力清单Hub 声明,Link 只用来做门控,不做自动渲染界面
本地网络仅局域网直连;协议形状已为将来的云端中继预留
协议文件不建 JSON Schema,01 文档即规范

三个硬约束

这三条来自对现有代码的实测审计,方案是绕开它们设计的:

  1. LAN 服务落在 Rust Host 里。 Engine 的命名管道 nMaxInstances=1 且拒绝远程客户端(named_pipe_server.cpp:33-40), Rust 是它唯一客户端。头显直连 Engine 会死锁。 链路是:头显 → Rust Host → EngineManager → Engine。

  2. 头显刷命令会挤掉桌面用户的操作。 Engine 命令队列只有 32 深,溢出时丢弃最旧(engine_manager.rs:23,419-422)。 协议因此规定了服务端限流与按资源串行化。

  3. 互斥目前只写在前端main.ts 里的 slimevrBusy 等),Rust 侧没有对应物。 头显与桌面 UI 并发操作会互相干扰,串行化需要下沉到 Rust。

另有一个已经存在的安全缺口:SlimeVR 状态桥接监听 0.0.0.0:21112 且没有鉴权, 接受明文 wifi_provision:<ssid>:<密码> 等命令。它只需要被本机访问,改成只监听回环即可 (见协议 §9.5)。


建议的实施顺序

PC 端先做,并在动头显端之前用探针脚本留下证据,这样联调时能立刻分清是哪一端的问题。

阶段内容
P0–P3Hub配对 + 令牌 + RPC 骨架 → 能力清单与操作 → SSE 事件 → UDP 信标
P4–P7Link发现与配对 → 状态与追踪控制 → 体感追踪 → 更新与设备管理

P0–P3 可以用 curl 独立验证,不需要头显配合。


现在还没实现

本目录是设计文档,不是已完成的代码。截至编写时:

  • Hub 端没有自己的局域网服务(现有 21112 端口属于 SlimeVR Java 进程)

  • Link 端没有远程控制相关代码,发现机制目前只广播、不监听

  • 两端都没有配对、令牌、能力清单相关的任何代码

两端方案里各自标注了风险与未决问题,那两节值得先看。