hyapp-server/docs/room-entry-reconnect-development-requirements.md
2026-05-01 00:32:00 +08:00

12 KiB
Raw Blame History

Room Entry And Reconnect Development Requirements

本文档定义下一阶段必须完成的语音房基础闭环:创建房间、进房、离房、断线重连。目标是让一个房间可以被稳定打开、进入、退出,并在客户端断线或服务短暂抖动后恢复到可继续使用的状态。

Goal

本阶段只解决房间生命周期的最小业务闭环。

Capability Required Result
创建房间 用户可以创建一个 active 语音房,并获得房间快照
进房 用户可以进入房间业务 presence并获得当前房间状态
订阅房间消息 用户进房成功后可以登录腾讯云 IM 并加入房间群
离房 用户主动退出后,房间 presence 被清理,后续进群和发言必须被业务守卫拒绝
断线重连 用户短暂断线后,可以重新鉴权、恢复房间状态、重新登录腾讯云 IM 并进群
防越权 未进房、被踢、被封禁用户不能继续进群或发公屏

Non Goals

本阶段不做这些:

Not Included Reason
麦位完整玩法 放到下一阶段,避免和进房链路混在一起
腾讯云 RTC token 下一阶段接 RTC 时补齐
金币和礼物 需要 wallet-service 先落地
推荐流和房间列表 先保证单房间可用
多端复杂同步 首版只保证同一用户重连恢复
热门房主备热同步 当前仍是单房间单活 + lease 接管

Ownership

Domain Owner Rule
HTTP 房间命令 gateway-service 只做鉴权、入参校验、协议转换
房间业务 presence room-service 创建房间、进房、离房、封禁、恢复
实时连接和房间群 腾讯云 IM 持有客户端长连接、群成员关系、房间消息历史
身份和 token user-service 登录、token、用户状态
真实语音链路 腾讯云 RTC 后续阶段接入,不由本阶段实现

关键边界:

  • room-service 不保存 socket。
  • 腾讯云 IM 不拥有房间业务 presence业务守卫仍以 room-service 为准。
  • gateway-service 不信任客户端自报 owner_user_idhost_user_idactor_user_id
  • 所有业务身份以 access token 解析出的 user_id 为准。
  • 腾讯云 IM 登录使用 gateway-service 签发的 UserSigUserSig 里的 identifier 使用不可变长 user_id

Presence Model

需要明确区分三种状态:

State Owner Meaning
房间业务 presence room-service 用户业务上属于这个房间
房间群连接态 腾讯云 IM 用户当前客户端是否登录 IM、是否在房间群内
RTC 在线态 腾讯云 RTC 用户是否在真实音频频道中

本阶段只实现 room-service presence并通过腾讯云 IM 群承载消息。RTC 在线态只预留字段和流程位置。

External API

Create Room

POST /api/v1/rooms/create
Authorization: Bearer <access_token>

建议请求:

{
  "room_id": "room_1001",
  "command_id": "cmd_create_room_1001_10001_1",
  "seat_count": 8,
  "mode": "voice",
  "room_name": "周末语音房",
  "room_avatar": "",
  "room_description": "本房间用于轻量聊天和上麦互动"
}

正式客户端不应该传 owner_user_idhost_user_id。gateway 必须从 access token 取当前 user_id 写入 RequestMeta.actor_user_idroom-service 使用该 actor 确定 owner 和默认 host。room_name 必填,room_avatar 为空时写入默认系统头像,房间展示资料统一落在 RoomExt

响应必须包含:

{
  "result": {
    "applied": true,
    "room_version": 1,
    "server_time_ms": 1777000000000
  },
  "room": {}
}

Join Room

POST /api/v1/rooms/join
Authorization: Bearer <access_token>

请求:

{
  "room_id": "room_1001",
  "command_id": "cmd_join_room_1001_10002_1",
  "role": "audience"
}

响应必须包含用户业务 presence 和房间快照:

