feat(phase2e-2): WebSocket 信令协议 13 事件全量落地(Task 6)

将 meeting.* 事件族从 Task 5 的 PublishToUser 循环升级为完整 WS 信令协议:
抽离统一广播层、扩容 MediaOrchestrator 接口、实现 8 个 C→S 事件业务逻辑
+ Redis 资源追踪 + host 权限校验,端到端 18/18 PASS。

核心产出:
- 新建 MeetingBroadcaster(统一广播层,REST/WS 共用)
- 新建 MeetingSignalService 8 C→S 事件 + cleanupUserResources
- 新建 MeetingWSHandler 薄层 controller
- MediaOrchestrator 扩容 9 方法 + NoopMediaOrchestrator 占位(Task 7 替换)
- C→S 白名单机制防恶意伪造广播事件
- Redis Set 资源追踪防 mediasoup 端资源泄漏

文档同步:
- docs/api/frontend/meeting.md 追加 §WebSocket 信令协议(Task 6)200 行
- docs/progress/CURRENT_STATUS.md + project-context.mdc + 实施计划 Task 6 

Made-with: Cursor
This commit is contained in:
bujinyuan
2026-04-21 17:10:32 +08:00
parent e235e001b3
commit 096563d3ea
13 changed files with 1212 additions and 107 deletions

View File

@@ -92,23 +92,43 @@ const (
MeetingChatRetentionHours = 24 // 会议聊天保留时长(会议结束后)
)
// 会议 WS 事件常量(设计文档 §6.311 个事件
// 会议 WS 事件常量(设计文档 §6.3
// 命名格式meeting.{domain}.{action}
// 方向说明C→S客户端发往服务端需 ACKS→C服务端广播/定向推送,不需 ACK
const (
// 房间级事件
MeetingWSEventRoomEnded = "meeting.room.ended" // 会议已结束
MeetingWSEventRoomLocked = "meeting.room.locked" // 会议被锁定等候室Phase 2e-3
MeetingWSEventRoomHostChange = "meeting.room.host.changed" // 主持人变更
// ====== 房间组3 个)======
MeetingWSEventRoomJoin = "meeting.room.join" // C→S加入会议后的"宣告在线",绑定 WS 连接 ↔ roomCode
MeetingWSEventRoomLeave = "meeting.room.leave" // C→S主动离会等价 REST leave但保留信令触发入口
MeetingWSEventRoomEnded = "meeting.room.ended" // S→C会议已结束广播全员
// 成员级事件
MeetingWSEventMemberJoined = "meeting.member.joined" // 新成员加入
MeetingWSEventMemberLeft = "meeting.member.left" // 成员离开
MeetingWSEventMemberStateChange = "meeting.member.state.changed" // 麦克风 / 摄像头状态变化
MeetingWSEventMemberKicked = "meeting.member.kicked" // 被移出
// ====== 成员组5 个)======
MeetingWSEventMemberJoined = "meeting.member.joined" // S→C新成员加入
MeetingWSEventMemberLeft = "meeting.member.left" // S→C成员离开
MeetingWSEventMemberStateChange = "meeting.member.state.changed" // 双向:麦克风 / 摄像头状态变化host 可带 target_user_id 强制静音他人)
MeetingWSEventMemberKicked = "meeting.member.kicked" // S→C被移出会议定向发给被踢者
MeetingWSEventMemberProducerNew = "meeting.member.producer.new" // S→C有新 producer 可订阅produce.start 成功后广播)
MeetingWSEventHostChanged = "meeting.host.changed" // S→C主持人变更
// 媒体级事件Go 发起,驱动客户端 mediasoup-client 订阅/取消)
MeetingWSEventProducerNew = "meeting.producer.new" // 有新 producer 可订阅
MeetingWSEventProducerClosed = "meeting.producer.closed" // producer 已关闭
MeetingWSEventConsumerResumed = "meeting.consumer.resumed" // consumer 已恢复(由服务端触发
MeetingWSEventChatMessage = "meeting.chat.message" // 会议内文字聊天
// ====== 媒体组5 个mediasoup signaling 桥接)======
MeetingWSEventTransportCreate = "meeting.transport.create" // C→S→Node创建 Transport
MeetingWSEventTransportConnect = "meeting.transport.connect" // C→S→NodeTransport DTLS 握手
MeetingWSEventProduceStart = "meeting.produce.start" // C→S→Node创建 Producer广播 producer.new
MeetingWSEventConsumeStart = "meeting.consume.start" // C→S→Node订阅远端 Producer创建本地 Consumer
MeetingWSEventProducerClose = "meeting.producer.close" // C→S→Node关闭自己的 Producer推流停止
// ====== 补充事件(非 §6.3 核心 11 事件,但业务必须)======
MeetingWSEventChatMessage = "meeting.chat.message" // S→C会议内文字聊天广播REST SendChat 触发)
)
// MeetingWSClientEvents 客户端可主动发起的 WS 事件C→S白名单
// 用于 WS 消息路由时快速校验事件名合法性
var MeetingWSClientEvents = []string{
MeetingWSEventRoomJoin,
MeetingWSEventRoomLeave,
MeetingWSEventMemberStateChange,
MeetingWSEventTransportCreate,
MeetingWSEventTransportConnect,
MeetingWSEventProduceStart,
MeetingWSEventConsumeStart,
MeetingWSEventProducerClose,
}