# HY Voice Room HY Voice Room 是一个语音房后端 monorepo。当前重点不是做通用 IM 平台,而是把语音房的实时业务闭环跑起来:HTTP 命令入口、房间 Room Cell、WebSocket 消息投递、MySQL 状态恢复、Redis 房间路由。 ## Architecture 核心边界: - `gateway-service` 是客户端 HTTP JSON 入口,负责鉴权、协议转换和调用 `room-service`。它不持有房间状态,也不终止 WebSocket。 - `room-service` 是房间业务状态 owner,负责 Room Cell、麦位、房间 presence、本地礼物榜、送礼落房间、snapshot、command log、outbox、Redis lease 路由。 - `im-service` 是连接和消息 owner,负责 WebSocket、房间频道订阅、公屏、房间系统消息、单聊、ACK、最近房间历史。 - `wallet-service` 当前提供送礼扣费 stub,`room-service` 的 `SendGift` 同步调用它。 - `user-service` 和 `activity-service` 当前是独立进程骨架,后续分别承接用户主数据和活动消费。 外部协议和内部协议: - 客户端命令面:`gateway-service` 暴露 HTTP JSON。 - 客户端实时面:`im-service` 暴露 WebSocket JSON。 - 服务内部调用:gRPC + protobuf,契约在 `api/proto`。 - 房间外事件:protobuf outbox,当前先落 MySQL。 ## Ports 本地和 Docker 编排统一使用 `13xxx` 端口: | Component | Port | Purpose | | --- | ---: | --- | | `gateway-service` | `13000` | HTTP JSON | | `room-service` | `13001` | gRPC | | `im-service` | `13002` | HTTP/WebSocket | | `im-service` | `13003` | gRPC | | `wallet-service` | `13004` | gRPC | | `user-service` | `13005` | gRPC | | `activity-service` | `13006` | gRPC | | MySQL | `13306 -> 3306` | local Docker only | | Redis | `13379 -> 6379` | local Docker only | ## Run Locally Use Docker for local and test environments: ```bash make compose-up ``` `make compose-up` starts the stack in detached mode and prints host-local, host-LAN, and Docker-network addresses for every service port. Follow logs: ```bash make compose-logs ``` Print addresses again without restarting services: ```bash make compose-addresses ``` Stop services: ```bash make compose-down ``` The compose stack starts MySQL and Redis. MySQL schema is initialized from: ```text services/room-service/deploy/mysql/initdb/001_room_service.sql ``` For direct host execution, each service reads its own `services//configs/config.yaml`. ## Development Commands ```bash make proto make test make build make compose-up make compose-addresses make compose-logs make compose-down ``` `make proto` requires `protoc`, `protoc-gen-go`, and `protoc-gen-go-grpc`. ## Storage Model `room-service` uses MySQL as the 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} ``` The Redis value stores `room_id`, `node_id`, `lease_token`, and `expires_at_ms`. Lease acquisition is atomic through Lua in `internal/router/redis_directory.go`. ## 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. ## Cloud Deployment Local Docker uses: ```text services/room-service/configs/config.docker.yaml ``` Tencent Cloud deployment should follow: ```text services/room-service/configs/config.tencent.example.yaml ``` Set the real Tencent Cloud MySQL DSN, Redis address, Redis password, and internal service DNS names. Keep `mysql_auto_migrate: false` online; schema changes should run through a controlled migration process. Deployment lifecycle requirements are documented in: ```text docs/health-checks.md docs/graceful-shutdown.md ``` ## API Entry Points Gateway HTTP routes: - `POST /rooms/create` - `POST /rooms/join` - `POST /rooms/leave` - `POST /rooms/mic/up` - `POST /rooms/mic/down` - `POST /rooms/mic/change` - `POST /rooms/user/mute` - `POST /rooms/user/kick` - `POST /rooms/gift/send` IM WebSocket path: ```text ws://127.0.0.1:13002/ws ``` The first WS frame must be `auth`; later frames include `subscribe_room`, `unsubscribe_room`, `room_chat_send`, `peer_send`, `ack`, and `pull_history`. ## Project Layout ```text api/proto/ protobuf contracts pkg/ small shared packages services/gateway-service/ HTTP entry service services/room-service/ Room Cell and durable room state services/im-service/ WebSocket and message delivery services/wallet-service/ wallet stub services/user-service/ user stub services/activity-service/ activity stub ``` ## Current Limits - `wallet-service`, `user-service`, and `activity-service` are still stubs. - `room-service` outbox is durable, but external activity consumption is not implemented yet. - `im-service` keeps message/session state in memory; scaling it across nodes still needs shared online routing or a delivery bus. - JWT secrets in local config are development values only.