hyapp-server/README.md
2026-04-30 02:30:32 +08:00

166 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# HY Voice Room
HY Voice Room 是语音房后端 monorepo。当前架构不再自研 IM 长连接服务:房间业务状态由 `room-service` 承担,客户端实时消息接入腾讯云 IM服务端只负责签发 UserSig、创建房间群组、发送房间系统消息。
## Architecture
核心边界:
任何开发,不需要历史兼容,目前只是在开发阶段
- `gateway-service` 是客户端 HTTP JSON 入口,负责鉴权、协议转换、签发腾讯云 IM UserSig以及调用内部 gRPC 服务。
- `room-service` 是房间业务状态 owner负责 Room Cell、麦位、房间 presence、本地礼物榜、送礼落房间、snapshot、command log、outbox、Redis lease以及腾讯云 IM 群组/系统消息桥接。
- `wallet-service` 当前提供 `DebitGift` 送礼扣费语义,余额、流水和幂等记录落 MySQL`room-service``SendGift` 同步调用它。
- `user-service` 当前承接登录、三方注册、密码、refresh session、用户主数据、默认短号和临时靓号基础能力。
- `activity-service` 当前提供活动 gRPC 查询骨架和房间事件 consumer 边界,尚未接入 `room_outbox` 消费主循环。
- 腾讯云 IM 承担客户端长连接、群消息、公屏、单聊、离线/漫游和全球接入能力;本仓库不再部署 `im-service`
协议边界:
- 客户端命令面:`gateway-service` 暴露 HTTP JSON。
- 客户端实时面:腾讯云 IM SDK客户端用 gateway 签发的 UserSig 登录。
- 服务内部调用gRPC + protobuf契约在 `api/proto`
- 房间外事件protobuf outbox当前先落 MySQL。
## Ports
本地和 Docker 编排统一使用 `13xxx` 端口:
| Component | Port | Purpose |
| ------------------ | --------------: | ----------------- |
| `gateway-service` | `13000` | HTTP JSON |
| `room-service` | `13001` | gRPC |
| `wallet-service` | `13004` | gRPC |
| `user-service` | `13005` | gRPC |
| `activity-service` | `13006` | gRPC |
| MySQL | `23306 -> 3306` | local Docker only |
| Redis | `13379 -> 6379` | local Docker only |
## Run Locally
Use Docker for local and test environments:
```bash
make up
```
Service aliases: `gs/gateway`, `rs/room`, `ws/wallet`, `us/user`, `as/activity`, `mysql`, `redis`.
Common commands:
```bash
make test
make build
make addr
make logs
make rebuild rs
make down
```
For direct host execution, each service reads its own `services/<service>/configs/config.yaml`; `room-service``user-service``wallet-service``activity-service` 都要求 MySQL 可用。
## Tencent IM
客户端获取腾讯云 IM 登录票据:
```text
GET /api/v1/im/usersig
Authorization: Bearer <access_token>
```
响应 `data` 包含:
```json
{
"sdk_app_id": 1400000000,
"user_id": "10001",
"user_sig": "xxx",
"expire_at_ms": 1710000000000
}
```
房间流程:
- 客户端先经 gateway 调 `JoinRoom`,让用户进入 `room-service` presence。
- 客户端再用腾讯云 IM SDK 登录并加入 `room_id` 对应的群组。
- `gateway-service` 创建房间时从 access token 取当前 `user_id` 写入 `RequestMeta.actor_user_id``room-service` 由该 actor 收敛 owner 和默认 host外部 CreateRoom 请求体不接收 `owner_user_id``host_user_id`
- 房间 HTTP 命令支持请求体 `command_id` 作为幂等键;`request_id` 只做链路追踪。
- `room-service``CreateRoom` 时通过腾讯云 IM REST API 创建同名群组。
- `room-service` 在上下麦、禁言、踢人、送礼等命令提交后,通过腾讯云 IM REST API 发送房间系统自定义消息。
- `gateway-service` 已提供 `/api/v1/tencent-im/callback`,支持腾讯云 IM 入群前和发言前回调,并分别回查 `VerifyRoomPresence``CheckSpeakPermission`
腾讯云 IM 配置分别在:
```text
services/gateway-service/configs/config.yaml
services/room-service/configs/config.yaml
services/room-service/configs/config.tencent.example.yaml
```
本地联调腾讯云 IM 时,`gateway-service``room-service` 必须使用同一组 `sdk_app_id``secret_key``room-service` 还必须配置匹配的 `admin_identifier` 和区域 `endpoint`
基础闭环实现顺序见:
```text
docs/voice-room-basic-loop-implementation.md
```
## Storage Model
MySQL 是本地和线上运行的持久化底座:
- `room-service`: `hyapp_room`,保存 room meta、snapshot、command log 和 outbox。
- `user-service`: `hyapp_user`保存用户主数据、注册资料快照、登录身份、session、默认短号和靓号租约。
- `wallet-service`: `hyapp_wallet`,保存余额、账务流水和扣费幂等记录。
- `activity-service`: `hyapp_activity`,保存活动状态、事件消费幂等和 activity outbox。
`room-service` uses MySQL as the room recovery durable source:
- `rooms`: room metadata.
- `room_snapshots`: latest room state snapshot.
- `room_command_log`: replayable command log for recovery.
- `room_outbox`: async event records.
`room-service` uses Redis for current room ownership:
```text
room:route:{room_id}
```
Redis lease 只保存当前执行权,不能作为恢复来源。恢复来源是 MySQL snapshot + command log。
## Room Recovery
A room is not permanently bound to one process. A node is only the current executor while its Redis lease is valid.
Recovery path:
1. A request reaches a node that can own the room.
2. The node acquires or renews `room:route:{room_id}`.
3. If the local Room Cell does not exist, it loads the latest MySQL snapshot.
4. It replays command log records after the snapshot version.
5. It installs a local Room Cell and continues processing.
This is single-active recovery, not hot standby. Short retry/reconnect windows are expected during node failure.
## Project Layout
```text
api/proto/ protobuf contracts
pkg/ shared packages, including Tencent IM signing/client
services/gateway-service/ HTTP entry service
services/room-service/ Room Cell and durable room state
services/wallet-service/ wallet DebitGift and ledger foundation
services/user-service/ user service
services/activity-service/ activity foundation and room event consumer boundary
```
## Current Limits
- 腾讯云 IM 回调入口已经落在 gateway线上仍必须在腾讯云 IM 控制台启用 `Group.CallbackBeforeApplyJoinGroup``Group.CallbackBeforeSendMsg`,并配置公网 callback URL 与鉴权 token。
- 房间命令未传 `command_id`gateway 会自动生成新值;客户端 HTTP 重试同一业务动作时必须复用原 `command_id` 才能命中 room-service command log 幂等。
- `wallet-service` App 运行路径使用 MySQL 扣费事务;本地需要先通过 compose initdb 建好 `hyapp_wallet`
- `activity-service` 当前只有同步查询和 consumer 边界;`room_outbox` 到 activity/audit 的实际消费链路未完整实现。
- `room-service` App 已启动 `room_outbox` 补偿 worker该状态只表示腾讯云 IM 系统消息补偿结果activity/audit 后续必须使用独立消费位点。
- JWT、腾讯云 IM secret 等本地配置只能用开发值,线上必须走安全配置源。