Neko 路线图解析:从 V3 服务器迁移、客户端重写到模块化架构
【免费下载链接】nekoA self hosted virtual browser that runs in docker and uses WebRTC.项目地址: https://gitcode.com/GitHub_Trending/ne/neko
Neko 是一个运行在 Docker 中、基于 WebRTC 的自托管虚拟浏览器项目,其官方路线图(webpage/docs/roadmap.md)将未来发展划分为三个阶段:V3 服务器迁移、V3 客户端重写、整体模块化。本文以该路线图为骨架,结合当前仓库中的服务端、客户端源码与配置实现,逐阶段拆解每个规划的技术内涵、当前落地状态与后续演进方向,帮助读者理解 Neko 的架构演进逻辑,以及连接、媒体流、控制三大抽象层的设计思路。
路线图总览:三个阶段
路线图将 Neko 的发展划分为三个彼此衔接的阶段,每一阶段聚焦项目的一个侧面:
- Phase 1 – Server migration to V3:完成服务端向 V3 的迁移与整合,已随 Neko V3.0.0 发布而完成;
- Phase 2 – Client rewrite to V3:将基于 Vue2 的客户端重写为基于 Vue3 的组件化客户端;
- Phase 3 – Modularization:将 V3 客户端与服务端模块化,把连接、媒体流、控制抽取为可替换的接口层。
从仓库结构看,这三个阶段并非彼此割裂:服务端server/internal/下的api/、capture/、http/legacy/、webrtc/、websocket/等模块,以及客户端client/src/下的neko/、store/、components/,共同构成了路线图所描述的现状基础。
Phase 1:V3 服务器迁移与 V2 兼容层
服务器合并与 V3.0.0 发布
Phase 1 的目标是完成服务端迁移,其成果随 Neko V3.0.0 发布而落地。原 m1k1o/neko 服务器与已归档的 demodesk/neko 服务器被合并,并在此基础上发布了新的 V3.0.0 版本。合并的目的在于统一两套代码遗产、收敛维护精力,同时为后续的客户端重写与模块化提供稳定的服务端基础。
V2 客户端兼容层:legacy 模块
路线图明确指出,Phase 1 中"添加了一个兼容层以支持 V2 客户端"。在仓库中,这一兼容层对应server/internal/http/legacy/目录(handler.go 等)。
从源码看,LegacyHandler采用"协议翻译代理"模式实现兼容:
- 对外暴露 V2 时代的 HTTP/WebSocket 端点,例如
/ws、/stats、/screenshot.jpg、/file(支持 GET/POST/DELETE)、/health(handler.go); - 收到 V2 客户端连接后,通过
wsDialer.Dial("ws://"+serverAddr+"/api/ws?token=...")回连到 V3 后端(handler.go); - 通过两个 goroutine 双向复制 WebSocket 消息(
replicateWebsocketConn),并在wsToClient/wsToBackend中对新旧消息格式做改写(handler.go)。
这意味着 V2 老客户端无需改动即可继续访问 V3 服务端,为 V3 上线提供了平滑过渡路径。
配置层面的 V2 → V3 迁移
与兼容层配套,服务端保留了完整的 V2 配置兼容逻辑。以 WebRTC 配置为例,server/internal/config/webrtc.go 中同时存在Init/Set(V3 命名空间)与InitV2/SetV2(V2 旧命名空间):
- V3 配置形如
NEKO_WEBRTC_ICELITE、NEKO_WEBRTC_ICESERVERS_FRONTEND、NEKO_WEBRTC_EPR等; - V2 配置形如
NEKO_ICELITE、NEKO_ICESERVERS、NEKO_EPR等,一旦被检测到,代码会打印弃用警告并自动启用legacy标志(webrtc.go)。
视频捕获配置同样如此:server/internal/config/capture.go 中 V2 的NEKO_VIDEO_CODEC、NEKO_HWENC、NEKO_VIDEO_BITRATE、NEKO_MAX_FPS会被转换为 V3 的NEKO_CAPTURE_VIDEO_*管线配置,并通过NewVideoPipeline自动生成 GStreamer 管线(capture.go)。这种"新旧并存、自动降级"的设计,保证了从 V2 到 V3 的配置迁移成本可控。
Phase 2:V3 客户端重写(Vue2 → Vue3)
重写动机:Vue2 生命周期结束
路线图指出,V2 客户端基于 Vue2 构建,而 Vue2 早已到达生命周期终点(EOL)。当前仓库的 client/package.json 中依赖仍为"vue": "^2.7.13"、vue-class-component、vue-property-decorator、vuex等 Vue2 生态组件,这正印证了路线图所述的现状——V2 客户端仍是当前实现。
从"界面导向"到"组件导向"的设计转变
路线图明确对比了两代客户端的设计哲学:
- V2 客户端聚焦用户界面(user interface):当前
client/src/components/下的connect.vue、video.vue、menu.vue、side.vue、controls.vue、members.vue、chat.vue、clipboard.vue等组件即为此类 UI 呈现; - V3 客户端聚焦可扩展性(extensibility in the form of components):客户端将被拆分为可无缝嵌入任意现有应用的组件,这些组件可以在任何其他 Vue3 应用中被复用;对传统用户而言,客户端仍会以独立应用形式提供全部既有功能。
仓库中已经能看到组件化方向的雏形:client/src/lib.ts 通过build:lib脚本(vue-cli-service build --target lib --name neko-lib 'src/lib.ts')将客户端构建为库,并导出了NekoConnect、NekoVideo、NekoMenu、NekoSide、NekoControls、NekoMembers、NekoChat、NekoClipboard等一系列可独立引用的组件(package.json,lib.ts)。这就是"组件可用于任何 Vue3 应用"理念在当前代码中的最早落地。
Phase 3:模块化——连接、媒体流与控制三抽象
Phase 3 是路线图中着墨最多的部分。其核心设想是:V3 客户端将被拆分成一个不依赖 Vue.js(甚至不依赖任何库)的 TypeScript 组件库,任何项目都可以像嵌入一个视频播放器那样轻松集成 Neko,参考 demodesk/neko-client 的构建思路,但去掉 Vue.js 依赖。同时,连接(connection)、媒体流(media streaming)、控制(control)将被提取为接口,使 Neko 从"共享虚拟环境"升级为"内置反馈与带外通信工具的视频流服务器"——例如原生绑定 RDP/VNC 协议、远程控制无人机/机器人/PTZ 摄像头/工业设备等。由于控制层可以是插件,输入源也不再局限于键盘鼠标,还可接入游戏手柄、摇杆甚至 VR 眼镜。
Connection:面向 API 用户的连接抽象
路线图要求:Neko 可以通过多种通道连接后端,因此API 用户不应暴露于 WebSocket 内部细节,只需要关心两类信息:
连接状态(connection status):
| 状态 | 含义 |
|---|---|
connected | 用户已连接服务器 |
connecting | 客户端正在尝试建立连接 |
disconnected | 用户已断开且无重连尝试,必须携带断开原因 |
连接类型(connection type):
| 类型 | 机制 |
|---|---|
none | 当前未使用任何连接 |
short_polling | 每隔 X ms 客户端请求一次服务器获取更新 |
long_polling | HTTP 请求保持打开,直到服务器有更新下发,随后客户端再发起新请求 |
sse | 服务器通过 Server-Sent Events 向客户端推送更新 |
websocket | 服务器通过 WebSockets 推送更新 |
... | 其他,例如 MQTT |
当前实现中,连接状态机已存在于客户端基类 client/src/neko/base.ts:
socketOpen判断 WebSocket 是否打开,peerConnected判断 WebRTC ICE 状态是否处于connected/checking/completed,二者同时满足才认为整体connected(base.ts);- 事件处理中区分了
EVENT.CONNECTING、EVENT.CONNECTED、EVENT.DISCONNECTED(reason),其中onDisconnected会接收reason?: Error参数(base.ts),与路线图"断开必须携带原因"的要求一致; - 客户端状态在 Vuex store 中维护
connecting/connected布尔状态(client/src/store/index.ts)。
这也解释了路线图为何要求抽取连接接口:当前BaseClient将 WebSocket(信令、控制消息)与 WebRTC(媒体、数据通道)深度耦合,一旦接入 MQTT 或 SSE 通道,就必须在接口层将这些细节隐藏起来。
Media streaming:单一接口下的多流后端
路线图对媒体流提出了与连接层对称的抽象,计划支持的流媒体后端包括:
| 流后端 | 机制 |
|---|---|
none | 当前无媒体流 |
m3u8 | 通过 HLS 传输媒体 |
webrtc | 通过 WebRTC 传输媒体 |
quic | 通过 QUIC 传输媒体 |
... | 其他,例如 RTSP、DASH |
不同的流媒体后端具备不同能力:例如 WebRTC 支持"向服务器发送媒体"(麦克风上行),而 HTTP 系只能单向接收。流后端的选择可基于用户设备能力、网络条件、服务器能力综合决定。所有流后端必须满足同一个接口,该接口是与系统其他部分通信的唯一通道。
仓库当前的多流支持已经为这一抽象奠定了基础:
- server/internal/config/capture.go 支持配置多个视频管线
NEKO_CAPTURE_VIDEO_PIPELINES(map[string]VideoConfig)与有序视频 ID 列表NEKO_CAPTURE_VIDEO_IDS,也可用NEKO_CAPTURE_VIDEO_PIPELINE快捷配置单管线;未配置时使用默认 VP8 管线(capture.go); - server/internal/capture/streamselector.go 实现了
StreamSelectorManagerCtx流选择器,支持按流 ID(exact/lower/higher)和按码率(nearest/lower/higher/exact)选择当前使用的流,并带有nearestBitrate最近码率匹配逻辑(streamselector.go); - 服务端 WebRTC 带宽估计器(
webrtc.estimator.*系列配置,见 server/internal/config/webrtc.go)会根据估计带宽自动在高低码率流之间升级/降级,其read_interval、stable_duration、unstable_duration、diff_threshold等参数正是"基于网络条件选择流"的工程实现。
路线图中"单一接口"的设计目标,与当前StreamSinkManager/StreamSelector的抽象方向是一致的——未来的 m3u8/quic 后端可以挂到同一接口之下。
Control(人机接口设备):带内与带外反馈
控制层是 Phase 3 中最具想象力的部分。路线图设想用户可使用键盘、鼠标、游戏手柄、触摸屏或任何其他可控制系统的设备,也支持自定义或虚拟设备。控制数据的反馈分为两种模式:
- 带内反馈(in-band):正常情况下,反馈直接在媒体流内呈现给用户(例如画面本身);
- 带外反馈(out-of-band):在特定场景下必须走独立通道,包括:
- 游戏手柄的振动反馈;
- 光标在屏幕上被隐藏,或针对特定用户隐藏,因此光标需要带外传输;
- 多用户场景下,所有人可在屏幕上看到各自的自定义光标,但只有一人能实际控制光标,因此光标位置必须带外传输;
- 修改屏幕分辨率、方向或其他设置;
- 修改键盘布局或修饰键;
- 设置 host(根据优先级与权限决定当前控制者)。
控制数据既可以通过底层连接传输,也可以通过媒体流通道传输——例如WebRTC data channel 可用于实时传输控制数据。
当前实现恰好展示了"带外光标"与"数据通道控制"的雏形:
- server/internal/webrtc/handler.go 处理 WebRTC DataChannel 上到达的二进制控制协议:
OP_MOVE移动事件中,host 用户移动真实光标(manager.desktop.Move+curPosition.Set),非 host 用户仅更新自己的会话光标位置(session.SetCursor),这与路线图"只有一人控制光标、所有人光标位置带外传输"完全吻合(handler.go);此外还处理OP_SCROLL、键盘按键(KEY_DOWN/KEY_UP)与OP_PING/OP_PONG心跳(handler.go); - 客户端侧 client/src/neko/base.ts 的
sendData用二进制帧封装鼠标移动(OPCODE.MOVE)、滚轮(OPCODE.SCROLL)、按键按下/抬起,通过this._channel.send(buffer)走 RTCDataChannel 发送; - 服务端
server/internal/webrtc/cursor/(image.go、position.go)独立维护光标图像与位置,client/src/neko/index.ts 中EVENT.CONTROL.LOCKED/EVENT.CONTROL.RELEASE分别响应 host 的取得与释放,配合键盘布局切换(remote.changeKeyboard()),正是"设置 host"与"键盘布局带外同步"的现有实现。
路线图的演进价值
综合来看,Neko 的路线图描绘了一条清晰的架构演进路径:
- 兼容优先:Phase 1 通过合并服务器 + 协议代理兼容层(
server/internal/http/legacy/)+ V2 配置自动迁移(webrtc.go/capture.go的InitV2/SetV2),在不中断老用户的前提下完成服务端换代; - 体验升级:Phase 2 借 Vue2 EOL 之机,把以界面为中心的客户端重构为以组件为中心的可嵌入式客户端(
client/src/lib.ts已是第一步); - 能力泛化:Phase 3 将连接、媒体流、控制三者的接口彻底解耦,使 Neko 从"共享浏览器"泛化为通用的低延迟远程控制与视频流基础设施,输入设备与传输协议均可按插件化方式扩展。
对开发者而言,如果希望参与 Neko 的后续演进,可以从三个切入点着手:研究 server/internal/http/legacy/ 理解协议兼容层的实现模式;阅读 client/src/neko/base.ts 与 client/src/lib.ts 评估 Vue3 客户端重写的工作量;以及围绕 server/internal/webrtc/handler.go 与 server/internal/capture/streamselector.go 思考新流后端与控制设备插件应如何接入统一接口。
【免费下载链接】nekoA self hosted virtual browser that runs in docker and uses WebRTC.项目地址: https://gitcode.com/GitHub_Trending/ne/neko
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考