Skip to content

WebSocket API

nixi-agent edited this page Aug 10, 2026 · 1 revision

WebSocket API

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能考量
  8. 故障排除指南
  9. 结论
  10. 附录

简介

本文件面向使用 VRChat 好友监控系统的开发者与运维人员,提供完整的 WebSocket API 文档。内容涵盖:

  • WebSocket 连接建立过程、认证机制与连接生命周期管理
  • 事件类型定义(friend-online、friend-offline、friend-location、friend-active 等)及数据格式说明
  • 连接管理最佳实践:重连策略、心跳保活、错误处理
  • 完整示例代码路径与事件处理模式
  • 性能优化建议与故障排除方法

项目结构

本项目围绕 WebSocket 连接管理与事件处理构建,关键模块如下:

  • WsManager:负责 WebSocket 连接生命周期、认证、心跳、重连、状态回调与事件分发
  • VrchatApiClient:负责 HTTP 认证、Cookie/OTP 流程、获取 WebSocket token
  • EventPipeline:将标准化后的事件持久化到数据库,并维护世界名缓存
  • FriendStateManager:内存中维护好友在线状态与位置信息
  • start-monitor.js:主入口,组装各组件,监听 WS 事件并更新本地状态
  • 测试脚本:用于直连或经代理连接验证
graph TB
A["应用/测试脚本"] --> B["WsManager<br/>连接管理"]
B --> C["VrchatApiClient<br/>HTTP认证/Token"]
B --> D["WebSocket 管道<br/>wss://pipeline.vrchat.cloud"]
B --> E["EventPipeline<br/>事件持久化"]
B --> F["FriendStateManager<br/>内存状态"]
A --> G["start-monitor.js<br/>主入口"]
G --> E
G --> F
Loading

图表来源

  • core/ws-manager.js:29-185
  • vrchat-api.js:243-330
  • core/event-pipeline.js:33-61
  • start-monitor.js:54-98

核心组件

  • WsManager:封装连接、认证、心跳、重连、事件解析与回调;支持直连失败自动回退代理;指数退避重连;认证冷却保护
  • VrchatApiClient:实现 Cookie 加载/保存、Basic Auth 登录、OTP 验证、ensureAuth 单飞锁、获取 /auth token
  • EventPipeline:按事件类型路由处理,写入数据库,维护世界名缓存
  • FriendStateManager:内存 Set/Map 维护在线集合与位置信息,支持批量刷新与变更通知
  • start-monitor.js:组合上述组件,WS 事件映射为状态更新,并在重连后全量刷新在线列表

架构总览

下图展示从认证到事件落库的端到端流程,包括直连与代理回退、心跳保活、重连策略。

sequenceDiagram
participant App as "应用/测试"
participant API as "VrchatApiClient"
participant WS as "WsManager"
participant VRC as "VRChat 服务器"
participant EP as "EventPipeline"
participant DB as "存储(SQLite)"
App->>API : "确保认证 (ensureAuth/withAutoOtp)"
API-->>App : "用户信息/需要OTP信号"
App->>API : "GET /auth 获取token"
API-->>App : "{ok : true, token}"
App->>WS : "start()"
WS->>VRC : "WSS 连接 wss : //pipeline.vrchat.cloud/?auth=token"
alt 直连成功
VRC-->>WS : "open"
WS->>WS : "启动心跳(ping/pong)"
else 直连失败
WS->>VRC : "通过代理重试"
VRC-->>WS : "open"
WS->>WS : "启动心跳"
end
VRC-->>WS : "消息(JSON)"
WS->>WS : "解析标准化事件"
WS->>EP : "process(event)"
EP->>DB : "insertEvent/upsertFriend"
WS-->>App : "onEvent(event)/onStatusChange(status)"
Loading

图表来源

  • core/ws-manager.js:93-185
  • vrchat-api.js:243-330
  • core/event-pipeline.js:33-61

详细组件分析

连接建立与认证

  • 认证流程
    • 优先尝试 Cookie 校验,过期则 Basic Auth 登录
    • 若需要邮箱 OTP,抛出 needsOtp 信号,上层可调用 ensureAuthWithAutoOtp 自动获取验证码完成登录
    • 认证成功后调用 GET /auth 获取 WebSocket token
  • 连接建立
    • 构造 URL: wss://pipeline.vrchat.cloud/?auth=token
    • 先尝试直连,超时失败后自动切换代理(环境变量优先级:VRC_MONITOR_WS_PROXY > HTTPS_PROXY/HTTP_PROXY > 内置默认)
    • 设置 User-Agent、Origin 等请求头,握手超时配置
  • 连接状态
    • 状态机:idle → connecting → connected → reconnecting → error/disconnected
    • 每次重连前刷新认证,避免 AuthExpired
    • 认证失败时进入冷却期(限流更长),防止频繁触发限流
