diff --git a/internal/room/room.go b/internal/room/room.go index 3fcab93..3f189d2 100644 --- a/internal/room/room.go +++ b/internal/room/room.go @@ -87,9 +87,13 @@ type Room struct { createdAt int64 // 房间创建时间戳 lastActive int64 // 最近活跃时间戳(清理判定) lastResult map[string]any // 上一局结算信息(房间内展示) + inviteAt map[int]int64 // 对好友最近一次邀请时间(userID → unix),冷却 60 秒 closed bool // 房间是否已关闭 } +// 同一好友再次邀请的最短间隔 +const inviteCooldown = 60 * time.Second + // newRoom 构造房间:按游戏类型确定座位数,按配置构造 AI 实例 func newRoom(code, game, mode, aiProvider, aiDifficulty string) *Room { if aiProvider == "" { @@ -544,6 +548,18 @@ func (r *Room) handleMessage(c *Client, msgType string, raw json.RawMessage) { return } } + // 同一好友 60 秒内不可重复邀请 + now := time.Now().Unix() + if r.inviteAt == nil { + r.inviteAt = map[int]int64{} + } + if last, ok := r.inviteAt[req.UserID]; ok { + left := int64(inviteCooldown.Seconds()) - (now - last) + if left > 0 { + c.pushError(fmt.Sprintf("请 %d 秒后再邀请该好友", left)) + return + } + } gameName := r.Game var g model.Game if err := database.DB.Where("code = ?", r.Game).First(&g).Error; err == nil && g.Name != "" { @@ -563,7 +579,8 @@ func (r *Room) handleMessage(c *Client, msgType string, raw json.RawMessage) { }) } } - c.push("invite_sent", map[string]any{"user_id": req.UserID}) + r.inviteAt[req.UserID] = now + c.push("invite_sent", map[string]any{"user_id": req.UserID, "cooldown": int(inviteCooldown.Seconds())}) case "chat": var req struct { Text string `json:"text"`