package handler import ( "net/http" "strconv" "time" "github.com/gin-gonic/gin" "github.com/Tencent/WeKnora/internal/errors" "github.com/Tencent/WeKnora/internal/logger" "github.com/Tencent/WeKnora/internal/types/interfaces" secutils "github.com/Tencent/WeKnora/internal/utils" ) // MessageHandler handles HTTP requests related to messages within chat sessions // It provides endpoints for loading and managing message history type MessageHandler struct { MessageService interfaces.MessageService // Service that implements message business logic } // NewMessageHandler creates a new message handler instance with the required service // Parameters: // - messageService: Service that implements message business logic // // Returns a pointer to a new MessageHandler func NewMessageHandler(messageService interfaces.MessageService) *MessageHandler { return &MessageHandler{ MessageService: messageService, } } // LoadMessages godoc // @Summary 加载消息历史 // @Description 加载会话的消息历史,支持分页和时间筛选 // @Tags 消息 // @Accept json // @Produce json // @Param session_id path string true "会话ID" // @Param limit query int false "返回数量" default(20) // @Param before_time query string false "在此时间之前的消息(RFC3339Nano格式)" // @Success 200 {object} map[string]interface{} "消息列表" // @Failure 400 {object} errors.AppError "请求参数错误" // @Security Bearer // @Security ApiKeyAuth // @Router /messages/{session_id}/load [get] func (h *MessageHandler) LoadMessages(c *gin.Context) { ctx := c.Request.Context() logger.Info(ctx, "Start loading messages") // Get path parameters and query parameters sessionID := secutils.SanitizeForLog(c.Param("session_id")) limit := secutils.SanitizeForLog(c.DefaultQuery("limit", "20")) beforeTimeStr := secutils.SanitizeForLog(c.DefaultQuery("before_time", "")) logger.Infof(ctx, "Loading messages params, session ID: %s, limit: %s, before time: %s", sessionID, limit, beforeTimeStr) // Parse limit parameter with fallback to default limitInt, err := strconv.Atoi(limit) if err != nil { logger.Warnf(ctx, "Invalid limit value, using default value 20, input: %s", limit) limitInt = 20 } // If no beforeTime is provided, retrieve the most recent messages if beforeTimeStr == "" { logger.Infof(ctx, "Getting recent messages for session, session ID: %s, limit: %d", sessionID, limitInt) messages, err := h.MessageService.GetRecentMessagesBySession(ctx, sessionID, limitInt) if err != nil { logger.ErrorWithFields(ctx, err, nil) c.Error(errors.NewInternalServerError(err.Error())) return } logger.Infof( ctx, "Successfully retrieved recent messages, session ID: %s, message count: %d", sessionID, len(messages), ) c.JSON(http.StatusOK, gin.H{ "success": true, "data": messages, }) return } // If beforeTime is provided, parse the timestamp beforeTime, err := time.Parse(time.RFC3339Nano, beforeTimeStr) if err != nil { logger.Errorf( ctx, "Invalid time format, please use RFC3339Nano format, err: %v, beforeTimeStr: %s", err, beforeTimeStr, ) c.Error(errors.NewBadRequestError("Invalid time format, please use RFC3339Nano format")) return } // Retrieve messages before the specified timestamp logger.Infof(ctx, "Getting messages before specific time, session ID: %s, before time: %s, limit: %d", sessionID, beforeTime.Format(time.RFC3339Nano), limitInt) messages, err := h.MessageService.GetMessagesBySessionBeforeTime(ctx, sessionID, beforeTime, limitInt) if err != nil { logger.ErrorWithFields(ctx, err, nil) c.Error(errors.NewInternalServerError(err.Error())) return } logger.Infof( ctx, "Successfully retrieved messages before time, session ID: %s, message count: %d", sessionID, len(messages), ) c.JSON(http.StatusOK, gin.H{ "success": true, "data": messages, }) } // DeleteMessage godoc // @Summary 删除消息 // @Description 从会话中删除指定消息 // @Tags 消息 // @Accept json // @Produce json // @Param session_id path string true "会话ID" // @Param id path string true "消息ID" // @Success 200 {object} map[string]interface{} "删除成功" // @Failure 500 {object} errors.AppError "服务器错误" // @Security Bearer // @Security ApiKeyAuth // @Router /messages/{session_id}/{id} [delete] func (h *MessageHandler) DeleteMessage(c *gin.Context) { ctx := c.Request.Context() logger.Info(ctx, "Start deleting message") // Get path parameters for session and message identification sessionID := secutils.SanitizeForLog(c.Param("session_id")) messageID := secutils.SanitizeForLog(c.Param("id")) logger.Infof(ctx, "Deleting message, session ID: %s, message ID: %s", sessionID, messageID) // Delete the message using the message service if err := h.MessageService.DeleteMessage(ctx, sessionID, messageID); err != nil { logger.ErrorWithFields(ctx, err, nil) c.Error(errors.NewInternalServerError(err.Error())) return } logger.Infof(ctx, "Message deleted successfully, session ID: %s, message ID: %s", sessionID, messageID) c.JSON(http.StatusOK, gin.H{ "success": true, "message": "Message deleted successfully", }) }