flowchart TD
Start(["开始"]) --> CheckAuth["检查认证(Cookie/Basic)"]
CheckAuth --> |需要OTP| AutoOtp["自动获取OTP并验证"]
CheckAuth --> |OK| GetToken["GET /auth 获取token"]
AutoOtp --> GetToken
GetToken --> TryDirect["尝试直连 WSS"]
TryDirect --> |成功| Connected["已连接"]
TryDirect --> |失败| UseProxy["通过代理重试"]
UseProxy --> ProxyConnected{"代理成功?"}
ProxyConnected --> |是| Connected
ProxyConnected --> |否| Reconnect["指数退避重连"]
Reconnect --> GetToken
Loading

图表来源

  • vrchat-api.js:243-330
  • core/ws-manager.js:93-185

心跳保活与连接健康

  • 每 30 秒发送 ping,等待 10 秒 pong;未收到则主动断开并重连
  • 心跳定时器在连接成功后启动,关闭/错误时清理
  • 心跳异常会触发 _onClose -> 重连调度
sequenceDiagram
participant WS as "WsManager"
participant S as "服务器"
WS->>S : "ping (每30s)"
S-->>WS : "pong"
Note over WS,S : "若10s内未收到pong,terminate()并触发重连"
Loading

图表来源

  • core/ws-manager.js:258-287

重连策略

  • 指数退避延迟序列:1s→2s→4s→8s→16s→30s→60s(封顶)
  • MAX_RECONNECT_ATTEMPTS=0 表示无限重试
  • 每次重连前重新认证,避免 token 过期
  • 认证失败进入冷却期:普通失败 120s,限流 401 场景 300s
flowchart TD
OnClose["连接关闭"] --> Schedule["计算下次重连间隔"]
Schedule --> Wait["等待延迟"]
Wait --> Reconnect["_connect() 重新认证+连接"]
Reconnect --> Success{"连接成功?"}
Success --> |是| Reset["重置attempt/心跳"]
Success --> |否| Schedule
Loading

图表来源

  • core/ws-manager.js:318-336
  • core/ws-manager.js:310-316

事件模型与处理

  • 事件来源:WS 消息体 JSON,包含 type 与 content(content 可能为字符串嵌套 JSON)
  • 标准化字段:type、userId、displayName、location、worldId、instanceId、travelingToLocation、platform、content、raw、receivedAt
  • 事件类型与处理:
    • friend-online:标记好友上线,记录 location/worldId/platform,写入 events 表
    • friend-offline:标记离线,lastSeen/lastOffline 更新
    • friend-location:更新位置与世界名,不改变在线状态
    • user-location:自身位置变化,仅存事件,解析 worldId
    • friend-update:更新 displayName/lastSeen
    • friend-active:标记在线(活动心跳类事件)
    • friend-add/friend-delete:仅存储事件
    • notification/notification-v2:通知类事件,仅存储
  • 状态同步:
    • 重连后调用 /auth/user/friends?offline=false 全量刷新在线列表
    • 内存状态 FriendStateManager 提供 O(1) 查询与批量更新
classDiagram
class EventPipeline {
+process(event)
+getStats()
-_handleOnline(event)
-_handleOffline(event)
-_handleLocation(event)
-_handleUserLocation(event)
-_handleUpdate(event)
-_handleActive(event)
-_handleAdd(event)
-_handleDelete(event)
-_handleNotification(event)
-_storeEvent(event, worldName)
-_resolveWorldName(worldId)
}
class Storage {
+upsertFriend(...)
+insertEvent(...)
+getWorldName(worldId)
+save()
}
EventPipeline --> Storage : "读写"
Loading

图表来源

  • core/event-pipeline.js:33-217

事件类型与数据格式

  • 通用结构
    • type: 事件类型字符串
    • content: 对象或字符串(需二次解析)
    • 标准化字段由 ws-manager 提取:userId、displayName、location、worldId、instanceId、travelingToLocation、platform、receivedAt
  • 具体事件
    • friend-online
      • 含义:好友上线
      • 关键字段:userId、displayName、location、worldId、platform
      • 行为:更新在线状态、记录 lastOnline、写入 events
    • friend-offline
      • 含义:好友下线
      • 关键字段:userId
      • 行为:标记离线、记录 lastOffline
    • friend-location
      • 含义:好友位置变化(含 traveling/private/offline)
      • 关键字段:userId、location、worldId、displayName
      • 行为:更新位置与世界名,不改变在线状态
    • friend-active
      • 含义:好友活跃(如心跳/活动)
      • 关键字段:userId
      • 行为:标记在线、更新 lastSeen
    • user-location
      • 含义:自身位置变化
      • 关键字段:location(解析 worldId)
      • 行为:仅存事件,不更新好友状态表
    • friend-update
      • 含义:好友信息更新(如昵称)
      • 关键字段:userId、displayName
      • 行为:更新 lastSeen
    • friend-add / friend-delete
      • 含义:好友关系变更
      • 行为:仅存储事件
    • notification / notification-v2
      • 含义:系统通知(如 boop)
      • 行为:仅存储事件

