// Package handler provides HTTP handlers for various endpoints. package handler import ( "strings" "modelRT/constants" "modelRT/database" "modelRT/logger" "modelRT/network" "modelRT/orm" "github.com/gin-gonic/gin" "github.com/gofrs/uuid" ) // AsyncTaskResultQueryHandler handles querying of asynchronous task results // @Summary 查询异步任务结果 // @Description 根据任务ID列表查询异步任务的状态和结果 // @Tags AsyncTask // @Accept json // @Produce json // @Param task_ids query string true "任务ID列表,用逗号分隔" // @Success 200 {object} network.SuccessResponse{payload=network.AsyncTaskResultQueryResponse} "查询成功" // @Failure 200 {object} network.FailureResponse "请求参数错误" // @Router /task/async/results [get] func AsyncTaskResultQueryHandler(c *gin.Context) { ctx := c.Request.Context() taskIDsParam := c.Query("task_ids") if taskIDsParam == "" { logger.Error(ctx, "task_ids parameter is required") renderRespFailure(c, constants.RespCodeInvalidParams, "task_ids parameter is required", nil) return } var taskIDs []uuid.UUID taskIDStrs := splitCommaSeparated(taskIDsParam) for _, taskIDStr := range taskIDStrs { taskID, err := uuid.FromString(taskIDStr) if err != nil { logger.Error(ctx, "invalid task ID format", "task_id", taskIDStr, "error", err) renderRespFailure(c, constants.RespCodeInvalidParams, "invalid task ID format", nil) return } taskIDs = append(taskIDs, taskID) } if len(taskIDs) == 0 { logger.Error(ctx, "no valid task IDs provided") renderRespFailure(c, constants.RespCodeInvalidParams, "no valid task IDs provided", nil) return } pgClient := database.GetPostgresDBClient() if pgClient == nil { logger.Error(ctx, "database connection not found in context") renderRespFailure(c, constants.RespCodeServerError, "database connection error", nil) return } asyncTasks, err := database.GetAsyncTasksByIDs(ctx, pgClient, taskIDs) if err != nil { logger.Error(ctx, "failed to query async tasks from database", "error", err) renderRespFailure(c, constants.RespCodeServerError, "failed to query tasks", nil) return } taskResults, err := database.GetAsyncTaskResults(ctx, pgClient, taskIDs) if err != nil { logger.Error(ctx, "failed to query async task results from database", "error", err) renderRespFailure(c, constants.RespCodeServerError, "failed to query task results", nil) return } taskResultMap := make(map[uuid.UUID]orm.AsyncTaskResult) for _, result := range taskResults { taskResultMap[result.TaskID] = result } var responseTasks []network.AsyncTaskResult for _, asyncTask := range asyncTasks { taskResult := network.AsyncTaskResult{ TaskID: asyncTask.TaskID, TaskType: string(asyncTask.TaskType), Status: string(asyncTask.Status), CreatedAt: asyncTask.CreatedAt, FinishedAt: asyncTask.FinishedAt, Progress: asyncTask.Progress, } if result, exists := taskResultMap[asyncTask.TaskID]; exists { if result.Result != nil { taskResult.Result = map[string]any(result.Result) } if result.ErrorCode != nil { taskResult.ErrorCode = result.ErrorCode } if result.ErrorMessage != nil { taskResult.ErrorMessage = result.ErrorMessage } if result.ErrorDetail != nil { taskResult.ErrorDetail = map[string]any(result.ErrorDetail) } } responseTasks = append(responseTasks, taskResult) } renderRespSuccess(c, constants.RespCodeSuccess, "query completed", network.AsyncTaskResultQueryResponse{ Total: len(responseTasks), Tasks: responseTasks, }) } func splitCommaSeparated(s string) []string { var result []string var current strings.Builder inQuotes := false escape := false for _, ch := range s { if escape { current.WriteRune(ch) escape = false continue } switch ch { case '\\': escape = true case '"': inQuotes = !inQuotes case ',': if !inQuotes { result = append(result, strings.TrimSpace(current.String())) current.Reset() } else { current.WriteRune(ch) } default: current.WriteRune(ch) } } if current.Len() > 0 { result = append(result, strings.TrimSpace(current.String())) } return result }