feat: add redis cache and fanout support

This commit is contained in:
richjohnrambo
2026-08-25 20:54:03 +08:00
parent 07376c70e3
commit f900a08a01
68 changed files with 3949 additions and 5696 deletions
@@ -0,0 +1,110 @@
# IM 第三方接入本地测试结果
测试日期:2026-08-24
测试环境:本地环境,MySQL `127.0.0.1:3306`,控制库 `hotgo`,业务库 `tinode`。
## 1. 测试结论
| 项 | 结果 | 说明 |
| --- | --- | --- |
| 第三方相关普通单元测试 | 通过 | OSS、文件安全配置、阿里云内容安全封装测试通过 |
| MySQL build tag 单元测试 | 通过 | 文件审核表结构、MySQL 适配相关测试通过 |
| 本地 API handler 测试 | 通过 | 群文件、群邀请接受、实名申诉、组织成员、月报 reopen、反馈/举报、信箱、会话设置、云草稿等接口级测试通过 |
| 本地 MySQL 连通性 | 通过 | 可连接 `hotgo` 与 `tinode` |
| 第三方配置读取 | 通过 | `im_third_party` 配置存在 18 条,已按本地第三方依赖配置启用 OSS、内容审核和恶意文件检测 |
| 文件审核字典 | 通过 | provider 2 条、task type 2 条、status 5 条 |
| 文件审核任务表 | 通过 | `tinode.im_file_review_tasks` 存在,且不包含 `tenant_id` |
| 真实 OSS 上传/下载 | 通过 | 使用普通 Bucket endpoint 完成 put/get/sign URL,并清理测试对象 |
| 真实内容安全 | 通过 | 使用阿里云内容安全增强版 `FileModeration + document_detection` 提交并轮询,返回 `clean/none` |
| 真实恶意文件检测 | 阻塞 | SDK 请求 `tds.aliyuncs.com` 时本地网络连接被 reset,`curl` 直连同样失败 |
## 2. 执行命令
```bash
go test -count=1 ./server/media/oss ./server/filesafety ./server/filesafety/aliyun ./server/db/mysql
go test -count=1 -tags mysql ./server/media/oss ./server/filesafety ./server/filesafety/aliyun ./server/db/mysql
go test -count=1 ./server -run 'TestServeIM(GroupFiles|GroupInvitationAccept|RealNameAppeal|OrganizationMembers|MonthlyReportReopen|DailyReport|MonthlyReport|Mailbox|Feedback|Abuse|ConversationSettings|TopicDraft|P2PConversation|ForwardTargets)'
```
## 3. 命令结果
| 命令 | 结果 |
| --- | --- |
| `go test -count=1 ./server/media/oss ./server/filesafety ./server/filesafety/aliyun ./server/db/mysql` | 通过 |
| `go test -count=1 -tags mysql ./server/media/oss ./server/filesafety ./server/filesafety/aliyun ./server/db/mysql` | 通过 |
| `go test -count=1 ./server -run ...` | 通过 |
## 4. 本地数据库核验
| 核验项 | 结果 |
| --- | --- |
| MySQL ping | 通过 |
| `hotgo` 数据库 | 存在 |
| `tinode` 数据库 | 存在 |
| `hotgo.hg_sys_config` 中 `im_third_party` 配置数量 | 18 |
| `oss_enabled` | 1 |
| `file_review_content_enabled` | 1 |
| `file_review_malware_enabled` | 1 |
| OSS 敏感配置 | 已配置,报告不输出具体值 |
| 阿里云审核敏感配置 | 已配置,报告不输出具体值 |
| `im_file_review_provider` 字典 | 2 条 |
| `im_file_review_task_type` 字典 | 2 条 |
| `im_file_review_status` 字典 | 5 条 |
| `tinode.im_file_review_tasks` | 存在 |
| `im_file_review_tasks.tenant_id` | 不存在,符合租户分库方案 |
| `im_file_review_tasks` 当前记录数 | 0 |
## 5. 覆盖情况
| 测试范围 | 本次覆盖 | 结果 |
| --- | --- | --- |
| OSS 配置读取与对象路径规则 | 已覆盖单元测试 | 通过 |
| `im_third_party` 配置读取 | 已覆盖单元测试和本地库只读核验 | 通过 |
| `im_file_review_tasks` 表结构 | 已覆盖 MySQL tag 测试和本地库只读核验 | 通过 |
| 上传完成创建审核任务 | 已覆盖代码路径和表结构测试;本地无真实上传任务 | 部分通过 |
| 群文件 API handler | 已覆盖本地 handler 测试 | 通过 |
| 举报/反馈/信箱附件相关 API handler | 已覆盖本地 handler 测试 | 通过 |
| 日报/月报附件相关 API handler | 已覆盖本地 handler 测试 | 通过 |
| P2P 会话、会话设置、云草稿 | 已覆盖本地 handler 测试 | 通过 |
| 真实 OSS API | 已上传、读取、生成签名 URL、清理测试对象 | 通过 |
| 真实内容安全 API | 已提交 OSS 文件审核并轮询结果 | 通过 |
| 真实恶意文件检测 API | 已使用官方 SAS SDK 提交检测,受本地网络限制未到达服务端 | 阻塞 |
| 风险审核结果影响下载/展示 | worker 和策略闭环未完成 | 未执行 |
## 6. 真实第三方调用补测
补测时间:2026-08-24
### 6.1 补测操作
1. 从本地第三方依赖文档读取测试账号、OSS Bucket 和地域信息。
2. 将本地 `hotgo.hg_sys_config` 的 `im_third_party` 配置更新为启用状态。
3. 使用普通 Bucket endpoint `oss-cn-shenzhen.aliyuncs.com` 上传测试 TXT 文件。
4. 对同一 OSS 对象执行读取、签名 URL 生成和测试对象清理。
5. 使用阿里云内容安全增强版 `FileModeration + document_detection` 提交该 OSS 对象并轮询结果。
6. 使用阿里云云安全中心官方 SAS SDK 调用 `CreateFileDetect` 和 `GetFileDetectResult`。
### 6.2 补测结果
| 项 | 结果 | 说明 |
| --- | --- | --- |
| 本地配置启用 | 通过 | `oss_enabled`、`file_review_content_enabled`、`file_review_malware_enabled` 已置为 1 |
| OSS `PutObject` | 通过 | 测试文件成功写入 OSS |
| OSS `GetObject` | 通过 | 测试文件可读取且内容一致 |
| OSS `SignURL` | 通过 | 可生成短时下载 URL |
| OSS 测试对象清理 | 通过 | `codex-live/` 测试前缀已清理 |
| 内容安全提交 | 通过 | `FileModeration` 返回任务 ID |
| 内容安全轮询 | 通过 | 轮询结果为 `status=clean,risk=none` |
| 云安全中心提交 | 阻塞 | 本地网络访问 `https://tds.aliyuncs.com` 被 reset,未到达业务响应 |
### 6.3 SAS 阻塞说明
云安全中心 SDK 内置中国区 endpoint 为 `tds.aliyuncs.com`。本地环境中该域名解析到 `198.18.1.113`,无论 SDK 调用还是 `curl -I https://tds.aliyuncs.com/` 都返回 connection reset。备用 endpoint `tds.ap-southeast-1.aliyuncs.com` 在当前网络下同样 reset。因此本轮无法判断 SAS 账号权限或检测结果,只能确认本地网络到 SAS endpoint 不通。
## 7. 遗留问题
1. 本地网络无法访问云安全中心恶意文件检测 endpoint `tds.aliyuncs.com`,需要换网络、服务器环境或排查网络策略后复测。
2. 文件安全 worker 尚未完成,pending 审核任务不会自动提交第三方、轮询或回写状态。
3. 下载和业务展示侧尚未完整按 `im_file_review_tasks` 风险状态阻断或告警。
4. 纯文本内容安全不属于文件审核链路,群简介、签名、举报/反馈正文、日报/月报正文仍需独立文本审核方案。
@@ -2,46 +2,46 @@
## 1. 测试范围
- 测试时间:`2026-08-21 00:39:01 +0800`
- 测试时间:`2026-08-24 11:15:16 +0800`
- HTTP:`https://api.118im.com`
- WebSocket:`wss://api.118im.com/v0/channels`
- 租户:`default`
- 用户 A:`usr7-zA3UMrw7c` / `wsa459000` / `15794459000`
- 用户 B:`usrnDXQ3A2oQP0` / `wsb459000` / `15894459000`
- 用户 A:`usrO4KoysjOOVE` / `wsa043000` / `15757043000`
- 用户 B:`usricjD1vg9CXU` / `wsb043000` / `15857043000`
- API Key 与 Token 已脱敏,不在文档中展开。
## 2. 总体结论
本轮专项验证 Tinode WebSocket 真实协议链路,共执行 `29` 项,通过 `27` 项,未通过 `2` 项。
本轮专项验证 Tinode WebSocket 真实协议链路,共执行 `29` 项,通过 `28` 项,未通过 `1` 项。
| ID | 场景 | 方法 | 目标 | 结果 | 备注 |
| --- | --- | --- | --- | --- | --- |
| `WS-01` | 注册用户 A: HTTP 验证码 + WS acc | `WS` | `/v0/channels` | 通过 | user=usr7-zA3UMrw7c token=AwEA...18Om |
| `WS-02` | 注册用户 B: HTTP 验证码 + WS acc | `WS` | `/v0/channels` | 通过 | user=usrnDXQ3A2oQP0 token=AwEA...NX6b |
| `WS-03` | HTTP 建立好友关系生成 P2P Topic | `HTTP` | `/v1/im/friend-requests` | 通过 | request_id=frq_KAOkEfarCOA topic=p2p7-zA3UMrw7ecNdDcDahA_Q |
| `WS-04` | A token login + sub me | `WS` | `/v0/channels` | 通过 | login user=usr7-zA3UMrw7c |
| `WS-05` | B token login + sub me | `WS` | `/v0/channels` | 通过 | login user=usrnDXQ3A2oQP0 |
| `WS-06` | A/B 订阅 P2P Topic | `WS` | `p2p7-zA3UMrw7ecNdDcDahA_Q` | 通过 | topic=p2p7-zA3UMrw7ecNdDcDahA_Q |
| `WS-07` | A pub 文本消息,B 收到 data | `WS` | `p2p7-zA3UMrw7ecNdDcDahA_Q` | 通过 | seq=1 bob_topic=usr7-zA3UMrw7c |
| `WS-08` | B 发送 recv/read 回执 | `WS` | `p2p7-zA3UMrw7ecNdDcDahA_Q` | 通过 | what=read seq=1 |
| `WS-01` | 注册用户 A: HTTP 验证码 + WS acc | `WS` | `/v0/channels` | 通过 | user=usrO4KoysjOOVE token=AwEA...S/Xa |
| `WS-02` | 注册用户 B: HTTP 验证码 + WS acc | `WS` | `/v0/channels` | 通过 | user=usricjD1vg9CXU token=AwEA...Reda |
| `WS-03` | HTTP 建立好友关系生成 P2P Topic | `HTTP` | `/v1/im/friend-requests` | 通过 | request_id=frq_xYKajMBbqQM topic=p2pO4KoysjOOVGJyMPW-D0JdQ |
| `WS-04` | A token login + sub me | `WS` | `/v0/channels` | 通过 | login user=usrO4KoysjOOVE |
| `WS-05` | B token login + sub me | `WS` | `/v0/channels` | 通过 | login user=usricjD1vg9CXU |
| `WS-06` | A/B 订阅 P2P Topic | `WS` | `p2pO4KoysjOOVGJyMPW-D0JdQ` | 通过 | topic=p2pO4KoysjOOVGJyMPW-D0JdQ |
| `WS-07` | A pub 文本消息,B 收到 data | `WS` | `p2pO4KoysjOOVGJyMPW-D0JdQ` | 通过 | seq=1 bob_topic=usrO4KoysjOOVE |
| `WS-08` | B 发送 recv/read 回执 | `WS` | `p2pO4KoysjOOVGJyMPW-D0JdQ` | 通过 | what=read seq=1 |
| `WS-09` | basic login + sub me | `WS` | `/v0/channels` | 通过 | basic login ok |
| `WS-10` | 重复 login 被拒绝 | `WS` | `/v0/channels` | 通过 | code=409 text=already authenticated |
| `WS-11` | 订阅 fnd 搜索 Topic | `WS` | `fnd` | 通过 | sub fnd ok |
| `WS-12` | get me desc/sub/tags/cred | `WS` | `me` | 通过 | get me ok |
| `WS-13` | get P2P desc/sub/data/del | `WS` | `p2p7-zA3UMrw7ecNdDcDahA_Q` | 通过 | get p2p ok |
| `WS-14` | set P2P private 设置 | `WS` | `p2p7-zA3UMrw7ecNdDcDahA_Q` | 通过 | set private ok |
| `WS-15` | pub 产品 x-im 基础头 | `WS` | `p2p7-zA3UMrw7ecNdDcDahA_Q` | 通过 | seq=2 bob_topic=usr7-zA3UMrw7c |
| `WS-16` | pub 产品 x-im-client-mid 幂等头 | `WS` | `p2p7-zA3UMrw7ecNdDcDahA_Q` | 未通过 | pub ctrl: ctrl id=pub-003857.244320000 code=500 text=internal error |
| `WS-17` | note kp 输入中通知 | `WS` | `usr7-zA3UMrw7c` | 通过 | what=kp |
| `WS-18` | del 当前用户消息视图 | `WS` | `p2p7-zA3UMrw7ecNdDcDahA_Q` | 通过 | deleted seq=1 |
| `WS-19` | leave P2P detach 后重新订阅 | `WS` | `p2p7-zA3UMrw7ecNdDcDahA_Q` | 通过 | leave/resub ok |
| `WS-20` | HTTP 创建群供 WS 群协议测试 | `HTTP` | `/v1/im/groups` | 通过 | topic=grpURzKYanXB1Y |
| `WS-21` | A/B 订阅群 Topic | `WS` | `grpURzKYanXB1Y` | 通过 | sub group ok |
| `WS-22` | 群 pub 文本广播 | `WS` | `grpURzKYanXB1Y` | 通过 | seq=1 topic=grpURzKYanXB1Y |
| `WS-23` | get 群 desc/sub/data | `WS` | `grpURzKYanXB1Y` | 通过 | get group ok |
| `WS-13` | get P2P desc/sub/data/del | `WS` | `p2pO4KoysjOOVGJyMPW-D0JdQ` | 通过 | get p2p ok |
| `WS-14` | set P2P private 设置 | `WS` | `p2pO4KoysjOOVGJyMPW-D0JdQ` | 通过 | set private ok |
| `WS-15` | pub 产品 x-im 基础头 | `WS` | `p2pO4KoysjOOVGJyMPW-D0JdQ` | 通过 | seq=2 bob_topic=usrO4KoysjOOVE |
| `WS-16` | pub 产品 x-im-client-mid 幂等头 | `WS` | `p2pO4KoysjOOVGJyMPW-D0JdQ` | 通过 | seq=3 bob_topic=usrO4KoysjOOVE |
| `WS-17` | note kp 输入中通知 | `WS` | `usrO4KoysjOOVE` | 通过 | what=kp |
| `WS-18` | del 当前用户消息视图 | `WS` | `p2pO4KoysjOOVGJyMPW-D0JdQ` | 通过 | deleted seq=1 |
| `WS-19` | leave P2P detach 后重新订阅 | `WS` | `p2pO4KoysjOOVGJyMPW-D0JdQ` | 通过 | leave/resub ok |
| `WS-20` | HTTP 创建群供 WS 群协议测试 | `HTTP` | `/v1/im/groups` | 通过 | topic=grpNJqhCtAZwYM |
| `WS-21` | A/B 订阅群 Topic | `WS` | `grpNJqhCtAZwYM` | 通过 | sub group ok |
| `WS-22` | 群 pub 文本广播 | `WS` | `grpNJqhCtAZwYM` | 通过 | seq=1 topic=grpNJqhCtAZwYM |
| `WS-23` | get 群 desc/sub/data | `WS` | `grpNJqhCtAZwYM` | 通过 | get group ok |
| `WS-24` | 文件上传 /v0/file/u | `HTTP` | `/v0/file/u/` | 通过 | url=/v0/....bin |
| `WS-25` | WS 文件消息下发 | `WS` | `p2p7-zA3UMrw7ecNdDcDahA_Q` | 通过 | seq=3 bob_topic=usr7-zA3UMrw7c |
| `WS-26` | WebRTC 通话 invite pub | `WS` | `p2p7-zA3UMrw7ecNdDcDahA_Q` | 未通过 | pub ctrl: ctrl id=pub-003859.867810000 code=501 text=not implemented |
| `WS-25` | WS 文件消息下发 | `WS` | `p2pO4KoysjOOVGJyMPW-D0JdQ` | 通过 | seq=4 bob_topic=usrO4KoysjOOVE |
| `WS-26` | WebRTC 通话 invite pub | `WS` | `p2pO4KoysjOOVGJyMPW-D0JdQ` | 未通过 | pub ctrl: ctrl id=pub-111508.550364000 code=501 text=not implemented |
| `WS-27` | 未 hi 直接 login 被拒绝 | `WS` | `/v0/channels` | 通过 | code=409 text=command out of sequence |
| `WS-28` | hi 后切换 tenant 被拒绝 | `WS` | `/v0/channels` | 通过 | code=409 text=command out of sequence |
| `WS-29` | 非法 API Key 拒绝建连 | `WS` | `/v0/channels` | 通过 | http_status=403 |
@@ -53,6 +53,6 @@
## 4. 测试产生的数据
- P2P Topic:`p2p7-zA3UMrw7ecNdDcDahA_Q`
- Bob 收到的 Topic:`usr7-zA3UMrw7c`
- P2P Topic:`p2pO4KoysjOOVGJyMPW-D0JdQ`
- Bob 收到的 Topic:`usrO4KoysjOOVE`
- 消息 Seq:`1`