@cg-devcenter/rtc-fpnn-webjs-sdk 1.0.0-cg.2 → 1.0.0-cg.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -43
- package/dist/rtm.d.ts +175 -2
- package/dist/rtm.min.js +6 -6
- package/dist/rtm.shared-worker.js +27 -0
- package/dist/rtm.vite.d.ts +13 -0
- package/dist/rtm.vite.mjs +35 -0
- package/docs/CAPABILITIES.md +130 -0
- package/docs/PROTOCOL_MIGRATION.md +146 -0
- package/docs/TLV.md +1 -1
- package/docs/TLV_CONTRACT.md +2 -2
- package/docs/TLV_LIVE_E2E_TEST.md +115 -0
- package/docs/USAGE.md +538 -160
- package/package.json +14 -8
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import rtm = require('./rtm');
|
|
2
|
+
|
|
3
|
+
declare const sdk: typeof rtm;
|
|
4
|
+
|
|
5
|
+
export default sdk;
|
|
6
|
+
export const RTMClient: typeof rtm.RTMClient;
|
|
7
|
+
export const createClient: typeof rtm.createClient;
|
|
8
|
+
export const RTMSharedWorkerClient: typeof rtm.RTMSharedWorkerClient;
|
|
9
|
+
export const RTMConfig: typeof rtm.RTMConfig;
|
|
10
|
+
export const RTMProcessor: typeof rtm.RTMProcessor;
|
|
11
|
+
export const TLVCodec: typeof rtm.TLVCodec;
|
|
12
|
+
export const TLVWebSocketClient: typeof rtm.TLVWebSocketClient;
|
|
13
|
+
export const createSharedWorkerName: typeof rtm.createSharedWorkerName;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Use the package export for the UMD bundle so Vite's dependency optimizer
|
|
2
|
+
// provides CommonJS default interop. A relative import from this ESM wrapper
|
|
3
|
+
// is served as native ESM in dev and has no default export.
|
|
4
|
+
import rtmModule from '@cg-devcenter/rtc-fpnn-webjs-sdk/dist/rtm.min.js';
|
|
5
|
+
import workerUrl from './rtm.shared-worker.js?url';
|
|
6
|
+
|
|
7
|
+
const rtm = rtmModule.default || rtmModule;
|
|
8
|
+
|
|
9
|
+
class RTMSharedWorkerClient extends rtm.RTMSharedWorkerClient {
|
|
10
|
+
constructor(options) {
|
|
11
|
+
const config = options || {};
|
|
12
|
+
super(Object.assign({}, config, {
|
|
13
|
+
workerUrl: config.workerUrl || workerUrl
|
|
14
|
+
}));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function createClient(options) {
|
|
19
|
+
const config = options || {};
|
|
20
|
+
return rtm.createClient(Object.assign({}, config, {
|
|
21
|
+
workerUrl: config.workerUrl || workerUrl
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const sdk = Object.assign({}, rtm, { RTMSharedWorkerClient, createClient });
|
|
26
|
+
|
|
27
|
+
export const RTMClient = sdk.RTMClient;
|
|
28
|
+
export { createClient };
|
|
29
|
+
export { RTMSharedWorkerClient };
|
|
30
|
+
export const RTMConfig = sdk.RTMConfig;
|
|
31
|
+
export const RTMProcessor = sdk.RTMProcessor;
|
|
32
|
+
export const TLVCodec = sdk.TLVCodec;
|
|
33
|
+
export const TLVWebSocketClient = sdk.TLVWebSocketClient;
|
|
34
|
+
export const createSharedWorkerName = sdk.createSharedWorkerName;
|
|
35
|
+
export default sdk;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# RTM WebSocket SDK 能力总览
|
|
2
|
+
|
|
3
|
+
本页按接入方的业务目标整理 SDK 能做什么、每项能力对应哪些 API,以及 TLV v1 与 FPNN 的使用入口。具体参数、回调字段和 wire body 以 [SDK API](USAGE.md) 与 [TLV v1 Client API 契约](TLV_CONTRACT.md) 为准;逐 API 的 TLV 支持状态以 [TLV v1 API 支持矩阵](USAGE.md#6-tlv-v1-api-支持矩阵) 为准。
|
|
4
|
+
|
|
5
|
+
如果要从旧 FPNN 接入切换协议,参见 [FPNN 与 TLV v1 迁移对照](PROTOCOL_MIGRATION.md),其中按业务 API 列出 FPNN method 和 TLV URI 的对应关系。
|
|
6
|
+
|
|
7
|
+
下面的能力地图覆盖 SDK 整体 API;选择具体协议后,结合“协议与能力入口”表确定对应的调用入口和业务范围。
|
|
8
|
+
|
|
9
|
+
## 能力地图
|
|
10
|
+
|
|
11
|
+
当前源码推荐通过 `createClient()` 默认共享接入:扁平配置,UID 从登录参数取得,SDK 按 PID + 协议 + UID 自动命名并复用连接。`sharing: false` 显式选择独立连接;旧构造器保留原行为。已发布 `.3` 尚无此新入口,配置、错误和生命周期见 [默认共享接入](USAGE.md#默认共享接入当前源码)。
|
|
12
|
+
|
|
13
|
+
| 业务目标 | SDK 能力 | 常用 API |
|
|
14
|
+
| --- | --- | --- |
|
|
15
|
+
| 建立实时连接 | 登录、协议级关闭、主动关闭、自动重连、服务端时间、连接属性、调试日志 | `login`、`bye`、`close`、`startAutoReconnect`、`getServerTime`、`addAttrs`、`getAttrs`、`addDebugLog` |
|
|
16
|
+
| 同浏览器多窗口 | 同一 UID 共享一条 RTM WebSocket、共享登录态、按会话路由 Push | `createClient`、`RTMSharedWorkerClient`、`whenReady`、`loginIfNeeded`、`SharedSessionState`、`setConversation` |
|
|
17
|
+
| 维护用户状态 | 查询在线用户、设置/读取个人资料、读取公开资料、设置翻译语言 | `getOnlineUsers`、`setUserInfo`、`getUserInfo`、`getUserOpenInfo`、`setTranslationLanguage` |
|
|
18
|
+
| 保存用户数据 | 按 key 写入、读取和删除用户存储 | `dataSet`、`dataGet`、`dataDelete` |
|
|
19
|
+
| 用户关系控制 | 添加/解除黑名单并读取黑名单列表 | `addBlacks`、`deleteBlacks`、`getBlacks` |
|
|
20
|
+
| 一对一消息 | 发送文本、语音、命令消息;批量发送;接收可靠 Push | `sendChat`、`sendAudio`、`sendCmd`、`sendMessages`、`event.direct` |
|
|
21
|
+
| 群组消息 | 发送文本、语音、命令消息;接收群组 Push | `sendGroupChat`、`sendGroupAudio`、`sendGroupCmd`、`event.group` |
|
|
22
|
+
| 房间消息 | 进入/退出房间,发送文本、语音、命令消息,接收房间 Push | `enterRoom`、`leaveRoom`、`sendRoomChat`、`sendRoomAudio`、`sendRoomCmd`、`event.room` |
|
|
23
|
+
| 广播消息 | 接收广播 Push,查询广播历史和数量 | `event.broadcast`、`getBroadcastMessage`、`getBroadcastChat`、`getBroadcastMessageCount` |
|
|
24
|
+
| 群组管理 | 添加/移除成员,查询成员和人数,读取用户所在群组,设置和读取群组资料 | `addGroupMembers`、`deleteGroupMembers`、`getGroupMembers`、`getGroupCount`、`getUserGroups`、`setGroupInfo`、`getGroupInfo` |
|
|
25
|
+
| 房间管理 | 批量进入房间,查询房间成员/人数/资料,读取用户所在房间 | `enterRooms`、`getRoomMembers`、`getRoomCount`、`getUserRooms`、`setRoomInfo`、`getRoomInfo` |
|
|
26
|
+
| 历史消息 | 按时间和游标分页,按消息 ID 定位,统计消息数量 | `getP2PMessage`、`getGroupMessage`、`getRoomMessage`、`getBroadcastMessage`、`get*MessageByMessageId`、`get*MessageCount` |
|
|
27
|
+
| 单条消息管理 | 获取单条消息和撤回消息 | `getMessage`、`deleteMessage`、`getChat`、`deleteChat` |
|
|
28
|
+
| 收件箱同步 | 查询未读、清除未读、读取会话、标记会话已读、删除本地会话、读取会话列表 | `getUnreadMessage`、`cleanUnreadMessage`、`getSession`、`setSessionRead`、`removeSession`、`get*ConversationList` |
|
|
29
|
+
| 文本服务 | 文本审核、文本翻译、按用户设置翻译语言 | `textCheck`、`translate`、`setTranslationLanguage` |
|
|
30
|
+
| 文件消息 | 获取上传凭证和 endpoint,发送一对一/群组/房间文件 | `fileToken`、`sendFile`、`sendGroupFile`、`sendRoomFile` |
|
|
31
|
+
| 设备与好友 | 维护设备 Push 信息,维护好友关系 | `addDevice`、`removeDevice`、`getDevicePushOption`、`addFriends`、`deleteFriends`、`getFriends` |
|
|
32
|
+
| 多媒体内容服务 | 敏感词处理、图片/音频/视频审核、语音转文字 | `profanity`、`imageCheck`、`audioCheck`、`videoCheck`、`speech2Text` |
|
|
33
|
+
|
|
34
|
+
## 协议与能力入口
|
|
35
|
+
|
|
36
|
+
| 入口 | 适合场景 | 主要能力 |
|
|
37
|
+
| --- | --- | --- |
|
|
38
|
+
| `protocol: 'tlv-v1'` | 新项目、浏览器和 Node.js 接入 | 连接鉴权、用户与存储、黑名单、用户/群组/房间/广播消息、可靠 Push、历史、未读、会话、文本审核、翻译。 |
|
|
39
|
+
| `protocol: 'fpnn'` | 现有浏览器 RTM 应用的兼容接入 | 兼容 SDK 的完整传统 API 族,包括文件、设备、好友和多媒体内容服务。 |
|
|
40
|
+
|
|
41
|
+
### 协议与运行边界
|
|
42
|
+
|
|
43
|
+
| 能力 | `RTMClient` + TLV v1 | `RTMClient` + FPNN | `RTMSharedWorkerClient` |
|
|
44
|
+
| --- | --- | --- | --- |
|
|
45
|
+
| 连接环境 | 浏览器;Node.js 需传入 `webSocketFactory` | 浏览器 | 支持 SharedWorker 的浏览器,同源页面 |
|
|
46
|
+
| 用户/群组/房间/广播消息 | 支持;按 TLV v1 契约字段校验 | 支持兼容 API | 沿用所选协议已开放 API(文件发送除外) |
|
|
47
|
+
| Push ACK 与去重 | SDK 自动 ACK 可靠 Push,并按 `message_ref` 去重 | 沿用兼容实现 | 单条共享连接只 ACK 一次,再按页面会话路由给各端口 |
|
|
48
|
+
| 文件、设备、好友、多媒体审核 | TLV v1 当前未开放的传统 API 不可用 | 兼容 API 可用,依赖对应服务端能力 | 两种模式都不支持文件发送;FPNN 设备/好友/审核可转发,TLV 按其支持范围 |
|
|
49
|
+
| 多页面连接共享 | 每个 `RTMClient` 实例各自管理连接 | 每个 `RTMClient` 实例各自管理连接 | 相同协议、Worker identity 与配置下,同一 UID 共用一条连接 |
|
|
50
|
+
| 业务 UI 与消息存储 | 应用负责展示、缓存和历史补拉 | 应用负责展示、缓存和历史补拉 | 只路由实时 Push;不跨页同步草稿、未读 UI 状态或本地消息列表,也不持久化消息 |
|
|
51
|
+
|
|
52
|
+
TLV v1 的能力以 [Client API 契约](TLV_CONTRACT.md) 的 URI 表为准;旧 API 名称存在不代表 TLV 服务端开放了该 wire。保留但未开放的 wire 返回 `200020`(`RTM_EC_FORBIDDEN_METHOD`);未知且未登记的 wire 返回 `20004`(`RTM_EC_UNKNOWN_METHOD`)。`RTMSharedWorkerClient` 的文件发送方法在本地拒绝:callback 收到 `{mid, error}`,Promise 版本 reject 同一对象,`error.code` 为 `200999`(`RTM_EC_UNKNOWN_ERROR`),不发送 wire 请求。以上情况均不会退回 FPNN。SharedWorker 不是另一套 RTC 协议,也不替业务服务端签发 credential。
|
|
53
|
+
|
|
54
|
+
### SharedWorker 共享范围
|
|
55
|
+
|
|
56
|
+
- SDK 会默认从加载它的页面脚本同目录定位 `rtm.shared-worker.js`;Vite 项目可从 `@cg-devcenter/rtc-fpnn-webjs-sdk/vite` 导入 ESM 入口,由 SDK 自动将 Worker 作为构建资源配置给客户端。部署时 Worker 必须在页面同源下可访问;非 Vite 自定义部署路径时可显式提供 `workerUrl`。
|
|
57
|
+
- 共享键由浏览器 origin、Worker URL、Worker 名称和完全相同的 `clientOptions` 共同决定;这些值不同的页面不会共用连接。
|
|
58
|
+
- 支持 `clientOptions.protocol: 'tlv-v1'` 或 `'fpnn'`,默认仍为 TLV;FPNN 扩展目前为源码/本地构建能力,已发布 `.3` 尚不包含它。同 UID 使用不同协议会建立独立连接。
|
|
59
|
+
- 一个 Worker 只登录一个 UID。不同 UID 同时在线必须分别建立 Worker/RTC 连接;单 UID 的多页面共享登录态。
|
|
60
|
+
- 每个页面有独立的 Push 监听端口。配置 `conversation` 后,SDK 按所选协议提取 direct sender、group ref 或 room ref 后过滤,保留原协议事件名和数据;未配置时该页面接收全部会话 Push。
|
|
61
|
+
- SDK 负责连接、重连、Push ACK/去重和端口分发;业务仍负责消息展示、历史补拉、业务未读规则、草稿与页面状态。
|
|
62
|
+
- 登录态保存在 Worker 内存。Worker 被浏览器回收或空闲回收完成后,需要业务重新创建 client 并登录;SDK 不持久化 credential,也不承诺把断线期间未投递的 Push 自动补齐。
|
|
63
|
+
- `destroy()` 只 detach 当前页面;最后一个页面 detach 后默认等待 5 秒再销毁共享 RTMClient,期间有新页面接入会取消回收。可通过 `idleShutdownTimeout` 调整,设为 0 表示立即关闭;同一个 Worker 的页面须使用相同值。`bye()` / `close()` 会结束所有共用页面的 RTC 会话。共享 Worker 初始化失败时不会静默降级为每页单独连接。
|
|
64
|
+
|
|
65
|
+
TLV v1 使用 MessagePack 二进制 WebSocket frame。SDK 提供以下基础模块:
|
|
66
|
+
|
|
67
|
+
- `RTMClient`:面向业务的登录、消息、群组、房间、历史和会话 API。
|
|
68
|
+
- `RTMProcessor`:接收并分发 Push;通过 `client.processor.on(name, callback)` 订阅事件。
|
|
69
|
+
- `TLVCodec`:编解码 TLV frame、Answer、Push 和 MessagePack body。
|
|
70
|
+
- `TLVWebSocketClient`:管理 TLV WebSocket 请求、响应、心跳和连接状态。
|
|
71
|
+
- `RTMConfig`:提供 `Int64`、消息类型、文件类型和 Push 名称常量。
|
|
72
|
+
|
|
73
|
+
## 典型业务流程
|
|
74
|
+
|
|
75
|
+
### Callback 与 Promise 写法
|
|
76
|
+
|
|
77
|
+
为兼容既有应用,`RTMClient` 和 `RTMSharedWorkerClient` 保留 callback 方法;两者也提供 `client.promises`,把所有 callback 型业务请求封装为 Promise。原方法参数顺序不变,只省略 callback:
|
|
78
|
+
|
|
79
|
+
```js
|
|
80
|
+
const result = await client.promises.sendChat(peerUid, 'hello', '{}', 0, 12000);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`client.promises.login(uid, credential, timeout?)` 成功时 resolve `{ accepted: true, errorCode }`,鉴权失败时 reject 一个带 `code` 的 Error。TLV Gate 返回 `control.error` 时保留服务端错误码;若只返回 `accepted: false`,SDK 使用 `200027`。`client.promises.bye(timeout?)` 等待 Gate 应答协议关闭;TLV 请求失败时 SDK 主动关闭连接。`RTMSharedWorkerClient.loginIfNeeded()` 保持自己的结果约定:RTC 鉴权结果 resolve 为 `{ accepted, errorCode, reused, uid }`;Worker 初始化错误及缺少首次登录 credential 会 reject。其他生命周期方法和事件仍通过 client 本身调用。
|
|
84
|
+
|
|
85
|
+
### 一对一聊天
|
|
86
|
+
|
|
87
|
+
1. 构造 `RTMClient`,注册 `ErrorRecorder` 和 `event.direct` Push 监听。
|
|
88
|
+
2. 调用 `login` 进入登录态。
|
|
89
|
+
3. 使用 `sendChat`、`sendAudio` 或 `sendCmd` 发送消息。
|
|
90
|
+
4. 在 `event.direct` 回调中接收对方消息;SDK 自动回复可靠 Push 的 `control.ack` 并按 `message_ref` 去重。
|
|
91
|
+
5. 使用 `getP2PMessage` 或 `getP2PConversationList` 加载历史和会话摘要。
|
|
92
|
+
|
|
93
|
+
### 群组与房间互动
|
|
94
|
+
|
|
95
|
+
群组流程使用 `addGroupMembers`、`getGroupMembers` 和 `sendGroupChat` 管理成员与消息;房间流程使用 `enterRoom`、`getRoomMembers` 和 `sendRoomChat` 管理在线参与者与消息。两类消息分别通过 `event.group` 和 `event.room` 接收。
|
|
96
|
+
|
|
97
|
+
### 登录后的收件箱同步
|
|
98
|
+
|
|
99
|
+
应用恢复到前台或完成重新登录后,可以组合使用:
|
|
100
|
+
|
|
101
|
+
1. `getUnreadMessage` 获取未读范围;
|
|
102
|
+
2. `getP2PUnreadConversationList`、`getGroupUnreadConversationList` 或 `getUnreadConversationList` 获取会话摘要;
|
|
103
|
+
3. `getP2PMessage`、`getGroupMessage` 或 `getRoomMessage` 分页读取历史;
|
|
104
|
+
4. `setSessionRead` 标记已读,必要时使用 `cleanUnreadMessage` 清理全局未读状态。
|
|
105
|
+
|
|
106
|
+
### 发送前的内容处理
|
|
107
|
+
|
|
108
|
+
发送文本前可先调用 `textCheck` 获取审核结果,再根据业务策略调用 `translate` 生成目标语言内容,最后使用 `sendChat`、`sendGroupChat` 或 `sendRoomChat` 发送。审核和翻译的请求字段、返回结构见 [TLV v1 Client API 契约](TLV_CONTRACT.md)。
|
|
109
|
+
|
|
110
|
+
### 文件消息
|
|
111
|
+
|
|
112
|
+
文件消息可以使用 `fileToken` 获取上传所需的 token 和 endpoint,再调用 `sendFile`、`sendGroupFile` 或 `sendRoomFile` 完成消息发送;接收方通过对应的文件 Push 获取文件地址和消息元数据。
|
|
113
|
+
|
|
114
|
+
## 核心数据约定
|
|
115
|
+
|
|
116
|
+
- **ID 与时间**:用户 ID、群组 ID、房间 ID、消息引用和时间游标可能超过 JavaScript 安全整数范围,使用 `new RTMConfig.Int64(String(value))` 传入和读取。
|
|
117
|
+
- **消息类型**:`RTMConfig.CHAT_TYPE.text`、`audio`、`cmd` 分别对应文本、语音和命令消息。
|
|
118
|
+
- **文件类型**:文件消息的类型使用 `RTMConfig.FILE_TYPE` 中的 image、audio、video、file。
|
|
119
|
+
- **普通回调**:大多数业务 API 使用 `callback(err, data)`;发送 API 成功结果包含 `message_ref` 和 `payload`。
|
|
120
|
+
- **登录回调**:`login` 使用 `callback(accepted, errorCode)`;连接、协议和登录错误可通过 `ErrorRecorder` 观察。普通业务 API 的 Gate 错误由对应的 `callback(err, data)` 或 Promise rejection 返回,不会另发全局事件。
|
|
121
|
+
- **TLV Push**:应用通过 `RTMConfig.TLV_SERVER_PUSH` 取得 `event.direct`、`event.group`、`event.room`、`event.broadcast`、`event.kicked` 和 `event.room_removed` 的订阅名称。
|
|
122
|
+
|
|
123
|
+
## 文档导航
|
|
124
|
+
|
|
125
|
+
- [快速开始与引用](../README.md)
|
|
126
|
+
- [公开 API 参数](USAGE.md)
|
|
127
|
+
- [FPNN 与 TLV v1 迁移对照](PROTOCOL_MIGRATION.md)
|
|
128
|
+
- [TLV v1 URI、字段和返回值](TLV_CONTRACT.md)
|
|
129
|
+
- [TLV v1 frame 与编解码](TLV.md)
|
|
130
|
+
- [在线验证与业务套件](TLV_LIVE_E2E_TEST.md)
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# FPNN 与 TLV v1 协议迁移对照
|
|
2
|
+
|
|
3
|
+
本文说明如何在现有 `RTMClient` 接入中选择 FPNN 或 TLV v1,并对照 SDK 业务 API、旧 FPNN wire method 与 TLV URI。
|
|
4
|
+
|
|
5
|
+
## 先看结论
|
|
6
|
+
|
|
7
|
+
- `RTMClient` 是两种协议共用的业务 API 门面。TLV v1 已实现的接口由 SDK 在内部把旧 method 和字段转换成 TLV URI 与字段;业务代码不需要自己发送 TLV frame,也不应直接调用这些 wire 名称。
|
|
8
|
+
- 协议在创建客户端时选择:`protocol: 'fpnn'` 或 `protocol: 'tlv-v1'`。一个客户端实例不会按请求混用两种协议。
|
|
9
|
+
- 业务 API 名称和调用方式在支持范围内保持一致,但这不保证每个返回对象、错误对象、服务端权限或业务语义都完全相同。切换前请对照本页的差异说明和 [TLV v1 Client API 契约](TLV_CONTRACT.md)。
|
|
10
|
+
- TLV v1 未支持的 FPNN API 不会自动回退到 FPNN。完整支持边界见 [接入指南的支持矩阵](USAGE.md#6-tlv-v1-api-支持矩阵)。
|
|
11
|
+
|
|
12
|
+
## 选择协议
|
|
13
|
+
|
|
14
|
+
现有 FPNN 客户端通常使用 `endpoint`(FPNN Gate 地址)创建;保留这套配置时显式指定 `protocol: 'fpnn'`,或依赖兼容默认值:
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
const client = new rtm.RTMClient({
|
|
18
|
+
protocol: 'fpnn',
|
|
19
|
+
pid,
|
|
20
|
+
endpoint: fpnnEndpoint,
|
|
21
|
+
});
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
迁移到 TLV v1 时,将连接地址换成部署方提供的完整 WebSocket URL,并在创建时选择 TLV:
|
|
25
|
+
|
|
26
|
+
```js
|
|
27
|
+
const client = new rtm.RTMClient({
|
|
28
|
+
protocol: 'tlv-v1',
|
|
29
|
+
pid,
|
|
30
|
+
tlvEndpoint: 'wss://<gate-host>/service/websocket',
|
|
31
|
+
autoReconnect: true,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
await client.promises.login(uid, credential);
|
|
35
|
+
await client.promises.sendChat(peerUid, 'hello', '{}');
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`credential` 仍须由业务服务端或受控签发工具为当前 UID 签发。不要把项目 `SecretKey` 放入浏览器。其余连接、登录、发送、监听 Push 的业务调用可以继续使用同一套 `RTMClient` API;若使用 `RTMSharedWorkerClient`,默认仍为 TLV v1,当前源码也支持显式选择 FPNN;已发布 `.3` 仅支持 TLV。SharedWorker 配置和能力边界见 [FPNN 多窗口接入](USAGE.md#fpnn-多窗口接入)。
|
|
39
|
+
|
|
40
|
+
## API 与 wire 名称对照
|
|
41
|
+
|
|
42
|
+
“FPNN method”列是 SDK 内部兼容接口使用的旧请求 method 名称,用于帮助查旧 FPNN 文档和服务端日志。它不是 TLV 请求名,也不是建议业务直接调用的 API。TLV 连接实际发送右侧的 URI。
|
|
43
|
+
|
|
44
|
+
### 连接、用户与存储
|
|
45
|
+
|
|
46
|
+
| RTMClient 业务 API | FPNN method | TLV v1 URI |
|
|
47
|
+
| --- | --- | --- |
|
|
48
|
+
| `login` | `auth` | `auth.login` |
|
|
49
|
+
| `bye` | `bye` | `connection.close` |
|
|
50
|
+
| `getServerTime` | `getservertime` | `system.time` |
|
|
51
|
+
| `addAttrs` / `getAttrs` | `addattrs` / `getattrs` | `connection.set_props` / `connection.get_props` |
|
|
52
|
+
| `addDebugLog` | `adddebuglog` | `system.debug` |
|
|
53
|
+
| `getOnlineUsers` | `getonlineusers` | `presence.online` |
|
|
54
|
+
| `setUserInfo` / `getUserInfo` | `setuserinfo` / `getuserinfo` | `user.set_profile` / `user.get_profile` |
|
|
55
|
+
| `getUserOpenInfo` | `getuseropeninfo` | `user.get_public` |
|
|
56
|
+
| `setTranslationLanguage` | `setlang` | `user.set_locale` |
|
|
57
|
+
| `dataGet` / `dataSet` / `dataDelete` | `dataget` / `dataset` / `datadel` | `storage.get` / `storage.set` / `storage.delete` |
|
|
58
|
+
| `addBlacks` / `deleteBlacks` / `getBlacks` | `addblacks` / `delblacks` / `getblacks` | `blacklist.add` / `blacklist.remove` / `blacklist.list` |
|
|
59
|
+
|
|
60
|
+
### 群组与房间
|
|
61
|
+
|
|
62
|
+
| RTMClient 业务 API | FPNN method | TLV v1 URI |
|
|
63
|
+
| --- | --- | --- |
|
|
64
|
+
| `addGroupMembers` / `deleteGroupMembers` | `addgroupmembers` / `delgroupmembers` | `group.add` / `group.remove` |
|
|
65
|
+
| `getGroupMembers` / `getGroupCount` | `getgroupmembers` / `getgroupcount` | `group.members` / `group.count` |
|
|
66
|
+
| `getUserGroups` | `getusergroups` | `group.joined` |
|
|
67
|
+
| `setGroupInfo` / `getGroupInfo` | `setgroupinfo` / `getgroupinfo` | `group.set_profile` / `group.get_profile` |
|
|
68
|
+
| `getGroupOpenInfo` / `getGroupsOpenInfo` | `getgroupopeninfo` / `getgroupsopeninfo` | `group.get_public` / `group.get_public_batch` |
|
|
69
|
+
| `enterRoom` / `leaveRoom` / `enterRooms` | `enterroom` / `leaveroom` / `enterrooms` | `room.join` / `room.leave` / `room.join_batch` |
|
|
70
|
+
| `getUserRooms` / `getRoomMembers` / `getRoomCount` | `getuserrooms` / `getroommembers` / `getroomcount` | `room.joined` / `room.members` / `room.counts` |
|
|
71
|
+
| `setRoomInfo` / `setRoomProfile` | `setroominfo` | `room.set_profile` |
|
|
72
|
+
| `getRoomInfo` / `getRoomOpenInfo` / `getRoomsOpenInfo` | `getroominfo` / `getroomopeninfo` / `getroomsopeninfo` | `room.get_profile` / `room.get_public` / `room.get_public_batch` |
|
|
73
|
+
| `getUserRoomsAndLastMessage` | `getuserroomsandlastmsg` | `room.last_messages` |
|
|
74
|
+
|
|
75
|
+
### 消息、审核、翻译与历史
|
|
76
|
+
|
|
77
|
+
| RTMClient 业务 API | FPNN method | TLV v1 URI |
|
|
78
|
+
| --- | --- | --- |
|
|
79
|
+
| `sendMessage`、`sendChat`、`sendAudio`、`sendCmd` | `sendmsg` | `message.send` |
|
|
80
|
+
| `sendMessages` | `sendmsgs` | `message.send_batch` |
|
|
81
|
+
| `sendGroupMessage`、`sendGroupChat`、`sendGroupAudio`、`sendGroupCmd` | `sendgroupmsg` | `message.send_group` |
|
|
82
|
+
| `sendRoomMessage`、`sendRoomChat`、`sendRoomAudio`、`sendRoomCmd` | `sendroommsg` | `message.send_room` |
|
|
83
|
+
| `textCheck` | `tcheck` | `moderation.check` |
|
|
84
|
+
| `translate` | `translate` | `translation.run` |
|
|
85
|
+
| `getP2PMessage` / `getP2PChat` | `getp2pmsg` | `history.direct` |
|
|
86
|
+
| `getGroupMessage` / `getGroupChat` | `getgroupmsg` | `history.group` |
|
|
87
|
+
| `getRoomMessage` / `getRoomChat` | `getroommsg` | `history.room` |
|
|
88
|
+
| `getBroadcastMessage` / `getBroadcastChat` | `getbroadcastmsg` | `history.broadcast` |
|
|
89
|
+
| `getP2PMessageByMessageId` / `getGroupMessageByMessageId` | `getp2pmsgbymessageid` / `getgroupmsgbymessageid` | `history.direct_anchor` / `history.group_anchor` |
|
|
90
|
+
| `getRoomMessageByMessageId` / `getBroadcastMessageByMessageId` | `getroommsgbymessageid` / `getbroadcastmsgbymessageid` | `history.room_anchor` / `history.broadcast_anchor` |
|
|
91
|
+
| `getP2PMessageCount` / `getGroupMessageCount` | `getp2pmsgcount` / `getgroupmsgcount` | `history.direct_count` / `history.group_count` |
|
|
92
|
+
| `getRoomMessageCount` / `getBroadcastMessageCount` | `getroommsgcount` / `getbroadcastmsgcount` | `history.room_count` / `history.broadcast_count` |
|
|
93
|
+
| `getMessage` / `getChat` | `getmsg` | `message.get` |
|
|
94
|
+
| `deleteMessage` / `deleteChat` | `delmsg` | `message.revoke` |
|
|
95
|
+
|
|
96
|
+
### 未读、会话与会话列表
|
|
97
|
+
|
|
98
|
+
| RTMClient 业务 API | FPNN method | TLV v1 URI |
|
|
99
|
+
| --- | --- | --- |
|
|
100
|
+
| `getUnreadMessage` | `getunread` | `unread.summary` |
|
|
101
|
+
| `getSession` | `getsession` | `session.list` |
|
|
102
|
+
| `cleanUnreadMessage` | `cleanunread` | `unread.clear` |
|
|
103
|
+
| `setSessionRead` | `setsessionread` | `session.read` |
|
|
104
|
+
| `getP2PUnreadMessageNum` / `getGroupUnreadMessageNum` | `getp2punread` / `getgroupunread` | `unread.direct` / `unread.group` |
|
|
105
|
+
| `removeSession` | `removesession` | `session.remove` |
|
|
106
|
+
| `getP2PConversationList` / `getP2PUnreadConversationList` | `getp2pconversationlist` / `getp2punreadconversationlist` | `conversation.direct` / `conversation.direct_unread` |
|
|
107
|
+
| `getGroupConversationList` / `getGroupUnreadConversationList` | `getgroupconversationlist` / `getgroupunreadconversationlist` | `conversation.group` / `conversation.group_unread` |
|
|
108
|
+
| `getUnreadConversationList` | `getunreadconversationlist` | `conversation.unread` |
|
|
109
|
+
|
|
110
|
+
### 服务端 Push 事件
|
|
111
|
+
|
|
112
|
+
两种协议的 Push 名称和字段也不同。按所选协议使用对应的 `RTMConfig` 常量订阅;不要把常量的字符串值写死在业务代码里。
|
|
113
|
+
|
|
114
|
+
| Push 场景 | FPNN 事件名 | TLV v1 事件名 | TLV 常量 |
|
|
115
|
+
| --- | --- | --- | --- |
|
|
116
|
+
| 一对一消息 | `pushmsg` | `event.direct` | `RTMConfig.TLV_SERVER_PUSH.recvMessage` |
|
|
117
|
+
| 群组消息 | `pushgroupmsg` | `event.group` | `RTMConfig.TLV_SERVER_PUSH.recvGroupMessage` |
|
|
118
|
+
| 房间消息 | `pushroommsg` | `event.room` | `RTMConfig.TLV_SERVER_PUSH.recvRoomMessage` |
|
|
119
|
+
| 广播消息 | `pushbroadcastmsg` | `event.broadcast` | `RTMConfig.TLV_SERVER_PUSH.recvBroadcastMessage` |
|
|
120
|
+
| 当前账号被踢下线 | `kickout` | `event.kicked` | `RTMConfig.TLV_SERVER_PUSH.kickOut` |
|
|
121
|
+
| 从房间移除 | `kickoutroom` | `event.room_removed` | `RTMConfig.TLV_SERVER_PUSH.kickOutRoom` |
|
|
122
|
+
|
|
123
|
+
## 切换时要核对的差异
|
|
124
|
+
|
|
125
|
+
### 参数与返回字段
|
|
126
|
+
|
|
127
|
+
TLV URI 使用自己的字段名和 schema。例如 FPNN `sendmsg` 的 `to / mid / mtype / msg / attrs` 在 TLV `message.send` 中映射为 `recipient / message_ref / kind / payload / extra`;历史查询的 `begin / end / lastid / num / desc` 映射为 `start_ms / end_ms / cursor / limit / reverse`。SDK 执行映射,业务代码仍传 `RTMClient` 方法参数。各 URI 的字段、类型、默认值和 Gate Answer 见 [TLV v1 Client API 契约](TLV_CONTRACT.md)。
|
|
128
|
+
|
|
129
|
+
Push 事件也有协议差异:名称见上表,事件字段与 FPNN wire payload 不完全相同。业务侧应依照当前协议订阅并按契约处理事件;不要将 FPNN Push 字段表直接套用到 TLV。FPNN 订阅名见 [事件处理说明](EventProcess.md),TLV Push 字段见 [TLV v1 Client API 契约](TLV_CONTRACT.md#控制-uri-与-push)。
|
|
130
|
+
|
|
131
|
+
### API 支持范围
|
|
132
|
+
|
|
133
|
+
`protocol: 'tlv-v1'` 只覆盖 [TLV v1 支持矩阵](USAGE.md#6-tlv-v1-api-支持矩阵)中标为支持的 API。常见未开放项包括文件(`filetoken`、`sendfile` 等)、好友(`addfriends`、`getfriends`)、设备 Push 设置、多媒体审核,以及传统 RTM 房间控制类接口。调用未开放 wire 不会切换到 FPNN:保留但未开放的 wire 会返回 `200020`,未知 wire 会返回 `20004`;SharedWorker 文件发送在本地拒绝。错误细节见 [能力总览](CAPABILITIES.md#协议与能力入口) 和支持矩阵。
|
|
134
|
+
|
|
135
|
+
### 登录与错误处理
|
|
136
|
+
|
|
137
|
+
`login` callback 仍按 `(accepted, errorCode)` 判断是否成功;Promise 登录失败会 reject。TLV 的具体鉴权错误码和仅收到拒绝应答时的默认错误码见 [接入指南错误约定](USAGE.md#callbackpromise-与错误)。TLV 消息发送失败的错误对象结构也有专门约定,不要假设所有协议的业务错误都有同一种形状。
|
|
138
|
+
|
|
139
|
+
**发布前应按业务实际使用的 API 做回归验证**:登录/重连、消息收发与 Push、历史分页、未读/会话查询、业务错误处理及服务端权限。成功建立连接不代表 Gate 已开放所有 URI。
|
|
140
|
+
|
|
141
|
+
## 相关文档
|
|
142
|
+
|
|
143
|
+
- [TLV v1 接入指南与 API 参数](USAGE.md)
|
|
144
|
+
- [TLV v1 API、字段与返回值契约](TLV_CONTRACT.md)
|
|
145
|
+
- [SDK 能力与协议边界](CAPABILITIES.md)
|
|
146
|
+
- [FPNN 兼容 API 旧说明](Users.md)、[消息](Messages.md)、[聊天](Chat.md)、[群组](Groups.md)、[房间](Rooms.md)
|
package/docs/TLV.md
CHANGED
|
@@ -42,7 +42,7 @@ TLV v1 使用 MessagePack over WebSocket。公开方法见 [SDK API](USAGE.md)
|
|
|
42
42
|
|
|
43
43
|
| URI | 请求/响应 body | 行为 |
|
|
44
44
|
| --- | --- | --- |
|
|
45
|
-
| `control.ping` | `{}` / `{}` | SDK
|
|
45
|
+
| `control.ping` | `{}` / `{ts?:int64}` | SDK 空闲心跳;Gate 可在 Answer 中返回时间戳。 |
|
|
46
46
|
| `control.ack` | `{}` | 复用可靠 Push sequence;无需应答。 |
|
|
47
47
|
| `control.error` | `{status:int32, reason:string}` | Gate 请求失败应答。 |
|
|
48
48
|
| `connection.close` | `{}` / `{}` | Gate 应答后关闭连接。 |
|
package/docs/TLV_CONTRACT.md
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
|
|
25
25
|
| URI | `mt` | body |
|
|
26
26
|
| --- | --- | --- |
|
|
27
|
-
| `control.ping` | `'1'` / `'2'` | `{}` |
|
|
27
|
+
| `control.ping` | `'1'` / `'2'` | request `{}`; Answer `{ts?:i64}` |
|
|
28
28
|
| `control.ack` | `'2'` | `{}` |
|
|
29
29
|
| `control.error` | `'2'` | `{status:i32, reason:str}` |
|
|
30
30
|
| `event.direct` | `'1'` | `recipient, sender, message_ref, kind, payload, extra, time_ms` |
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
|
|
42
42
|
| SDK API | Gate URI | 请求字段 | Gate Answer |
|
|
43
43
|
| --- | --- | --- | --- |
|
|
44
|
-
| `login` | `auth.login` | `project, user, credential, client_ver, auth_sec?, auth_ver?, locale?, props?` | `accepted
|
|
44
|
+
| `login` | `auth.login` | `project, user, credential, client_ver, auth_sec?, auth_ver?, locale?, props?` | `accepted, telemetry_on?` |
|
|
45
45
|
| `bye` | `connection.close` | 无 | 无 |
|
|
46
46
|
| `getServerTime` | `system.time` | 无 | `server_ms` |
|
|
47
47
|
| `addAttrs` | `connection.set_props` | `props` | 无 |
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# TLV v1 在线验证页面
|
|
2
|
+
|
|
3
|
+
验证页面位于 `test/e2e/live-tlv-suite.html`。它用于验证一个真实 TLV Gate 环境与 SDK 的联调结果,不替代本地协议测试或 npm 包 smoke test。页面只接受运行时输入,不内置环境参数、项目密钥或 credential。
|
|
4
|
+
|
|
5
|
+
## 前置条件
|
|
6
|
+
|
|
7
|
+
- 能访问目标 TLV WebSocket endpoint,并准备好对应的 RTC `pid`。
|
|
8
|
+
- 准备两个不同的、正整数 UID,以及服务端签发给这两个 UID 的有效 credential。
|
|
9
|
+
- 如需验证群组流程,准备一个已存在且 UID A 有成员管理权限的 Group ID。
|
|
10
|
+
- 如需把黑名单、文本审核和翻译作为强制能力验证,勾选页面上的“要求黑名单、文本审核和翻译能力通过”。
|
|
11
|
+
- 浏览器需要支持 WebSocket、`TextEncoder` 和 `TextDecoder`。
|
|
12
|
+
|
|
13
|
+
credential 应从服务端鉴权流程取得,不要把项目密钥放进浏览器页面、URL 或 `requestMetadata`。
|
|
14
|
+
|
|
15
|
+
## 启动页面
|
|
16
|
+
|
|
17
|
+
页面通过相对路径加载仓库内的 `dist/rtm.min.js`,所以应从仓库根目录启动 HTTP 服务,不能直接使用 `file://` 打开:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
cd ~/Documents/code/origin/rtm-client-sdk-websocket
|
|
21
|
+
|
|
22
|
+
# 只有在 dist 需要由当前源码重新生成时才执行;依赖未安装时先执行 npm install
|
|
23
|
+
npm install
|
|
24
|
+
npm run build
|
|
25
|
+
|
|
26
|
+
python3 -m http.server 8000
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
然后打开:
|
|
30
|
+
|
|
31
|
+
```text
|
|
32
|
+
http://127.0.0.1:8000/test/e2e/live-tlv-suite.html
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
如果只是验证仓库当前已提交的 `dist`,可以跳过 `npm install` 和 `npm run build`,直接启动 HTTP 服务。若页面提示 `rtm` 未定义或脚本加载失败,先确认服务根目录是本仓库,而不是 `test/e2e` 目录。
|
|
36
|
+
|
|
37
|
+
## 执行顺序
|
|
38
|
+
|
|
39
|
+
推荐先执行仓库内的本地检查,再执行在线页面:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm run test:unit # TLV 协议与文档链接/覆盖检查
|
|
43
|
+
npm run test:package # 重新构建 dist,并验证 CommonJS 与浏览器 UMD 包入口
|
|
44
|
+
npm test # 以上两组检查的合并入口
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
在线页面按以下顺序运行:
|
|
48
|
+
|
|
49
|
+
1. 点击“运行无凭证 `control.ping`”,确认 WebSocket、TLV frame header、Answer sequence,以及请求空 map 和应答 `{}` / `{ts}` 均正确。
|
|
50
|
+
2. 填写 endpoint、pid、两个 UID 和 credential,点击“运行业务覆盖套件”。
|
|
51
|
+
3. 页面先执行两个 `auth.login`,再执行系统、用户、存储、黑名单、群组、房间、消息、历史、未读、会话、重连和关闭流程。
|
|
52
|
+
4. 页面会清理本次运行写入的存储、黑名单、房间和群成员状态;仍建议使用专用测试账号和测试群组。
|
|
53
|
+
|
|
54
|
+
## 输入
|
|
55
|
+
|
|
56
|
+
| 字段 | 类型 | 必填 | 说明 |
|
|
57
|
+
| --- | --- | --- | --- |
|
|
58
|
+
| `endpoint` | `string` | 是 | TLV WebSocket URL。 |
|
|
59
|
+
| `pid` | `number` | 是 | RTC 项目 ID。 |
|
|
60
|
+
| `uidA` / `credentialA` | `string` | 是 | 第一个 Client 身份;UID 必须是正整数。 |
|
|
61
|
+
| `uidB` / `credentialB` | `string` | 是 | 第二个 Client 身份;必须与 A 不同。 |
|
|
62
|
+
| `groupId` | `string` | 否 | 已配置的群组 ID;填写时 UID A 必须有相应权限。 |
|
|
63
|
+
| `requireCapabilities` | `boolean` | 否 | 要求黑名单、审核、翻译 API 通过;未勾选时这些外部能力可以 `SKIP`。 |
|
|
64
|
+
|
|
65
|
+
## 覆盖范围
|
|
66
|
+
|
|
67
|
+
| 阶段 | 动作 | 协议/API 范围 |
|
|
68
|
+
| --- | --- | --- |
|
|
69
|
+
| P0 | `control.ping` | 无凭证 TLV frame、Answer sequence、请求空 map 和应答 `{}` / `{ts}`。 |
|
|
70
|
+
| A1 | 登录与连接 | `auth.login`、连接属性、`system.time`、自动重连与 `connection.close`。 |
|
|
71
|
+
| U1/B1 | 用户与基础数据 | 在线状态、用户资料、公开资料、语言、存储和黑名单。 |
|
|
72
|
+
| G1/R1 | 群组与房间 | 群组成员/资料/计数、房间加入/退出/成员/资料。配置缺失时群组流程会跳过。 |
|
|
73
|
+
| M1/M2 | 消息与 Push | 单发、批量、群组/房间消息、`event.direct`/`event.group`/`event.room`、ACK 与去重。 |
|
|
74
|
+
| H1/H2/S1 | 读取与会话 | 历史消息、计数、撤回、未读、Session 和 Conversation。 |
|
|
75
|
+
| X1/N1 | 能力与负向契约 | 黑名单能力、文本审核、翻译,以及保留 friend wire 的 `200020` 拒绝。 |
|
|
76
|
+
|
|
77
|
+
可靠 Push 会自动回复 `control.ack`;套件还会检查同一 `message_ref` 不被重复投递。页面使用带时间戳的 marker 写入测试数据,便于从结果中定位本次运行。
|
|
78
|
+
|
|
79
|
+
## 结果判定
|
|
80
|
+
|
|
81
|
+
| 状态 | 含义 |
|
|
82
|
+
| --- | --- |
|
|
83
|
+
| `PASS` | 接口返回、响应字段和协议校验符合契约。 |
|
|
84
|
+
| `FAIL` | 接口调用、响应、Push、协议或超时校验不符合预期;应先看该行错误码和浏览器控制台。 |
|
|
85
|
+
| `SKIP` | 可选群组未配置,或未勾选强制能力时服务没有开放相应外部能力。 |
|
|
86
|
+
|
|
87
|
+
未勾选强制能力时,页面允许以下环境差异产生 `SKIP`:
|
|
88
|
+
|
|
89
|
+
- 黑名单:`200060`。
|
|
90
|
+
- 文本审核或翻译:`200020` 或 `300001`。
|
|
91
|
+
- 未填写 `groupId` 时,群组相关覆盖也会明确标记为 `SKIP`。
|
|
92
|
+
|
|
93
|
+
勾选强制能力后,上述错误会变成 `FAIL`,用于验证目标环境是否真的提供这些能力。`N1 reserved friend wire` 预期收到 `200020`,它是负向协议检查,不是故障。
|
|
94
|
+
|
|
95
|
+
## 排障路径
|
|
96
|
+
|
|
97
|
+
| 现象 | 优先检查 |
|
|
98
|
+
| --- | --- |
|
|
99
|
+
| 页面空白、`rtm` 未定义或脚本 404 | 是否从仓库根目录运行 HTTP 服务;`dist/rtm.min.js` 是否存在;源码有改动时是否重新执行 `npm run build`。 |
|
|
100
|
+
| WebSocket error、`control.ping` 失败或超时 | endpoint 的 scheme/路径、TLS 或反向代理、浏览器网络连通性;在 DevTools 的 Network → WS 查看握手和二进制帧,在 Console 查看协议断开原因。 |
|
|
101
|
+
| `200022` | 请求在登录完成前发送,或连接鉴权状态已失效。先确认 `auth.login` 成功。 |
|
|
102
|
+
| `200024` / `200027` | credential 被拒绝、过期或与 pid/UID 不匹配;重新从服务端获取,不要在页面输出 credential。 |
|
|
103
|
+
| `200020` / `200021` | URI 未开放或权限不足;确认 TLV 能力开关、项目权限和测试账号角色。 |
|
|
104
|
+
| `200034`、`200030` | 字段名/类型/范围或 payload/extra 大小不符合契约;对照 [TLV v1 传输 API](TLV.md) 和 [TLV v1 Client API 契约](TLV_CONTRACT.md)。 |
|
|
105
|
+
| `200053` | `message_ref` 重复;确认测试 marker、重试策略和业务侧 message_ref 生成规则。 |
|
|
106
|
+
| `200999` | 连接、超时或服务端内部错误;结合 `ErrorRecorder`、`SessionClosed` 和浏览器 Network 日志判断发生阶段。 |
|
|
107
|
+
|
|
108
|
+
SDK 调试时可重点观察:
|
|
109
|
+
|
|
110
|
+
- `ErrorRecorder`:查看连接、协议和登录层的 `code/status/reason`,比 `login` 的布尔结果更适合定位环境问题;普通业务请求的 Gate 错误要检查对应 callback 或 Promise rejection。
|
|
111
|
+
- `ReloginCompleted`、`SessionClosed`:判断自动重连是成功、失败还是被服务端关闭。
|
|
112
|
+
- `requestMetadata`:为每个请求附加不含秘密的 `trace` 和 `sent_ms`,用于和 Gate 日志关联。
|
|
113
|
+
- 原始 URI、字段和 frame 编解码问题:对照 [TLV v1 传输 API](TLV.md) 与 [TLV v1 Client API 契约](TLV_CONTRACT.md)。
|
|
114
|
+
|
|
115
|
+
页面会尽量脱敏结果,不保存 UID、credential、项目密钥或运行结果;仍不要把结果页截图或浏览器 Network 导出直接发到公开渠道。
|