连接管理最佳实践

  • 重连策略
    • 使用指数退避,避免雪崩与限流
    • 认证冷却:普通失败 120s,限流 401 场景 300s
    • 每次重连前刷新认证,保证 token 有效
  • 心跳保活
    • 30s ping,10s pong 超时检测
    • 超时主动断开,触发重连
  • 错误处理
    • 捕获网络错误、解析错误、认证错误
    • 区分直连失败与代理失败,记录日志便于排查
  • 状态观测
    • 暴露 getState() 获取 status、attempt、uptime、lastToken 掩码
    • onStatusChange 回调上报状态变化

完整示例与事件处理模式

  • 直连测试
    • 参考:test-ws-direct.mjs
    • 步骤:认证 → 获取 token → 直连 WSS → 接收消息 → 超时关闭
  • 经代理测试
    • 参考:test-websocket.mjs
    • 步骤:认证 → 获取 token → 通过代理连接 → 统计事件 → 报告
  • 事件处理模式
    • 统一解析:ws-manager 将 raw 消息标准化为 event
    • 路由处理:event-pipeline 根据 type 分派处理器
    • 状态同步:start-monitor 将事件映射到 FriendStateManager
    • 持久化:event-pipeline 写入 SQLite,定时 flush

依赖关系分析

  • WsManager 依赖 VrchatApiClient 进行认证与 token 获取
  • WsManager 将事件交给 EventPipeline 处理与持久化
  • start-monitor 组合 WsManager、EventPipeline、FriendStateManager,实现业务逻辑
  • 测试脚本直接依赖 VrchatApiClient 与 WebSocket 库,用于验证连通性
graph LR
VM["WsManager"] --> API["VrchatApiClient"]
VM --> EP["EventPipeline"]
SM["start-monitor"] --> VM
SM --> EP
SM --> FS["FriendStateManager"]
T1["test-ws-direct.mjs"] --> API
T2["test-websocket.mjs"] --> API
Loading

图表来源

  • core/ws-manager.js:29-185
  • core/event-pipeline.js:33-61
  • start-monitor.js:54-98
  • test-ws-direct.mjs:13-71
  • test-websocket.mjs:51-200

性能考量

  • 认证节流
    • 认证失败冷却:普通 120s,限流 300s,避免频繁触发限流
    • 单飞锁:ensureAuth/ensureAuthWithAutoOtp 并发安全
  • 连接优化
    • 直连优先,失败回退代理,减少握手失败影响
    • 心跳 30s ping,10s pong 超时,及时释放无效连接
  • 事件处理
    • 事件批量持久化:每 100 条或 5s 定时 flush,降低 I/O 压力
    • 世界名缓存:按需查询,避免重复 API 调用
  • 内存状态
    • FriendStateManager 使用 Set/Map,O(1) 查询与更新
    • 重连后全量刷新,保证一致性

故障排除指南

  • 无法直连
    • 现象:直连超时,日志提示“直连超时,尝试代理”
    • 处理:确认代理配置(环境变量优先级),检查防火墙/代理可达性
    • 参考:core/ws-manager.js:147-168
  • 认证失败/限流
    • 现象:401 或认证错误,进入冷却期
    • 处理:等待冷却结束,检查账号状态与网络;必要时手动触发 re-login
    • 参考:core/ws-manager.js:310-316
  • 心跳超时
    • 现象:无 pong,主动断开并重连
    • 处理:检查服务端响应、网络质量;调整心跳参数(如需)
    • 参考:core/ws-manager.js:268-273
  • 事件解析失败
    • 现象:JSON 解析异常,记录错误日志
    • 处理:检查原始消息,定位上游数据格式问题
    • 参考:core/ws-manager.js:233-235
  • 状态不一致
    • 现象:重连后内存状态缺失
    • 处理:触发全量刷新 /auth/user/friends?offline=false
    • 参考:start-monitor.js:81-98

结论

本 WebSocket API 实现了高可用的连接管理、健壮的认证与重连机制、标准化的事件处理与持久化。通过心跳保活、指数退避与认证冷却,系统在复杂网络环境下保持稳定。结合内存状态与数据库持久化,提供了高效的好友监控能力。建议在生产环境中合理配置代理、监控心跳与重连日志,并结合全量刷新保证状态一致性。

附录

  • 快速上手
    • 直连测试:参考 test-ws-direct.mjs
    • 代理测试:参考 test-websocket.mjs
    • 主服务集成:参考 start-monitor.js
  • 关键常量
    • 心跳间隔:30s;心跳超时:10s
    • 重连延迟序列:1s→2s→4s→8s→16s→30s→60s
    • 认证冷却:普通 120s;限流 300s
  • 事件类型速查
    • friend-online、friend-offline、friend-location、user-location、friend-update、friend-active、friend-add、friend-delete、notification、notification-v2

Clone this wiki locally