package httpapi import ( "encoding/json" "errors" "net/http" "strings" "github.com/easyai/easyai-ai-gateway/apps/api/internal/store" ) // listRuntimePolicySets godoc // @Summary 列出运行策略集 // @Description 管理端返回可分配给平台、模型或用户组的运行策略集。 // @Tags runtime // @Produce json // @Security BearerAuth // @Success 200 {object} RuntimePolicySetListResponse // @Failure 401 {object} ErrorEnvelope // @Failure 403 {object} ErrorEnvelope // @Failure 500 {object} ErrorEnvelope // @Router /api/admin/runtime/policy-sets [get] func (s *Server) listRuntimePolicySets(w http.ResponseWriter, r *http.Request) { items, err := s.store.ListRuntimePolicySets(r.Context()) if err != nil { s.logger.Error("list runtime policy sets failed", "error", err) writeError(w, http.StatusInternalServerError, "list runtime policy sets failed") return } writeJSON(w, http.StatusOK, map[string]any{"items": items}) } // getRunnerPolicy godoc // @Summary 获取 Runner 策略 // @Description 管理端获取当前生效的默认 Runner 调度策略。 // @Tags runtime // @Produce json // @Security BearerAuth // @Success 200 {object} store.RunnerPolicy // @Failure 401 {object} ErrorEnvelope // @Failure 403 {object} ErrorEnvelope // @Failure 500 {object} ErrorEnvelope // @Router /api/admin/runtime/runner-policy [get] func (s *Server) getRunnerPolicy(w http.ResponseWriter, r *http.Request) { item, err := s.store.GetActiveRunnerPolicy(r.Context()) if err != nil { s.logger.Error("get runner policy failed", "error", err) writeError(w, http.StatusInternalServerError, "get runner policy failed") return } writeJSON(w, http.StatusOK, item) } // updateRunnerPolicy godoc // @Summary 更新 Runner 策略 // @Description 管理端写入默认 Runner 调度策略。 // @Tags runtime // @Accept json // @Produce json // @Security BearerAuth // @Param input body store.RunnerPolicyInput true "Runner 策略请求" // @Success 200 {object} store.RunnerPolicy // @Failure 400 {object} ErrorEnvelope // @Failure 401 {object} ErrorEnvelope // @Failure 403 {object} ErrorEnvelope // @Failure 500 {object} ErrorEnvelope // @Router /api/admin/runtime/runner-policy [patch] func (s *Server) updateRunnerPolicy(w http.ResponseWriter, r *http.Request) { var input store.RunnerPolicyInput if err := json.NewDecoder(r.Body).Decode(&input); err != nil { writeError(w, http.StatusBadRequest, "invalid json body") return } item, err := s.store.UpsertDefaultRunnerPolicy(r.Context(), input) if err != nil { s.logger.Error("update runner policy failed", "error", err) writeError(w, http.StatusInternalServerError, "update runner policy failed") return } writeJSON(w, http.StatusOK, item) } type updatePlatformDynamicPriorityRequest struct { DynamicPriority *int `json:"dynamicPriority" example:"10"` Reset bool `json:"reset" example:"false"` } // updatePlatformDynamicPriority godoc // @Summary 更新平台动态优先级 // @Description 管理端调整平台运行时动态优先级;reset 为 true 时清空动态值。 // @Tags runtime // @Accept json // @Produce json // @Security BearerAuth // @Param platformID path string true "平台 ID" // @Param input body updatePlatformDynamicPriorityRequest true "动态优先级请求" // @Success 200 {object} store.Platform // @Failure 400 {object} ErrorEnvelope // @Failure 401 {object} ErrorEnvelope // @Failure 403 {object} ErrorEnvelope // @Failure 404 {object} ErrorEnvelope // @Failure 500 {object} ErrorEnvelope // @Router /api/admin/platforms/{platformID}/dynamic-priority [patch] func (s *Server) updatePlatformDynamicPriority(w http.ResponseWriter, r *http.Request) { var input updatePlatformDynamicPriorityRequest if err := json.NewDecoder(r.Body).Decode(&input); err != nil { writeError(w, http.StatusBadRequest, "invalid json body") return } var dynamicPriority *int if input.Reset { dynamicPriority = nil } else { if input.DynamicPriority == nil { writeError(w, http.StatusBadRequest, "dynamicPriority is required unless reset is true") return } if *input.DynamicPriority < 0 { writeError(w, http.StatusBadRequest, "dynamicPriority must be greater than or equal to 0") return } dynamicPriority = input.DynamicPriority } item, err := s.store.UpdatePlatformDynamicPriority(r.Context(), r.PathValue("platformID"), dynamicPriority) if err != nil { if store.IsNotFound(err) { writeError(w, http.StatusNotFound, "platform not found") return } s.logger.Error("update platform dynamic priority failed", "error", err) writeError(w, http.StatusInternalServerError, "update platform dynamic priority failed") return } writeJSON(w, http.StatusOK, item) } // createRuntimePolicySet godoc // @Summary 创建运行策略集 // @Description 管理端创建运行策略集,policyKey 和 name 必填。 // @Tags runtime // @Accept json // @Produce json // @Security BearerAuth // @Param input body store.RuntimePolicySetInput true "运行策略集请求" // @Success 201 {object} store.RuntimePolicySet // @Failure 400 {object} ErrorEnvelope // @Failure 401 {object} ErrorEnvelope // @Failure 403 {object} ErrorEnvelope // @Failure 409 {object} ErrorEnvelope // @Failure 500 {object} ErrorEnvelope // @Router /api/admin/runtime/policy-sets [post] func (s *Server) createRuntimePolicySet(w http.ResponseWriter, r *http.Request) { var input store.RuntimePolicySetInput if err := json.NewDecoder(r.Body).Decode(&input); err != nil { writeError(w, http.StatusBadRequest, "invalid json body") return } if !validRuntimePolicyInput(input) { writeError(w, http.StatusBadRequest, "policyKey and name are required") return } item, err := s.store.CreateRuntimePolicySet(r.Context(), input) if err != nil { if store.IsUniqueViolation(err) { writeError(w, http.StatusConflict, "runtime policy key already exists") return } s.logger.Error("create runtime policy set failed", "error", err) writeError(w, http.StatusInternalServerError, "create runtime policy set failed") return } writeJSON(w, http.StatusCreated, item) } // updateRuntimePolicySet godoc // @Summary 更新运行策略集 // @Description 管理端更新运行策略集及其限流、重试、超时等策略配置。 // @Tags runtime // @Accept json // @Produce json // @Security BearerAuth // @Param policySetID path string true "运行策略集 ID" // @Param input body store.RuntimePolicySetInput true "运行策略集请求" // @Success 200 {object} store.RuntimePolicySet // @Failure 400 {object} ErrorEnvelope // @Failure 401 {object} ErrorEnvelope // @Failure 403 {object} ErrorEnvelope // @Failure 404 {object} ErrorEnvelope // @Failure 409 {object} ErrorEnvelope // @Failure 500 {object} ErrorEnvelope // @Router /api/admin/runtime/policy-sets/{policySetID} [patch] func (s *Server) updateRuntimePolicySet(w http.ResponseWriter, r *http.Request) { var input store.RuntimePolicySetInput if err := json.NewDecoder(r.Body).Decode(&input); err != nil { writeError(w, http.StatusBadRequest, "invalid json body") return } if !validRuntimePolicyInput(input) { writeError(w, http.StatusBadRequest, "policyKey and name are required") return } item, err := s.store.UpdateRuntimePolicySet(r.Context(), r.PathValue("policySetID"), input) if err != nil { if store.IsNotFound(err) { writeError(w, http.StatusNotFound, "runtime policy set not found") return } if store.IsUniqueViolation(err) { writeError(w, http.StatusConflict, "runtime policy key already exists") return } s.logger.Error("update runtime policy set failed", "error", err) writeError(w, http.StatusInternalServerError, "update runtime policy set failed") return } writeJSON(w, http.StatusOK, item) } // deleteRuntimePolicySet godoc // @Summary 删除运行策略集 // @Description 管理端删除非默认运行策略集;默认策略集受保护。 // @Tags runtime // @Produce json // @Security BearerAuth // @Param policySetID path string true "运行策略集 ID" // @Success 204 "No Content" // @Failure 401 {object} ErrorEnvelope // @Failure 403 {object} ErrorEnvelope // @Failure 404 {object} ErrorEnvelope // @Failure 500 {object} ErrorEnvelope // @Router /api/admin/runtime/policy-sets/{policySetID} [delete] func (s *Server) deleteRuntimePolicySet(w http.ResponseWriter, r *http.Request) { if err := s.store.DeleteRuntimePolicySet(r.Context(), r.PathValue("policySetID")); err != nil { if store.IsNotFound(err) { writeError(w, http.StatusNotFound, "runtime policy set not found") return } if errors.Is(err, store.ErrProtectedDefault) { writeError(w, http.StatusForbidden, "default runtime policy set cannot be deleted") return } s.logger.Error("delete runtime policy set failed", "error", err) writeError(w, http.StatusInternalServerError, "delete runtime policy set failed") return } w.WriteHeader(http.StatusNoContent) } func validRuntimePolicyInput(input store.RuntimePolicySetInput) bool { return strings.TrimSpace(input.PolicyKey) != "" && strings.TrimSpace(input.Name) != "" }