package handler import ( "net/http" "time" "github.com/gin-gonic/gin" "github.com/yourname/cyrene-ai/gateway/internal/middleware" "github.com/yourname/cyrene-ai/gateway/internal/ws" ) // SessionHandler 会话管理处理器 type SessionHandler struct { // MVP阶段使用内存存储,后续迁移到PostgreSQL sessions map[string][]SessionInfo // userID -> sessions hub *ws.Hub } // SessionInfo 会话信息 type SessionInfo struct { ID string `json:"id"` UserID string `json:"user_id"` Title string `json:"title"` CreatedAt int64 `json:"created_at"` UpdatedAt int64 `json:"updated_at"` MessageCount int `json:"message_count"` IsActive bool `json:"is_active"` } // NewSessionHandler 创建会话处理器 func NewSessionHandler(hub *ws.Hub) *SessionHandler { return &SessionHandler{ sessions: make(map[string][]SessionInfo), hub: hub, } } // Create 创建新会话 func (h *SessionHandler) Create(c *gin.Context) { userID := middleware.GetUserID(c) var req struct { Title string `json:"title"` } if err := c.ShouldBindJSON(&req); err != nil { // 允许空body req.Title = "新的对话" } if req.Title == "" { req.Title = "新的对话" } session := SessionInfo{ ID: "session_" + randomID(12), UserID: userID, Title: req.Title, CreatedAt: time.Now().UnixMilli(), UpdatedAt: time.Now().UnixMilli(), } h.sessions[userID] = append([]SessionInfo{session}, h.sessions[userID]...) c.JSON(http.StatusCreated, session) } // List 获取会话列表 func (h *SessionHandler) List(c *gin.Context) { userID := middleware.GetUserID(c) sessions, ok := h.sessions[userID] if !ok { sessions = []SessionInfo{} } c.JSON(http.StatusOK, gin.H{ "sessions": sessions, }) } // Delete 删除会话 func (h *SessionHandler) Delete(c *gin.Context) { userID := middleware.GetUserID(c) sessionID := c.Param("id") sessions := h.sessions[userID] for i, s := range sessions { if s.ID == sessionID { h.sessions[userID] = append(sessions[:i], sessions[i+1:]...) c.JSON(http.StatusOK, gin.H{"status": "deleted"}) return } } c.JSON(http.StatusNotFound, gin.H{ "error": "会话不存在", "errorType": "session_not_found", "hint": "会话可能已被删除,或 Gateway 重启后内存数据已清空", }) } // Get 获取单个会话信息 func (h *SessionHandler) Get(c *gin.Context) { userID := middleware.GetUserID(c) sessionID := c.Param("id") for _, s := range h.sessions[userID] { if s.ID == sessionID { c.JSON(http.StatusOK, s) return } } c.JSON(http.StatusNotFound, gin.H{ "error": "会话不存在", "errorType": "session_not_found", "hint": "会话可能已被删除,或 Gateway 重启后内存数据已清空", }) } // GetMessages 获取会话的完整消息列表 func (h *SessionHandler) GetMessages(c *gin.Context) { userID := middleware.GetUserID(c) sessionID := c.Param("id") messages := h.hub.GetConversation(userID, sessionID) if messages == nil { messages = []ws.Message{} } c.JSON(http.StatusOK, gin.H{ "messages": messages, }) } // ========== Admin 端点 ========== // ListActiveSessions 获取当前所有活跃 WebSocket 会话列表 (管理员) func (h *SessionHandler) ListActiveSessions(c *gin.Context) { sessions := h.hub.GetActiveSessions() if sessions == nil { sessions = []*ws.SessionState{} } c.JSON(http.StatusOK, gin.H{ "sessions": sessions, "total": len(sessions), }) } // GetActiveSessions 返回按用户分组的活跃会话列表 func (h *SessionHandler) GetActiveSessions(c *gin.Context) { sessionsByUser := h.hub.GetActiveSessionsByUser() if sessionsByUser == nil { sessionsByUser = make(map[string][]*ws.SessionState) } c.JSON(http.StatusOK, gin.H{ "users": sessionsByUser, }) } // GetSession 获取指定会话的详细信息 (管理员) func (h *SessionHandler) GetSession(c *gin.Context) { sessionID := c.Param("id") if sessionID == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "缺少会话ID"}) return } session := h.hub.GetSession(sessionID) if session == nil { c.JSON(http.StatusNotFound, gin.H{ "error": "会话不存在", "errorType": "session_not_found", "hint": "该会话可能已断开,或 Gateway 重启后内存数据已清空", }) return } c.JSON(http.StatusOK, session) } // 简单的工具函数 func randomID(n int) string { const letters = "abcdefghijklmnopqrstuvwxyz0123456789" b := make([]byte, n) for i := range b { b[i] = letters[i%len(letters)] } // 使用纳秒时间戳增加唯一性 return string(b) }