333 lines
7.7 KiB
Markdown
333 lines
7.7 KiB
Markdown
# 房间锁房 Flutter 对接
|
||
|
||
## 地址
|
||
|
||
本地:
|
||
|
||
```text
|
||
http://127.0.0.1:13000
|
||
```
|
||
|
||
接口:
|
||
|
||
| 方法 | 地址 | 说明 |
|
||
| --- | --- | --- |
|
||
| `POST` | `/api/v1/rooms/password` | 房主设置或清空房间密码 |
|
||
| `POST` | `/api/v1/rooms/join` | 进入房间;锁房时必须传密码 |
|
||
| `GET` | `/api/v1/rooms` | 房间列表和搜索,返回 `locked` |
|
||
| `GET` | `/api/v1/rooms/feeds` | Mine 页房间流,返回 `locked` |
|
||
|
||
请求头:
|
||
|
||
| Header | 必填 | 说明 |
|
||
| --- | --- | --- |
|
||
| `Authorization` | 是 | `Bearer <access_token>` |
|
||
| `X-App-Code` | 否 | App 编码,例如 `lalu` |
|
||
|
||
## 设置房间密码
|
||
|
||
`POST /api/v1/rooms/password`
|
||
|
||
参数:
|
||
|
||
| 字段 | 必填 | 类型 | 说明 |
|
||
| --- | --- | --- | --- |
|
||
| `room_id` | 是 | string | 房间 ID |
|
||
| `command_id` | 是 | string | 本次设置动作的幂等键,同一次重试复用 |
|
||
| `locked` | 是 | bool | `true` 设置密码,`false` 清空密码 |
|
||
| `password` | `locked=true` 必填 | string | 房间密码,服务端 trim 后最长 64 字符;`locked=false` 时忽略 |
|
||
|
||
请求:
|
||
|
||
```json
|
||
{
|
||
"room_id": "room_10001",
|
||
"command_id": "cmd_room_password_room_10001_1710000000",
|
||
"locked": true,
|
||
"password": "1234"
|
||
}
|
||
```
|
||
|
||
返回:
|
||
|
||
```json
|
||
{
|
||
"code": "OK",
|
||
"message": "ok",
|
||
"request_id": "req_abc",
|
||
"data": {
|
||
"result": {
|
||
"applied": true,
|
||
"room_version": 12,
|
||
"server_time_ms": 1710000000456
|
||
},
|
||
"room": {
|
||
"room_id": "room_10001",
|
||
"im_group_id": "room_10001",
|
||
"room_short_id": "100001",
|
||
"title": "Live Room",
|
||
"cover_url": "https://cdn.example/room.png",
|
||
"owner_user_id": "10001",
|
||
"mode": "voice",
|
||
"status": "active",
|
||
"chat_enabled": true,
|
||
"locked": true,
|
||
"heat": 1000,
|
||
"online_count": 12,
|
||
"seat_count": 15,
|
||
"occupied_seat_count": 2,
|
||
"version": 12
|
||
},
|
||
"seats": [],
|
||
"server_time_ms": 1710000000456
|
||
}
|
||
}
|
||
```
|
||
|
||
返回字段:
|
||
|
||
| 字段 | 说明 |
|
||
| --- | --- |
|
||
| `data.result.applied` | 本次命令是否改变房间状态 |
|
||
| `data.result.room_version` | 房间最新版本 |
|
||
| `data.room.locked` | 最新锁房状态 |
|
||
| `data.room.version` | 房间快照版本 |
|
||
| `data.seats` | 当前麦位列表 |
|
||
|
||
## 清空房间密码
|
||
|
||
`POST /api/v1/rooms/password`
|
||
|
||
参数:
|
||
|
||
| 字段 | 必填 | 类型 | 说明 |
|
||
| --- | --- | --- | --- |
|
||
| `room_id` | 是 | string | 房间 ID |
|
||
| `command_id` | 是 | string | 本次清空动作的幂等键 |
|
||
| `locked` | 是 | bool | 固定传 `false` |
|
||
|
||
请求:
|
||
|
||
```json
|
||
{
|
||
"room_id": "room_10001",
|
||
"command_id": "cmd_room_unlock_room_10001_1710000100",
|
||
"locked": false
|
||
}
|
||
```
|
||
|
||
返回同设置密码接口,`data.room.locked=false`。
|
||
|
||
## 进入锁房房间
|
||
|
||
`POST /api/v1/rooms/join`
|
||
|
||
参数:
|
||
|
||
| 字段 | 必填 | 类型 | 说明 |
|
||
| --- | --- | --- | --- |
|
||
| `room_id` | 是 | string | 房间 ID |
|
||
| `command_id` | 是 | string | 本次进房动作的幂等键,同一次重试复用 |
|
||
| `role` | 否 | string | 当前传 `audience` |
|
||
| `password` | 锁房时必填 | string | 本次入房密码 |
|
||
|
||
请求:
|
||
|
||
```json
|
||
{
|
||
"room_id": "room_10001",
|
||
"command_id": "cmd_join_room_10001_20001_1710000000",
|
||
"role": "audience",
|
||
"password": "1234"
|
||
}
|
||
```
|
||
|
||
返回:
|
||
|
||
```json
|
||
{
|
||
"code": "OK",
|
||
"message": "ok",
|
||
"request_id": "req_abc",
|
||
"data": {
|
||
"result": {
|
||
"applied": true,
|
||
"room_version": 13,
|
||
"server_time_ms": 1710000001456
|
||
},
|
||
"room": {
|
||
"room_id": "room_10001",
|
||
"im_group_id": "room_10001",
|
||
"locked": true,
|
||
"version": 13
|
||
},
|
||
"viewer": {
|
||
"user_id": "20001",
|
||
"role": "audience",
|
||
"joined_at_ms": 1710000001456,
|
||
"last_seen_at_ms": 1710000001456
|
||
},
|
||
"im": {
|
||
"group_id": "room_10001",
|
||
"need_join_group": true
|
||
},
|
||
"rtc": {
|
||
"need_token": true,
|
||
"available": true
|
||
},
|
||
"server_time_ms": 1710000001456
|
||
}
|
||
}
|
||
```
|
||
|
||
返回字段:
|
||
|
||
| 字段 | 说明 |
|
||
| --- | --- |
|
||
| `data.room.locked` | 当前房间是否锁房 |
|
||
| `data.viewer.user_id` | 当前用户 ID |
|
||
| `data.im.group_id` | JoinRoom 成功后需要加入的腾讯 IM 房间群 |
|
||
| `data.im.need_join_group` | `true` 时 Flutter 调腾讯 IM `joinGroup` |
|
||
| `data.rtc.available` | 是否拿到 RTC token |
|
||
|
||
进房规则:
|
||
|
||
| 场景 | 结果 |
|
||
| --- | --- |
|
||
| 未锁房 | `password` 可不传 |
|
||
| 已锁房且密码正确 | JoinRoom 成功,再加入 IM 房间群 |
|
||
| 已锁房且密码错误或缺失 | 返回 `403 PERMISSION_DENIED`,不要加入 IM 房间群 |
|
||
| 房主进自己房间 | 不需要密码 |
|
||
| 已在房间内重复 JoinRoom | 非房主仍要按当前最新密码校验;密码错误返回 `403 PERMISSION_DENIED` |
|
||
|
||
## 房间列表 locked 字段
|
||
|
||
`GET /api/v1/rooms?tab=hot&query=100001`
|
||
|
||
`GET /api/v1/rooms/feeds?tab=followed`
|
||
|
||
返回:
|
||
|
||
```json
|
||
{
|
||
"code": "OK",
|
||
"message": "ok",
|
||
"request_id": "req_abc",
|
||
"data": {
|
||
"rooms": [
|
||
{
|
||
"room_id": "room_10001",
|
||
"im_group_id": "room_10001",
|
||
"title": "Live Room",
|
||
"locked": true,
|
||
"online_count": 12,
|
||
"visible_region_id": 1,
|
||
"room_short_id": "100001"
|
||
}
|
||
],
|
||
"next_cursor": ""
|
||
}
|
||
}
|
||
```
|
||
|
||
字段:
|
||
|
||
| 字段 | 说明 |
|
||
| --- | --- |
|
||
| `rooms[].locked` | 是否锁房;`true` 时进房前弹密码输入 |
|
||
| `rooms[].im_group_id` | 房间 IM 群 ID,只能在 JoinRoom 成功后使用 |
|
||
| `rooms[].visible_region_id` | 房间区域 |
|
||
|
||
## 相关 IM
|
||
|
||
### JoinRoom 成功后加入房间群
|
||
|
||
接口 `POST /api/v1/rooms/join` 成功后,Flutter 使用:
|
||
|
||
```text
|
||
data.im.group_id
|
||
```
|
||
|
||
调用腾讯 IM SDK 加入房间群。
|
||
|
||
规则:
|
||
|
||
| 场景 | Flutter 行为 |
|
||
| --- | --- |
|
||
| JoinRoom 成功 | 调腾讯 IM `joinGroup(data.im.group_id)` |
|
||
| JoinRoom 返回 `PERMISSION_DENIED` | 不调用 `joinGroup` |
|
||
| JoinRoom 返回 `ROOM_CLOSED` 或 `NOT_FOUND` | 不调用 `joinGroup`,刷新列表 |
|
||
|
||
### 房间密码变更区域通知
|
||
|
||
房主设置或清空密码后,服务端会发区域播报 IM,不再发房间群 IM。
|
||
|
||
Flutter 需要监听用户所在区域播报群的自定义消息:
|
||
|
||
```json
|
||
{
|
||
"event_id": "room_password_changed:evt_room_xxx",
|
||
"broadcast_type": "room_password_changed",
|
||
"scope": "region",
|
||
"app_code": "lalu",
|
||
"region_id": 1,
|
||
"room_id": "room_10001",
|
||
"actor_user_id": 10001,
|
||
"locked": true,
|
||
"sent_at_ms": 1710000000456,
|
||
"room_version": 12,
|
||
"source_event_id": "evt_room_xxx",
|
||
"action": {
|
||
"type": "refresh_room",
|
||
"room_id": "room_10001"
|
||
}
|
||
}
|
||
```
|
||
|
||
字段:
|
||
|
||
| 字段 | 说明 |
|
||
| --- | --- |
|
||
| `broadcast_type` | 固定 `room_password_changed` |
|
||
| `scope` | 固定 `region` |
|
||
| `region_id` | 区域 ID |
|
||
| `room_id` | 发生变化的房间 |
|
||
| `locked` | 最新锁房状态 |
|
||
| `room_version` | 房间版本;本地只用更大的版本覆盖旧状态 |
|
||
| `action.type` | 固定 `refresh_room` |
|
||
|
||
处理:
|
||
|
||
| 当前页面 | 行为 |
|
||
| --- | --- |
|
||
| 房间列表页 | 更新对应房间卡片 `locked` |
|
||
| 房间详情页 | 如果 `room_id` 相同,刷新房间快照或更新本地 `locked` |
|
||
| 密码弹窗打开中 | 收到同房间更新后,按最新 `locked` 状态决定是否关闭弹窗 |
|
||
|
||
### 房间群系统消息
|
||
|
||
`room_password_changed` 不走房间群 IM。房间内用户刷新锁房状态依赖区域播报或接口返回的 `room.locked`。
|
||
|
||
## 错误返回
|
||
|
||
失败统一返回:
|
||
|
||
```json
|
||
{
|
||
"code": "PERMISSION_DENIED",
|
||
"message": "permission denied",
|
||
"request_id": "req_abc"
|
||
}
|
||
```
|
||
|
||
常见错误:
|
||
|
||
| HTTP | code | 说明 |
|
||
| --- | --- | --- |
|
||
| `400` | `INVALID_ARGUMENT` | 参数缺失、设置密码时密码为空或超过 64 字符 |
|
||
| `401` | `UNAUTHORIZED` | token 无效或过期 |
|
||
| `403` | `PERMISSION_DENIED` | 非房主设置密码、进房密码错误、用户被 ban |
|
||
| `404` | `NOT_FOUND` | 房间不存在 |
|
||
| `409` | `ROOM_CLOSED` | 房间已关闭 |
|
||
| `409` | `CONFLICT` | 同一个 `command_id` 被不同请求体复用 |
|