formatting and comments
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
# 组件实时协议
|
||||
|
||||
当前协议版本为 `1`。后端的权威定义在 `domain.rs` 的
|
||||
`ComponentMessage`,浏览器渲染器只依赖本文列出的稳定字段。
|
||||
|
||||
## 连接地址与认证
|
||||
|
||||
组件流地址:
|
||||
|
||||
```text
|
||||
wss://danmaku.luoxingci.com/api/v1/components/<publicId>/stream
|
||||
```
|
||||
|
||||
OBS 页面地址中的 token 位于 fragment:
|
||||
|
||||
```text
|
||||
https://danmaku.luoxingci.com/obs/<publicId>#token=<component-token>
|
||||
```
|
||||
|
||||
fragment 不会进入首次 HTTP 请求或 Nginx access
|
||||
log。WebSocket 建立后,客户端必须在 8 秒内发送第一帧:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "authenticate",
|
||||
"token": "component-token"
|
||||
}
|
||||
```
|
||||
|
||||
服务端验证 token 摘要、组件归属和 `events:subscribe` scope。认证成功后返回:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"type": "authenticated",
|
||||
"componentId": "08d31d19-3e4b-4c11-9cf7-9bd786a39465"
|
||||
}
|
||||
```
|
||||
|
||||
之后立即发送
|
||||
`overlay.settings.snapshot`,再开始发送实时事件。token 无效、被轮换或属于其他组件时,服务端以 policy
|
||||
close 结束连接。
|
||||
|
||||
## 版本化事件信封
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"id": "d56c1a28-a6f1-4ad9-b02f-4c22dc4d3c27",
|
||||
"componentId": "08d31d19-3e4b-4c11-9cf7-9bd786a39465",
|
||||
"sourceId": "c8087bb0-0dde-40eb-a43d-a9a2574c2717",
|
||||
"occurredAt": "2026-07-15T20:10:30.125Z",
|
||||
"roomId": "123456",
|
||||
"type": "live.danmaku",
|
||||
"payload": {
|
||||
"viewer": { "uid": "42", "name": "观众" },
|
||||
"text": "晚上好",
|
||||
"segments": [{ "type": "text", "text": "晚上好" }]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`ownerId` 永远不会序列化到浏览器。消费者应按 `version` 和 `type`
|
||||
分派,并忽略不认识的 payload 字段,从而允许兼容地增加元数据。
|
||||
|
||||
## 事件类型
|
||||
|
||||
| `type` | 主要 payload | 说明 |
|
||||
| --------------------------- | --------------------------------------------- | ---------------------- |
|
||||
| `overlay.settings.snapshot` | `settings` | 认证后当前设置快照 |
|
||||
| `overlay.settings.updated` | `settings` | 控制台保存后的实时设置 |
|
||||
| `live.danmaku` | `viewer`, `text`, `segments` | 普通文字和表情分段 |
|
||||
| `live.enter` | `viewer` | 进房事件 |
|
||||
| `live.gift` | `viewer`, `gift`, `quantity`, `sourceEventId` | 一次可记账的礼物事件 |
|
||||
| `live.gift.combo` | `viewer`, `gift`, `quantity`, `comboId` | 同一连击的视觉更新 |
|
||||
| `live.superchat` | `viewer`, `message`, `price`, `sourceEventId` | 醒目留言 |
|
||||
| `live.guard.buy` | `viewer`, `guardName`, `quantity`, `price` | 舰长购买 |
|
||||
| `live.like` | `viewer` | 点赞 |
|
||||
| `live.share` | `viewer` | 分享 |
|
||||
| `live.unknown` | `command`, `metadata` | 有界且已清理的未知事件 |
|
||||
|
||||
礼物目录价格的原始单位是人民币的千分之一。`gift.totalPrice` 保留该整数单位,`gift.priceCny`
|
||||
是供展示使用的人民币数值。
|
||||
|
||||
`live.gift` 与 `live.gift.combo` 不是两笔礼物。需要持久化计数的组件通常只消费
|
||||
`live.gift`;连击事件用于更新同一张视觉卡片。
|
||||
|
||||
## 表情分段
|
||||
|
||||
`live.danmaku.payload.segments` 是判别联合:
|
||||
|
||||
- `text`:包含可直接显示的文字。
|
||||
- `emoticon`:包含回退文字、图片 URL、可选尺寸、动态标记和整条大表情标记。
|
||||
|
||||
图片失败时客户端必须回退到 `text`,不能让一张失效图片破坏整条弹幕。
|
||||
|
||||
## 背压与重连
|
||||
|
||||
- 每个组件使用有界 `tokio::broadcast` channel。
|
||||
- 慢客户端发生 `Lagged` 时跳过已经丢失的旧帧,继续接收新事件;实时展示不保证历史重放。
|
||||
- 浏览器对非鉴权关闭使用指数退避重连,上限 12 秒。
|
||||
- 鉴权失败不会自动重试,避免对已撤销 token 形成无限请求。
|
||||
- 需要可靠业务处理的功能必须实现 `EventHandler` 并写入数据库,不能把 WebSocket 当作消息队列。
|
||||
Reference in New Issue
Block a user