Files
EchoChat/backend/go-service/pkg/utils/meeting_code.go
bujinyuan e235e001b3 feat(phase2e-2): Go meeting 模块 12 个 REST 接口业务逻辑全量落地(Task 5)
主要产出:
- DTO 层:app/dto/meeting_dto.go 完整定义 13 个 DTO(请求/响应/基础共用)
- Service 层:MeetingService 12 业务方法 + 11 个 sentinel 错误 + 4 辅助
  - CreateRoom/JoinRoom/LeaveRoom/EndRoom 核心生命周期
  - KickMember/TransferHost/GetRoom/ListMyMeetings 会议管理
  - InviteUsers(+ NotifyPusher)/ RedeemInviteToken 邀请链路
  - SendChat/ListChats 会议内聊天
- Controller 层:12 handler + handleError 领域错误 → HTTP 映射
- 工具层:pkg/utils/meeting_code.go(XXX-XXX-XXX + invite token)
- Stub 接口:MediaOrchestrator(Task 7 替换)+ NoopMediaOrchestrator
- 路径修正:/rooms → /rooms/mine、/invites → /invite-tokens 对齐设计
- DAO 契约修复:GetByID/GetByCode/GetByRoomAndUser/FindActiveByUser
  将 gorm.ErrRecordNotFound 转为 (nil, nil),service 统一 nil 判定
- 安全强化:密码 bcrypt + 5 次错误锁 10 分钟;邀请 token 仅通过
  NotifyPusher.Extra 定向下发,响应不回传
- host 自动转让:host 离会时将最早加入者提升为 host
- 单点参会:用户同一时间仅能在一个活跃会议
- API 文档:docs/api/frontend/meeting.md 重写为 12 接口完整规范
- Wire 依赖注入:MediaOrchestrator + NoopMediaOrchestrator provider

验证:
- go build / go vet / wire 零告警
- 端到端 3 用户场景:12 happy path + 5 错误路径 PASS=19 / FAIL=0
  覆盖密码错/房间不存在/单点冲突/越权/邀请失效

文档同步:
- docs/progress/CURRENT_STATUS.md 增补 Task 5 章节
- .cursor/rules/project-context.mdc 更新阶段状态
- docs/plans/2026-04-21-phase2e-2-implementation.plan.md 标记 T5 

下一步:Task 6(WS 信令协议 + BroadcastToMeeting 替换 PublishToUser 循环)

Made-with: Cursor
2026-04-21 16:39:59 +08:00

42 lines
1.5 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 utils
import (
"crypto/rand"
"encoding/hex"
"fmt"
"math/big"
)
// meetingCodeDigitGroups 会议号的 3 段 × 3 位数字布局XXX-XXX-XXX
// 每段由 [0, 1000) 的 crypto/rand 数字零填充为 3 位构成
// 去除连字符后总长度与 constants.MeetingRoomCodeLength (=9) 对齐
const meetingCodeDigitGroups = 3
const meetingCodeDigitPerGroup = 3
// GenerateMeetingRoomCode 生成 9 位随机会议号,格式为 XXX-XXX-XXX
// 使用 crypto/rand 保证足够熵,服务端持久化时可按需去除连字符
// 返回示例329-471-086
func GenerateMeetingRoomCode() (string, error) {
parts := make([]string, meetingCodeDigitGroups)
maxPerGroup := big.NewInt(1000) // 每段 [0, 999]
for i := 0; i < meetingCodeDigitGroups; i++ {
n, err := rand.Int(rand.Reader, maxPerGroup)
if err != nil {
return "", fmt.Errorf("生成会议号随机数失败: %w", err)
}
parts[i] = fmt.Sprintf("%0*d", meetingCodeDigitPerGroup, n.Int64())
}
return parts[0] + "-" + parts[1] + "-" + parts[2], nil
}
// GenerateMeetingInviteToken 生成邀请链接用的高熵 Token32 hex 字符16 字节随机)
// 用于 Redis key echo:meeting:invite:{token} 的兑换凭证
// Token 不包含会议号等敏感信息,仅作为索引,查询时回查 Redis 值获取完整 payload
func GenerateMeetingInviteToken() (string, error) {
buf := make([]byte, 16)
if _, err := rand.Read(buf); err != nil {
return "", fmt.Errorf("生成邀请 Token 随机数失败: %w", err)
}
return hex.EncodeToString(buf), nil
}