Files
EchoChat/backend/go-service/app/constants/meeting.go
bujinyuan f97fec24a8 feat(phase2e-2): 前端 mediasoup-client 集成 + Pinia meeting Store(Task 9)
- frontend/src/api/meeting.js:12 个 REST 接口封装,统一 unwrap envelope.data
- frontend/src/services/websocket.js:新增 sendWithAck(Promise 化 + 超时 + 序列号)
- frontend/src/utils/mediasoup-client.js:MediaEngine 包装 Device/Transport/Producer/Consumer
- frontend/src/store/meeting.js:Pinia 会议状态机,桥接 14 个 WS 事件 + cleanupStaleMeetings
- frontend/src/constants/meeting.js:状态枚举 + 事件名集中管理
- frontend/src/pages/meeting/debug.vue:临时调试页(H5 原生 video/audio DOM 绕过 uni 组件限制)
- backend:meeting.consume.resume WS 事件 + create/join 响应透传 router_id + rtp_capabilities
- 文档:frontend/meeting.md、websocket.md、CURRENT_STATUS、plan 全部同步 Task 9 落地

Made-with: Cursor
2026-04-22 11:22:49 +08:00

137 lines
6.3 KiB
Go
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.

package constants
// 会议相关常量Phase 2e-2
// 包含:会议类型、会议状态、参与者角色、结束原因、离会原因、默认配置
// 所有枚举值严禁直接用中文字符串,中文仅用于 *Map 展示
// 会议类型meeting_rooms.type
const (
MeetingTypeInstant = 1 // 即时会议MVP 仅此)
MeetingTypeScheduled = 2 // 预约会议Phase 2e-3
)
// MeetingTypeMap 会议类型中文映射
var MeetingTypeMap = map[int]string{
MeetingTypeInstant: "即时会议",
MeetingTypeScheduled: "预约会议",
}
// 会议状态meeting_rooms.status
const (
MeetingStatusPending = 0 // 未开始(仅预约会议使用)
MeetingStatusActive = 1 // 进行中
MeetingStatusEnded = 2 // 已结束
)
// MeetingStatusMap 会议状态中文映射
var MeetingStatusMap = map[int]string{
MeetingStatusPending: "未开始",
MeetingStatusActive: "进行中",
MeetingStatusEnded: "已结束",
}
// 会议参与者角色meeting_participants.role
// MVP 仅使用 Participant / Host 两档CoHost 保留至第二期
const (
MeetingRoleParticipant = 0 // 普通参会人
MeetingRoleHost = 1 // 主持人
MeetingRoleCoHost = 2 // 联合主持人保留MVP 不用)
)
// MeetingRoleMap 参与者角色中文映射
var MeetingRoleMap = map[int]string{
MeetingRoleParticipant: "参会人",
MeetingRoleHost: "主持人",
MeetingRoleCoHost: "联合主持人",
}
// 会议结束原因meeting_rooms.ended_reason
const (
MeetingEndedReasonHostEnded = "host_ended" // 主持人主动结束
MeetingEndedReasonEmptyTTL = "empty_ttl" // 空房超时销毁
MeetingEndedReasonAdminForce = "admin_force" // 管理员强制结束
MeetingEndedReasonSystemError = "system_error" // 系统异常(如 Node worker died
)
// MeetingEndedReasonMap 结束原因中文映射
var MeetingEndedReasonMap = map[string]string{
MeetingEndedReasonHostEnded: "主持人结束",
MeetingEndedReasonEmptyTTL: "空房超时",
MeetingEndedReasonAdminForce: "管理员强制结束",
MeetingEndedReasonSystemError: "系统异常",
}
// 离会原因meeting_participants.left_reason
const (
MeetingLeftReasonSelf = "self" // 主动离会
MeetingLeftReasonKicked = "kicked" // 被主持人移除
MeetingLeftReasonHostEnd = "host_end" // 主持人结束会议
MeetingLeftReasonEmptyTTL = "empty_ttl" // 空房 TTL 触发
MeetingLeftReasonDisconnect = "disconnect" // 网络断开(宽限期结束仍未重连)
)
// MeetingLeftReasonMap 离会原因中文映射
var MeetingLeftReasonMap = map[string]string{
MeetingLeftReasonSelf: "主动离开",
MeetingLeftReasonKicked: "被移除",
MeetingLeftReasonHostEnd: "会议结束",
MeetingLeftReasonEmptyTTL: "空房超时",
MeetingLeftReasonDisconnect: "网络断开",
}
// 会议默认配置(应用层强制约束)
const (
MeetingMVPMaxMembers = 8 // MVP 阶段单会议硬上限
MeetingRoomCodeLength = 9 // 会议号去连字符后的长度XXX-XXX-XXX
MeetingRoomCodeRetryMax = 3 // 生成会议号冲突重试上限
MeetingPasswordMaxAttempts = 5 // 密码连续错误锁定阈值
MeetingPasswordLockSeconds = 600 // 密码锁定时长10 分钟)
MeetingHostGraceSeconds = 120 // 主持人掉线宽限期2 分钟)
MeetingEmptyRoomTTLSeconds = 300 // 空房销毁 TTL5 分钟)
MeetingInviteTokenTTL = 600 // 邀请链接 Token TTL10 分钟)
MeetingChatRetentionHours = 24 // 会议聊天保留时长(会议结束后)
)
// 会议 WS 事件常量(设计文档 §6.3
// 命名格式meeting.{domain}.{action}
// 方向说明C→S客户端发往服务端需 ACKS→C服务端广播/定向推送,不需 ACK
const (
// ====== 房间组3 个)======
MeetingWSEventRoomJoin = "meeting.room.join" // C→S加入会议后的"宣告在线",绑定 WS 连接 ↔ roomCode
MeetingWSEventRoomLeave = "meeting.room.leave" // C→S主动离会等价 REST leave但保留信令触发入口
MeetingWSEventRoomEnded = "meeting.room.ended" // S→C会议已结束广播全员
// ====== 成员组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主持人变更
// ====== 媒体组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
MeetingWSEventConsumeResume = "meeting.consume.resume" // C→S→NodeConsumer 订阅后由前端 track 挂载就绪再 resume防止首帧丢失Task 9 引入)
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,
MeetingWSEventConsumeResume,
MeetingWSEventProducerClose,
}