-
Notifications
You must be signed in to change notification settings - Fork 9
WebSocket通信
nixi-agent edited this page Aug 10, 2026
·
1 revision
本文件面向VRChat好友监控系统的WebSocket通信子系统,系统性说明连接建立、维护与重连机制;心跳保活算法与超时策略;事件处理管道(从原始消息到标准化事件对象);各类事件(好友在线/离线、位置更新、世界切换等)的处理逻辑;错误处理与异常恢复;连接状态监控与调试工具使用方法;以及性能优化建议与常见问题排查。
WebSocket相关代码主要分布在以下模块:
- ws-manager:负责WSS连接生命周期管理、认证、心跳、重连、状态回调
- event-pipeline:将WS事件标准化并持久化到SQLite,同时按类型路由到具体处理器
- vrchat-api:认证流程、Cookie/OTP管理、HTTP API调用
- storage:SQLite存储层(事件、好友、世界缓存等)
- friend-state:内存中的好友在线状态缓存与通知
- start-monitor:主入口,组装各组件,启动WS并桥接事件到状态管理与持久化
- test-*:直连/代理测试脚本,用于验证连通性与事件接收
graph TB
subgraph "运行时"
A["WsManager<br/>连接/心跳/重连"] --> B["EventPipeline<br/>标准化+持久化"]
A --> C["FriendStateManager<br/>内存状态"]
A --> D["VrchatApiClient<br/>认证/HTTP"]
B --> E["Storage<br/>SQLite"]
end
subgraph "外部服务"
F["VRChat WSS<br/>pipeline.vrchat.cloud"]
G["VRChat HTTP API<br/>api.vrchat.cloud"]
end
A --- F
D --- G
图表来源
- core/ws-manager.js:93-185
- core/event-pipeline.js:33-60
- vrchat-api.js:243-330
- core/storage.js:68-74
- WsManager:封装WSS连接、认证、心跳、指数退避重连、状态变更回调、最近事件日志
- EventPipeline:统一解析WS消息为标准化事件,按type分派到具体处理器,落库events表
- VrchatApiClient:Cookie/Basic Auth/OTP登录流程,确保鉴权有效,提供HTTP接口
- Storage:基于better-sqlite3的本地数据库操作,包含事件、好友、世界缓存等读写
- FriendStateManager:内存中维护好友在线集合与位置信息,支持批量刷新与监听
- 主入口start-monitor:装配上述组件,启动WS,桥接事件到状态与持久化,并在连接成功后刷新全量在线状态
下图展示从WS消息到持久化的端到端流程,包括认证、心跳、重连与事件分发。
sequenceDiagram
participant S as "服务端"
participant WS as "WsManager"
participant API as "VrchatApiClient"
participant EP as "EventPipeline"
participant DB as "Storage(SQLite)"
participant FS as "FriendStateManager"
Note over WS,API : 连接前确保认证有效
WS->>API : ensureAuth()/ensureAuthWithAutoOtp()
API-->>WS : 成功或需要OTP
WS->>S : GET /auth (获取token)
S-->>WS : {ok : true, token}
WS->>S : wss : //...?auth=token
S-->>WS : 连接建立(open)
WS->>WS : 启动心跳(30s ping, 10s pong超时)
loop 每30秒
WS->>S : ping
S-->>WS : pong
end
S-->>WS : message(JSON)
WS->>WS : 解析为标准化event
WS->>EP : onEvent(event)
EP->>DB : insertEvent(...)
EP->>FS : 可选更新内存状态(start-monitor中)
图表来源
- core/ws-manager.js:93-185
- core/ws-manager.js:197-236
- core/event-pipeline.js:33-60
- core/storage.js:68-74
- vrchat-api.js:243-330
- 认证前置:每次连接前调用ensureAuth,若需要邮箱OTP则通过ensureAuthWithAutoOtp自动获取验证码完成登录
- Token获取:GET /auth 获取wss连接所需的token
- 连接策略:优先直连wss://pipeline.vrchat.cloud/?auth=token,失败后回退到代理(环境变量优先级:VRC_MONITOR_WS_PROXY > HTTPS_PROXY/HTTP_PROXY > 内置默认)
- 握手与超时:直连握手超时6秒,代理模式15秒;open后启动心跳
- 心跳保活:每30秒ping一次,等待pong最多10秒;未收到pong则主动断开并重试
- 状态回调:连接/断开/重连时触发onStatusChange,便于上层UI或日志记录
flowchart TD
Start(["开始"]) --> Auth["确保认证有效<br/>ensureAuth/ensureAuthWithAutoOtp"]
Auth --> Token["获取WS Token<br/>GET /auth"]
Token --> TryDirect{"直连成功?"}
TryDirect -- 是 --> Open["open事件"]
TryDirect -- 否 --> Proxy["使用代理重试"]
Proxy --> Open
Open --> Heartbeat["启动心跳<br/>30s ping / 10s pong超时"]
Heartbeat --> Running["运行中"]
Running --> Close{"close/error"}
Close --> Reconnect["指数退避重连<br/>1→2→4→8→16→30→60s"]
Reconnect --> Auth
图表来源
- core/ws-manager.js:93-185
- core/ws-manager.js:258-287
- core/ws-manager.js:318-336
- 周期:30秒发送一次ping
- 超时:每次ping后设置10秒定时器,若未收到pong则主动terminate连接
- 清理:关闭/断开时清除心跳与重连定时器,避免资源泄漏
- 冷却:认证失败(尤其是限流)会进入冷却期,避免频繁Basic auth触发限流
- 指数退避:延迟序列[1,2,4,8,16,30,60]秒,最大次数可配置(当前为无限重试)
- 防抖:防止重复调度重连(_reconnectScheduled标志)
- 认证冷却:根据是否限流设置不同冷却时间,降低服务器压力
- 连接后刷新:连接成功后在start-monitor中刷新全量在线状态,保证一致性
- 标准化:ws-manager将原始JSON消息解析为统一event对象(包含type、userId、displayName、location、worldId、instanceId、platform、content、receivedAt等)
- 路由:event-pipeline根据type分派到对应处理器(friend-online/offline/location/update/active/add/delete/notification等)
- 持久化:所有事件最终写入events表,附带worldName(如可解析)与source=websocket
- 世界名解析:优先查本地world_cache,否则返回空字符串(由外部API按需填充)
flowchart TD
Msg["WS原始消息"] --> Parse["解析JSON/嵌套content"]
Parse --> Normalize["标准化为event对象"]
Normalize --> Route{"按type路由"}
Route --> |friend-online| H1["_handleOnline"]
Route --> |friend-offline| H2["_handleOffline"]
Route --> |friend-location| H3["_handleLocation"]
Route --> |user-location| H4["_handleUserLocation"]
Route --> |friend-update| H5["_handleUpdate"]
Route --> |friend-active| H6["_handleActive"]
Route --> |friend-add| H7["_handleAdd"]
Route --> |friend-delete| H8["_handleDelete"]
Route --> |notification*| H9["_handleNotification"]
Route --> |其他| Store["_storeEvent"]
H1 --> Store
H2 --> Store
H3 --> Store
H4 --> Store
H5 --> Store
H6 --> Store
H7 --> Store
H8 --> Store
H9 --> Store
Store --> DB["写入events表"]
图表来源
- core/ws-manager.js:197-236
- core/event-pipeline.js:33-60
- core/event-pipeline.js:70-180
- core/event-pipeline.js:184-210
- friend-online:更新好友在线状态、位置与世界ID,落库事件
- friend-offline:标记离线,更新last_offline
- friend-location:更新位置与世界ID,不写回世界名缓存以避免陈旧名称刷新
- user-location:解析location字符串提取worldId,仅存事件(不更新好友状态表)
- friend-update/friend-active:更新最后可见时间与在线状态
- friend-add/friend-delete:仅记录事件
- notification/notification-v2:仅记录事件
- 认证失败:设置冷却时间,避免高频Basic auth导致限流
- 连接失败:捕获异常并调度重连
- 心跳超时:主动断开连接,触发重连
- 消息解析失败:记录错误但不中断管道
- 重连保护:防止重复调度,达到最大次数(当前为无限)时置error状态
- 状态查询:getState()返回status、attempt、connectedAt、disconnectedAt、uptime、lastToken(脱敏)
- 事件日志:维护最近100条原始消息摘要,便于定位问题
- 测试脚本:
- test-websocket.mjs:通过代理连接,统计事件数量与样例
- test-ws-direct.mjs:直连测试,快速验证连通性
- 主入口集成:start-monitor在连接成功后刷新全量在线状态,并输出状态日志
- WsManager依赖VrchatApiClient进行认证与获取WS token
- EventPipeline依赖Storage进行事件持久化,并可选择性地与FriendStateManager交互(在主入口中)
- Storage使用better-sqlite3实现高性能、崩溃安全的本地存储
- 主入口start-monitor协调各组件,定义事件到状态更新的映射
graph LR
WS["WsManager"] --> API["VrchatApiClient"]
WS --> EP["EventPipeline"]
EP --> DB["Storage(SQLite)"]
EP -.可选.-> FS["FriendStateManager"]
SM["start-monitor"] --> WS
SM --> EP
SM --> FS
图表来源
- core/ws-manager.js:30-52
- core/event-pipeline.js:6-15
- core/storage.js:17-36
- core/friend-state.js:6-11
- start-monitor.js:15-22
- 心跳间隔与超时:30秒ping、10秒pong超时,平衡保活与网络开销
- 重连退避:指数退避减少瞬时重试风暴,提升稳定性
- 事件批处理:EventPipeline每100个事件触发一次持久化,降低IO频率
- 定时flush:每5秒检查是否需要保存,避免长时间内存积压
- 数据库WAL:better-sqlite3启用WAL模式,提高并发读与崩溃安全
- 世界名缓存:避免频繁API查询,仅在必要时解析
- 内存状态:FriendStateManager使用Set/Map实现O(1)查询,减少DB压力
- 无法连接
- 检查直连是否可用,必要时启用代理(环境变量配置)
- 查看握手超时与错误日志
- 频繁断线
- 检查心跳是否收到pong,确认网络质量
- 观察重连日志与冷却时间
- 认证失败
- 确认Cookie是否有效,必要时重新登录
- 如需OTP,检查自动获取流程是否成功
- 事件缺失
- 确认WS已连接且onMessage正常触发
- 检查EventPipeline路由与存储是否正常
- 性能问题
- 调整心跳间隔/超时、重连退避策略
- 评估事件批处理阈值与数据库WAL配置
该WebSocket通信子系统通过健壮的认证、心跳与指数退避重连机制,保障了与VRChat长连接的稳定性;事件处理管道实现了从原始消息到标准化事件的转换与持久化,支持多种事件类型的差异化处理;结合内存状态与本地数据库,提供了高效的状态查询与分析能力。配合测试脚本与状态监控,便于日常运维与问题定位。
- 环境变量
- VRC_MONITOR_WS_PROXY:优先使用的WS代理地址
- HTTPS_PROXY/HTTP_PROXY:备用代理
- 关键常量
- 心跳间隔:30秒
- 心跳超时:10秒
- 重连延迟序列:1,2,4,8,16,30,60秒
- 参考脚本
- test-websocket.mjs:代理连接测试
- test-ws-direct.mjs:直连快速测试
- API参考手册
- REST API接口
- WebSocket API
- SSE实时推送接口
- MCP 工具接口