{
  "result": {},
  "user": {
    "user_id": 10001,
    "role": "audience",
    "joined_at_ms": 1777000000000,
    "last_seen_at_ms": 1777000000000
  },
  "room": {}
}

JoinRoom 必须幂等。用户已经在房间时,不能重复增加在线人数或重复广播进房消息,但需要刷新 last_seen_at_ms

Leave Room

POST /api/v1/rooms/leave
Authorization: Bearer <access_token>

请求:

{
  "room_id": "room_1001",
  "command_id": "cmd_leave_room_1001_10002_1"
}

LeaveRoom 必须幂等。用户已经不在房间时,返回当前快照,不报业务错误。

Tencent IM Login And Join Group

客户端在 JoinRoom 成功后向 gateway 获取腾讯云 IM UserSig

POST /api/v1/im/usersig
Authorization: Bearer <access_token>

响应中的 user_id 是腾讯云 IM identifier必须等于内部不可变长 user_id 的十进制字符串。

客户端随后使用腾讯云 IM SDK 登录并加入房间群:

{
  "sdk_app_id": 1400000000,
  "user_id": "10001",
  "user_sig": "usersig_xxx",
  "room_id": "room_1001"
}

进群前业务守卫仍然需要存在。首版可以由客户端先 JoinRoom 再进群;线上必须补腾讯云 IM 回调或 gateway 代理校验:

room-service.VerifyRoomPresence(room_id, user_id, session_id)

只有 present=true 才允许进群或继续接收房间业务消息。被踢或封禁后,room-service 负责写 outbox 并通过腾讯云 IM 推系统事件,客户端必须按事件退房或触发重新同步。

Required Internal Changes

当前基础接口已经存在,但本阶段需要补齐这些行为。

gateway-service

Requirement Detail
创建房间身份收敛 CreateRoom 的 owner/host 必须由 room-service 从 RequestMeta.actor_user_id 收敛,不接受客户端 body 自报
command_id 所有房间命令请求体都支持稳定 command_id,用于 room-service command log 幂等。客户端重试同一业务动作必须复用该值;未传时 gateway 只为本次请求生成新值,不保证 HTTP 重试幂等
统一错误映射 房间不存在、被踢、无权限、重复命令要映射成稳定 HTTP envelope
请求日志 记录 request_iduser_idroom_id、command type

room-service

Requirement Detail
CreateRoom 创建 meta、command log、snapshot、outbox并安装 Room Cell
单 owner 单房间 同一个 RequestMeta.actor_user_id 只能作为 owner 创建一个房间;已有 owner 房间时返回 Conflict
JoinRoom 幂等 已在房间时刷新 last_seen_at_ms,不重复广播
LeaveRoom 幂等 不在房间时返回当前快照
VerifyRoomPresence 腾讯云 IM 回调或 gateway 代理进群前检查房间存在、用户在房间、未被 ban
Presence 过期 支持断线宽限期,超过 TTL 后自动清理
Recovery 节点重启后能通过 snapshot + command log 恢复房间

建议新增配置:

room_presence_reconnect_grace: "60s"
room_presence_stale_timeout: "300s"
room_presence_sweep_interval: "30s"

Tencent Cloud IM Integration

Requirement Detail
UserSig gateway-service 只给已鉴权用户签发腾讯云 IM UserSig
EnsureRoomGroup room-service.CreateRoom 必须确保腾讯云 IM 群组存在
PublishRoomEvent 房间状态变更后同步推腾讯云 IM 群系统消息,失败不回滚房间状态
Guard Callback 线上需要腾讯云 IM 进群/发言回调或等价 gateway 代理调用 VerifyRoomPresenceCheckSpeakPermission
History 房间最近消息优先使用腾讯云 IM 群历史;本仓库不再保存自研 IM 时间线

Reconnect Design

断线分三种。

