hyapp-server/README.md
2026-05-02 13:02:38 +08:00

8.2 KiB
Raw Blame History

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 送礼扣费语义,余额、流水和幂等记录落 MySQLroom-serviceSendGift 同步调用它。
  • user-service 当前承接登录、三方注册、密码、refresh session、用户主数据、默认短号和临时靓号基础能力。
  • activity-service 当前提供活动 gRPC 查询骨架和房间事件 consumer 边界,尚未接入 room_outbox 消费主循环。
  • 腾讯云 IM 承担客户端长连接、群消息、公屏、单聊、离线/漫游和全球接入能力;本仓库不再部署 im-service
  • 多 App 共用同一套后端服务,入口由 gateway-service 通过包名或 app_code 解析租户;所有业务库表按 app_code 隔离,设计细节见 docs/multi-app-tenant-architecture.md

协议边界:

  • 客户端命令面:gateway-service 暴露 HTTP JSON。
  • 客户端实时面:腾讯云 IM SDK客户端用 gateway 签发的 UserSig 登录。
  • 服务内部调用gRPC + protobuf契约在独立 Go module api,业务代码通过 hyapp.local/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:

make up

Service aliases: gs/gateway, rs/room, ws/wallet, us/user, as/activity, mysql, redis.

Common commands:

make test
make build
make admin-up
make admin
make addr
make logs
make rebuild rs
make down

make admin-up 会先启动后台本地依赖 MySQL、Redis 和 user-service,再以前台进程启动 server/admin。依赖已经存在时,可以直接运行 make admin

For direct host execution, each service reads its own services/<service>/configs/config.yaml; room-serviceuser-servicewallet-serviceactivity-service 都要求 MySQL 可用。

Tencent IM

客户端获取腾讯云 IM 登录票据:

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

响应 data 包含:

{
  "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_idroom-service 由该 actor 收敛 owner 和默认 host外部 CreateRoom 请求体不接收 owner_user_idhost_user_id
  • 房间 HTTP 命令支持请求体 command_id 作为幂等键;request_id 只做链路追踪。
  • room-serviceCreateRoom 时通过腾讯云 IM REST API 创建同名群组。
  • room-service 在上下麦、禁言、踢人、送礼等命令提交后,通过腾讯云 IM REST API 发送房间系统自定义消息。
  • gateway-service 已提供 /api/v1/tencent-im/callback,支持腾讯云 IM 入群前和发言前回调,并分别回查 VerifyRoomPresenceCheckSpeakPermission

腾讯云 IM 配置分别在:

services/gateway-service/configs/config.yaml
services/room-service/configs/config.yaml
services/room-service/configs/config.tencent.example.yaml

本地联调腾讯云 IM 时,gateway-serviceroom-service 必须使用同一组 sdk_app_idsecret_keyroom-service 还必须配置匹配的 admin_identifier 和区域 endpoint

基础闭环实现顺序见:

docs/voice-room-basic-loop-implementation.md

Storage Model

MySQL 是本地和线上运行的持久化底座:

  • room-service: hyapp_room,保存 room meta、snapshot、command log 和 outbox业务行按 app_code 隔离。
  • user-service: hyapp_user,保存 apps 注册表、用户主数据、注册资料快照、登录身份、session、默认短号、靓号租约和 host 关系事实,业务行按 app_code 隔离。
  • wallet-service: hyapp_wallet,保存余额、账务流水、礼物价格和扣费幂等记录,业务行按 app_code 隔离。
  • activity-service: hyapp_activity,保存活动状态、事件消费幂等和 activity outbox业务行按 app_code 隔离。
  • hyapp_admin: 后台管理后端独立库,只保存后台账号、权限和审计;不要把后台审计耦合进 App 业务库。

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:

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

go.work                    local workspace for app backend, api contracts and admin backend
api/                       independent Go module, protobuf contracts and generated code
pkg/                       app backend shared packages, including Tencent IM signing/client
server/admin/              independent admin backend module
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.CallbackBeforeApplyJoinGroupGroup.CallbackBeforeSendMsg,并配置公网 callback URL 与鉴权 token。
  • 房间命令未传 command_idgateway 会自动生成新值;客户端 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 等本地配置只能用开发值,线上必须走安全配置源。