# 语音房火箭功能架构 ## 服务边界 - `room-service` 是火箭进度、点火、待发射队列和奖励结算 owner。 - `gateway-service` 只提供 App HTTP 入口和鉴权后的协议转换;`GET /api/v1/rooms/{room_id}/rocket` 会按奖励 `resource_group_id` 查询 wallet-service 并嵌入 `resource_group.items`。 - `server/admin` 只读写 `room-service` 内部配置接口,不直连 room 数据库。 - `wallet-service` 负责资源组发放。 - `activity-service` 负责区域/全局飘屏和带用户资料的奖励房间 IM。 - 腾讯云 IM 负责房间群、区域群和全局群投递。 ## 状态模型 `RoomRocketState` 保存当前正在累计的火箭和已点火待发射队列。 | 字段 | 说明 | | --- | --- | | `current_level` | 当前正在累计的等级,最高 5 | | `current_fuel` | 当前等级燃料 | | `fuel_threshold` | 当前等级阈值 | | `status` | `charging` 或 `completed` | | `rocket_id` | 当前正在累计的火箭 ID | | `pending_launches` | 已点火、等待延迟发射的火箭 | | `last_rewards` | 最近一次发射奖励结果 | `pending_launches` 中每一项锁定: | 字段 | 说明 | | --- | --- | | `rocket_id` | 本枚火箭幂等 ID | | `level` | 点火等级 | | `fuel_threshold` | 点火阈值 | | `ignited_at_ms` | 点火时间 | | `launch_at_ms` | 预计发射时间 | | `reset_at_ms` | UTC 日重置时间 | | `top1_user_id` | 点火时贡献第一 | | `igniter_user_id` | 点火人 | | `config_version` | 点火配置版本 | | `cover_url` | 小封面图 | ## 送礼加燃料 1. `SendGift` 先调用 wallet 扣费。 2. 扣费成功后,Room Cell 串行更新热度、礼物榜和火箭。 3. 燃料来自 wallet 返回的 `heat_value`。 4. 当前等级未满时,增加 `min(本次燃料, 剩余阈值)`。 5. 超过阈值的燃料直接写入 `overflow_fuel`,不进入下一等级。 6. 当前等级满后: - 写入 `RoomRocketFuelChanged`。 - 写入 `RoomRocketIgnited`。 - 将当前火箭追加到 `pending_launches`。 - 如果未到 5 级,立刻把当前状态切到下一等级,`current_fuel=0`。 - 如果 5 级已满,状态切到 `completed`,UTC 重置前不再累计新火箭。 ## 发射结算 1. `RoomRocketIgnited` 被 outbox worker 处理后,安排 RocketMQ delayed wakeup。 2. 本地扫描 worker 也会扫描已加载且仍持有 lease 的 Room Cell,作为兜底。 3. 到点后 `LaunchRoomRocket` 命令重新加载 Room Cell。 4. 命令必须校验: - `rocket_id` 存在于 `pending_launches`。 - `level` 匹配。 - `launch_at_ms <= now_ms`。 - `now_ms < reset_at_ms`。 5. 结算时按发射瞬间 `OnlineUsers` 抽在房奖励。 6. `top1` 和 `igniter` 使用点火时锁定的用户,离房后仍发对应奖励。 7. 发奖完成后移除该 `pending_launches` 项,当前正在累计的火箭不被发射命令推进。 ## 奖励 | 奖励 | 用户来源 | | --- | --- | | 点火人奖励 | `pending_launches[].igniter_user_id` | | 贡献第一奖励 | `pending_launches[].top1_user_id` | | 在房奖励 | 发射命令执行时 Room Cell `OnlineUsers` | 发放规则: | 奖励 | 规则 | | --- | --- | | 在房奖励 | 每个在线用户从 `inRoomRewards` 按权重随机抽 1 个 | | 贡献第一奖励 | top1 用户获得 `top1Rewards` 配置池内全部奖励 | | 点火人奖励 | 点火用户获得 `igniterRewards` 配置池内全部奖励 | 同一用户同时是 top1 和点火人时,top1 池和点火人池继续叠加;如果该用户发射瞬间仍在房间,也会再拿 1 个在房随机奖励。 ## IM | 事实 | IM | 投递方 | | --- | --- | --- | | `RoomRocketFuelChanged` | `room_rocket_fuel_changed` | room-service IM bridge | | `RoomRocketIgnited` | `room_rocket_ignited` | room-service IM bridge | | `RoomRocketIgnited` | `room_rocket` 区域/全局飘屏 | activity-service | | `RoomRocketLaunched` | `room_rocket_launched` | room-service IM bridge | | `RoomRocketRewardGranted` | `room_rocket_reward_granted` 房间奖励 IM | activity-service | 奖励 IM 由 activity-service 查询用户公开资料后组装,包含头像、昵称、短 ID 和奖励信息。room-service 不反查 user-service。 奖励资源组内容不写入 Room Cell;客户端需要金币数量、有效期、聊天气泡或麦位特效素材时,通过 rocket GET 接口读取展开后的 `resource_group`。 ## 高频处理 - Room Cell 串行处理送礼命令,所以同房高频送礼不会并发写乱进度。 - 满阈值时只把火箭追加到 `pending_launches`,不会阻塞下一等级继续累计。 - 房间状态 IM 通过 room outbox 补偿投递,不在送礼主链路同步调用腾讯 IM。 - 奖励 IM 合并为一条消息,`rewards` 内包含所有中奖人,避免按用户逐条堆积。 - RocketMQ delayed wakeup 只负责唤醒,最终发射仍由 Room Cell 命令校验。 ## UTC 重置 - 火箭周期按 UTC 自然日。 - 到达 `reset_at_ms` 后,查询或下一次送礼会投影为 1 级新进度。 - 跨过 UTC 日界仍未发射的待发射火箭不结算。 ## 后台配置 配置表:`room_rocket_configs` | 字段 | 说明 | | --- | --- | | `enabled` | 是否开启 | | `fuel_source` | 固定 `heat_value` | | `launch_delay_ms` | 点火到发射延迟 | | `broadcast_enabled` | 是否发飘屏 | | `broadcast_scope` | `region`、`global`、`none` | | `reward_stack_policy` | 历史兼容字段;当前特殊身份奖励按上方规则叠加 | | `levels_json` | 5 级阈值、物料和奖励池 | | `gift_fuel_rules_json` | 礼物燃料规则 | `levels_json` 字段使用 `fuelThreshold`、`coverUrl`、`animationUrl`、`launchAnimationUrl`、`launchedImageUrl`、`inRoomRewards`、`top1Rewards`、`igniterRewards`。