Case Expected Behavior
IM 短断 room-service presence 保留,客户端重新登录腾讯云 IM 后重新进群
App 退后台后恢复 客户端先调用 JoinRoom 幂等刷新,再重新登录腾讯云 IM 并进群
超过 stale timeout room-service 自动清理 presence客户端需要重新进房

客户端重连标准流程:

1. 如果 access token 过期,先 RefreshToken
2. 调 POST /api/v1/rooms/join刷新房间业务 presence
3. 调 POST /api/v1/im/usersig拿腾讯云 IM UserSig
4. 使用腾讯云 IM SDK 登录
5. 加入 room_id 对应的腾讯云 IM 群
6. 拉取腾讯云 IM 群历史或等待房间系统消息补齐
7. 用 JoinRoom 返回的 RoomSnapshot 覆盖本地房间状态

服务端原则:

  • 断线不能立刻等同于离房。
  • 主动 LeaveRoom 才是明确离房。
  • 超时清理是兜底,不能依赖客户端一定发离房。
  • 被踢或封禁后,即使客户端仍在腾讯云 IM 群内,也必须通过回调守卫、系统事件和客户端同步阻断继续发言或展示在房间内。

Data Requirements

RoomUserState 至少需要支持:

Field Meaning
user_id 房间内业务用户
role owner, host, admin, audience
joined_at_ms 首次进入当前房间时间
last_seen_at_ms 最近一次 JoinRoom、订阅或心跳时间

建议后续追加:

Field Meaning
connection_state online, reconnecting, stale
reconnect_deadline_ms 断线宽限截止时间

首版可以先不把 connection_state 暴露给客户端,但内部清理逻辑要能基于 last_seen_at_ms 判断 stale。

Event Requirements

房间状态成功变更后,room-service 必须写 outbox。

Action Outbox Event IM System Event
创建房间 RoomCreated 可不广播
进房成功 RoomUserJoined room_user_joined
离房成功 RoomUserLeft room_user_left
stale 自动离房 RoomUserLeft room_user_leftreason=stale_timeout
被踢 RoomUserKicked room_user_kicked

同步 PublishRoomEvent 失败不能回滚房间状态,仍由 room outbox 补投到腾讯云 IM 和后续活动系统。

Acceptance Tests

必须覆盖这些测试。

Test Expected Result
创建房间成功 返回 version=1owner 在 online_users 内
重复 CreateRoom command_id 不重复创建,返回同一房间快照
普通用户 JoinRoom presence 增加,广播进房事件
重复 JoinRoom 不重复广播,不重复增加人数,刷新 last_seen
LeaveRoom presence 移除,进群/发言守卫拒绝后续实时消息权限
重复 LeaveRoom 幂等返回,不报错
JoinRoom 后进群 VerifyRoomPresence 通过,腾讯云 IM 群收到房间消息
未 JoinRoom 直接进群或发言 VerifyRoomPresenceCheckSpeakPermission 返回 not_in_room
Kick 后进群或发言 返回 user_banned
IM 断开后 60 秒内重连 JoinRoom 幂等刷新,腾讯云 IM 重新登录和进群成功,历史可拉
超过 stale timeout presence 自动清理,需要重新 JoinRoom
room-service 重启恢复 snapshot + command log 恢复后 JoinRoom/subscribe 继续可用

Implementation Order

建议按这个顺序做:

  1. 修正创建房间身份来源gateway 不接收 body 的 owner/hostroom-service 从 RequestMeta.actor_user_id 收敛 owner/default host。
  2. 补齐 JoinRoom 幂等刷新 last_seen_at_ms
  3. 补齐 LeaveRoom 后对订阅守卫的拒绝行为测试。
  4. 接入腾讯云 IM UserSig 签发、CreateRoom 建群和房间系统消息发布。
  5. 增加 stale presence 清理 worker。
  6. 增加重连集成测试JoinRoom -> UserSig -> IM login/join group -> disconnect -> reconnect -> history。
  7. 增加 room-service 重启恢复测试。