功能修改
This commit is contained in:
@@ -47,6 +47,16 @@ func (h *coreHandlers) register(mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/v1/game-plugins/{id}", h.gamePluginDetail)
|
||||
mux.HandleFunc("/api/v1/metrics/platform", h.platformMetrics)
|
||||
mux.HandleFunc("/api/v1/metrics/server-instances", h.serverInstanceMetrics)
|
||||
mux.HandleFunc("/api/v1/production/capacity", h.productionCapacity)
|
||||
mux.HandleFunc("/api/v1/production/capacity/admission", h.productionCapacityAdmission)
|
||||
mux.HandleFunc("/api/v1/alerts", h.alerts)
|
||||
mux.HandleFunc("/api/v1/alerts/{id}/acknowledge", h.alertAcknowledge)
|
||||
mux.HandleFunc("/api/v1/alerts/{id}/resolve", h.alertResolve)
|
||||
mux.HandleFunc("/api/v1/alerts/{id}/retry", h.alertRetry)
|
||||
mux.HandleFunc("/api/v1/plugin-lifecycles", h.pluginLifecycles)
|
||||
mux.HandleFunc("/api/v1/plugin-lifecycles/{pluginId}/actions", h.pluginLifecycleAction)
|
||||
mux.HandleFunc("/api/v1/ai/config-diffs", h.aiConfigDiffs)
|
||||
mux.HandleFunc("/api/v1/ai/config-diffs/{id}/approve", h.aiConfigDiffApprove)
|
||||
mux.HandleFunc("/api/v1/metrics/server-instances/history", h.metricHistory)
|
||||
mux.HandleFunc("/api/v1/run/metrics/batches", h.requireRunSignature(h.runMetricBatchIngest))
|
||||
mux.HandleFunc("/api/v1/backups", h.backups)
|
||||
@@ -74,6 +84,11 @@ func (h *coreHandlers) register(mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/v1/server-instances/{id}/client-managers/retry", h.serverClientManagerRetry)
|
||||
mux.HandleFunc("/api/v1/server-instances/{id}/client-managers/revoke-session", h.serverClientManagerRevokeSession)
|
||||
mux.HandleFunc("/api/v1/server-instances/{id}/client-managers/uninstall", h.serverClientManagerUninstall)
|
||||
mux.HandleFunc("/api/v1/server-instances/{id}/game-client-bridge", h.serverGameClientBridgeStatus)
|
||||
mux.HandleFunc("/api/v1/server-instances/{id}/game-client-bridge/commands", h.serverGameClientBridgeCommands)
|
||||
mux.HandleFunc("/api/v1/server-instances/{id}/game-client-bridge/commands/{commandId}/cancel", h.serverGameClientBridgeCommandCancel)
|
||||
mux.HandleFunc("/api/v1/server-instances/{id}/game-client-bridge/commands/{commandId}", h.serverGameClientBridgeCommandDetail)
|
||||
mux.HandleFunc("/api/v1/server-instances/{id}/game-client-bridge/snapshots", h.serverGameClientBridgeSnapshots)
|
||||
mux.HandleFunc("/api/v1/server-instances/{id}/dependencies/check", h.serverDependenciesCheck)
|
||||
mux.HandleFunc("/api/v1/server-instances/{id}/dependencies/install", h.serverDependenciesInstall)
|
||||
mux.HandleFunc("/api/v1/server-instances/{id}/dependencies", h.serverDependencies)
|
||||
@@ -123,6 +138,290 @@ func (h *coreHandlers) register(mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/v1/audit-events/{id}", h.auditEventDetail)
|
||||
mux.HandleFunc("/api/v1/client-managers/register", h.clientManagerRegister)
|
||||
mux.HandleFunc("/api/v1/client-managers/heartbeat", h.clientManagerHeartbeat)
|
||||
mux.HandleFunc("/api/v1/game-client-bridge/companion/commands/claim", h.gameClientBridgeCompanionClaim)
|
||||
mux.HandleFunc("/api/v1/game-client-bridge/companion/commands/{commandId}/ack", h.gameClientBridgeCompanionAck)
|
||||
mux.HandleFunc("/api/v1/game-client-bridge/companion/commands/{commandId}/result", h.gameClientBridgeCompanionResult)
|
||||
mux.HandleFunc("/api/v1/game-client-bridge/companion/snapshots", h.gameClientBridgeCompanionSnapshot)
|
||||
mux.HandleFunc("/api/v1/game-client-bridge/companion/diagnostics", h.gameClientBridgeCompanionDiagnostics)
|
||||
}
|
||||
|
||||
// productionCapacity godoc
|
||||
// @Summary Get production capacity governance state
|
||||
// @Description Returns bounded Run endpoint capacity and durable pressure counts visible to the current operator.
|
||||
// @Tags production-operations
|
||||
// @Produce json
|
||||
// @Success 200 {object} dto.ProductionCapacitySummaryResponse
|
||||
// @Failure 401 {object} dto.ErrorResponse
|
||||
// @Failure 405 {object} dto.ErrorResponse
|
||||
// @Router /api/v1/production/capacity [get]
|
||||
func (h *coreHandlers) productionCapacity(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
writeMethodNotAllowed(w, http.MethodGet)
|
||||
return
|
||||
}
|
||||
summary, err := h.core.GetProductionCapacityForSession(bearerToken(r))
|
||||
if err != nil {
|
||||
writeServiceError(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, dto.ProductionCapacityFromDomain(summary))
|
||||
}
|
||||
|
||||
// productionCapacityAdmission godoc
|
||||
// @Summary Check production capacity admission
|
||||
// @Description Evaluates endpoint heartbeat, capability, durable jobs, and bounded backlog pressure without dispatching work.
|
||||
// @Tags production-operations
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body dto.CapacityAdmissionRequest true "Capacity admission request"
|
||||
// @Success 200 {object} dto.CapacityAdmissionDecisionResponse
|
||||
// @Failure 400 {object} dto.ErrorResponse
|
||||
// @Failure 401 {object} dto.ErrorResponse
|
||||
// @Failure 403 {object} dto.ErrorResponse
|
||||
// @Failure 405 {object} dto.ErrorResponse
|
||||
// @Router /api/v1/production/capacity/admission [post]
|
||||
func (h *coreHandlers) productionCapacityAdmission(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
writeMethodNotAllowed(w, http.MethodPost)
|
||||
return
|
||||
}
|
||||
request, err := decodeJSON[dto.CapacityAdmissionRequest](r)
|
||||
if err != nil {
|
||||
writeDecodeError(w, err)
|
||||
return
|
||||
}
|
||||
decision, err := h.core.CheckCapacityAdmissionForSession(bearerToken(r), request.ToDomain())
|
||||
if err != nil {
|
||||
writeServiceError(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, dto.CapacityDecisionFromDomain(decision))
|
||||
}
|
||||
|
||||
// alerts godoc
|
||||
// @Summary List durable production alerts
|
||||
// @Description Lists alerts visible to the current operator with optional safe state/source/severity filters.
|
||||
// @Tags production-operations
|
||||
// @Produce json
|
||||
// @Success 200 {object} dto.AlertListResponse
|
||||
// @Failure 401 {object} dto.ErrorResponse
|
||||
// @Failure 405 {object} dto.ErrorResponse
|
||||
// @Router /api/v1/alerts [get]
|
||||
func (h *coreHandlers) alerts(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
writeMethodNotAllowed(w, http.MethodGet)
|
||||
return
|
||||
}
|
||||
alerts, err := h.core.ListAlertsForSession(bearerToken(r), domain.AlertFilter{State: domain.AlertState(r.URL.Query().Get("state")), SourceKind: r.URL.Query().Get("sourceKind"), SourceID: r.URL.Query().Get("sourceId"), Severity: domain.AlertSeverity(r.URL.Query().Get("severity"))})
|
||||
if err != nil {
|
||||
writeServiceError(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, dto.AlertListFromDomain(alerts))
|
||||
}
|
||||
|
||||
// alertAcknowledge godoc
|
||||
// @Summary Acknowledge a durable alert
|
||||
// @Description Persists acknowledgement actor, timestamp, and linked audit evidence for one alert.
|
||||
// @Tags production-operations
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "Alert ID"
|
||||
// @Param body body dto.AlertAcknowledgeRequest true "Acknowledgement request"
|
||||
// @Success 200 {object} dto.AlertResponse
|
||||
// @Failure 400 {object} dto.ErrorResponse
|
||||
// @Failure 401 {object} dto.ErrorResponse
|
||||
// @Failure 403 {object} dto.ErrorResponse
|
||||
// @Failure 405 {object} dto.ErrorResponse
|
||||
// @Router /api/v1/alerts/{id}/acknowledge [post]
|
||||
func (h *coreHandlers) alertAcknowledge(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
writeMethodNotAllowed(w, http.MethodPost)
|
||||
return
|
||||
}
|
||||
request, err := decodeJSON[dto.AlertAcknowledgeRequest](r)
|
||||
if err != nil {
|
||||
writeDecodeError(w, err)
|
||||
return
|
||||
}
|
||||
alert, err := h.core.AcknowledgeAlertForSession(bearerToken(r), domain.AlertAcknowledgeRequest{AlertID: r.PathValue("id"), Note: request.Note})
|
||||
if err != nil {
|
||||
writeServiceError(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, dto.AlertFromDomain(alert))
|
||||
}
|
||||
|
||||
// alertResolve godoc
|
||||
// @Summary Resolve a durable alert
|
||||
// @Description Resolves one alert with a safe operator note and linked audit evidence.
|
||||
// @Tags production-operations
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "Alert ID"
|
||||
// @Param body body dto.AlertResolveRequest true "Resolution request"
|
||||
// @Success 200 {object} dto.AlertResponse
|
||||
// @Failure 400 {object} dto.ErrorResponse
|
||||
// @Failure 401 {object} dto.ErrorResponse
|
||||
// @Failure 403 {object} dto.ErrorResponse
|
||||
// @Failure 405 {object} dto.ErrorResponse
|
||||
// @Router /api/v1/alerts/{id}/resolve [post]
|
||||
func (h *coreHandlers) alertResolve(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
writeMethodNotAllowed(w, http.MethodPost)
|
||||
return
|
||||
}
|
||||
request, err := decodeJSON[dto.AlertResolveRequest](r)
|
||||
if err != nil {
|
||||
writeDecodeError(w, err)
|
||||
return
|
||||
}
|
||||
alert, err := h.core.ResolveAlertForSession(bearerToken(r), domain.AlertResolveRequest{AlertID: r.PathValue("id"), Note: request.Note})
|
||||
if err != nil {
|
||||
writeServiceError(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, dto.AlertFromDomain(alert))
|
||||
}
|
||||
|
||||
// alertRetry godoc
|
||||
// @Summary Retry one durable alert source
|
||||
// @Description Retries only the bounded source represented by an alert and preserves idempotency.
|
||||
// @Tags production-operations
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "Alert ID"
|
||||
// @Param body body dto.AlertRetryRequest true "Scoped retry request"
|
||||
// @Success 202 {object} dto.AlertRetryResponse
|
||||
// @Failure 400 {object} dto.ErrorResponse
|
||||
// @Failure 401 {object} dto.ErrorResponse
|
||||
// @Failure 403 {object} dto.ErrorResponse
|
||||
// @Failure 405 {object} dto.ErrorResponse
|
||||
// @Router /api/v1/alerts/{id}/retry [post]
|
||||
func (h *coreHandlers) alertRetry(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
writeMethodNotAllowed(w, http.MethodPost)
|
||||
return
|
||||
}
|
||||
request, err := decodeJSON[dto.AlertRetryRequest](r)
|
||||
if err != nil {
|
||||
writeDecodeError(w, err)
|
||||
return
|
||||
}
|
||||
result, err := h.core.RetryAlertForSession(bearerToken(r), domain.AlertRetryRequest{AlertID: r.PathValue("id"), IdempotencyKey: request.IdempotencyKey})
|
||||
if err != nil {
|
||||
writeServiceError(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusAccepted, dto.AlertRetryFromDomain(result))
|
||||
}
|
||||
|
||||
// pluginLifecycles godoc
|
||||
// @Summary List server-bound plugin lifecycle state
|
||||
// @Description Lists durable plugin installation, desired/current state, compatibility, dependency, job, alert, and audit metadata.
|
||||
// @Tags production-operations
|
||||
// @Produce json
|
||||
// @Success 200 {object} dto.PluginLifecycleListResponse
|
||||
// @Failure 401 {object} dto.ErrorResponse
|
||||
// @Failure 405 {object} dto.ErrorResponse
|
||||
// @Router /api/v1/plugin-lifecycles [get]
|
||||
func (h *coreHandlers) pluginLifecycles(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
writeMethodNotAllowed(w, http.MethodGet)
|
||||
return
|
||||
}
|
||||
items, err := h.core.ListPluginLifecyclesForSession(bearerToken(r), domain.PluginLifecycleFilter{PluginID: r.URL.Query().Get("pluginId"), ServerInstanceID: r.URL.Query().Get("serverInstanceId"), CurrentState: domain.PluginLifecycleState(r.URL.Query().Get("currentState"))})
|
||||
if err != nil {
|
||||
writeServiceError(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, dto.PluginLifecycleListFromDomain(items))
|
||||
}
|
||||
|
||||
// pluginLifecycleAction godoc
|
||||
// @Summary Dispatch a platform-mediated plugin lifecycle action
|
||||
// @Description Runs compatibility and capacity gates before creating one durable bounded Run job.
|
||||
// @Tags production-operations
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param pluginId path string true "Plugin ID"
|
||||
// @Param body body dto.PluginLifecycleActionRequest true "Plugin lifecycle action"
|
||||
// @Success 202 {object} dto.PluginLifecycleActionResponse
|
||||
// @Failure 400 {object} dto.ErrorResponse
|
||||
// @Failure 401 {object} dto.ErrorResponse
|
||||
// @Failure 403 {object} dto.ErrorResponse
|
||||
// @Failure 405 {object} dto.ErrorResponse
|
||||
// @Router /api/v1/plugin-lifecycles/{pluginId}/actions [post]
|
||||
func (h *coreHandlers) pluginLifecycleAction(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
writeMethodNotAllowed(w, http.MethodPost)
|
||||
return
|
||||
}
|
||||
request, err := decodeJSON[dto.PluginLifecycleActionRequest](r)
|
||||
if err != nil {
|
||||
writeDecodeError(w, err)
|
||||
return
|
||||
}
|
||||
result, err := h.core.RunPluginLifecycleForSession(bearerToken(r), request.ToDomain(r.PathValue("pluginId")))
|
||||
if err != nil {
|
||||
writeServiceError(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusAccepted, dto.PluginLifecycleResultFromDomain(result))
|
||||
}
|
||||
|
||||
// aiConfigDiffs godoc
|
||||
// @Summary List reviewable AI config diffs
|
||||
// @Description Lists persisted AI recommendations visible to the current operator without provider credentials or transport configuration.
|
||||
// @Tags production-operations
|
||||
// @Produce json
|
||||
// @Success 200 {object} dto.AIConfigDiffListResponse
|
||||
// @Failure 401 {object} dto.ErrorResponse
|
||||
// @Failure 405 {object} dto.ErrorResponse
|
||||
// @Router /api/v1/ai/config-diffs [get]
|
||||
func (h *coreHandlers) aiConfigDiffs(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
writeMethodNotAllowed(w, http.MethodGet)
|
||||
return
|
||||
}
|
||||
items, err := h.core.ListAIConfigDiffsForSession(bearerToken(r), domain.AIConfigDiffFilter{ServerInstanceID: r.URL.Query().Get("serverInstanceId"), PluginID: r.URL.Query().Get("pluginId"), State: domain.AIConfigDiffState(r.URL.Query().Get("state"))})
|
||||
if err != nil {
|
||||
writeServiceError(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, dto.AIConfigDiffListFromDomain(items))
|
||||
}
|
||||
|
||||
// aiConfigDiffApprove godoc
|
||||
// @Summary Approve one reviewable AI config diff
|
||||
// @Description Revalidates actor/server/config revision fences before dispatching one bounded config write job.
|
||||
// @Tags production-operations
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "AI config diff ID"
|
||||
// @Param body body dto.AIConfigDiffApprovalRequest true "AI config diff approval"
|
||||
// @Success 202 {object} dto.AIConfigDiffApprovalResponse
|
||||
// @Failure 400 {object} dto.ErrorResponse
|
||||
// @Failure 401 {object} dto.ErrorResponse
|
||||
// @Failure 403 {object} dto.ErrorResponse
|
||||
// @Failure 405 {object} dto.ErrorResponse
|
||||
// @Router /api/v1/ai/config-diffs/{id}/approve [post]
|
||||
func (h *coreHandlers) aiConfigDiffApprove(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
writeMethodNotAllowed(w, http.MethodPost)
|
||||
return
|
||||
}
|
||||
request, err := decodeJSON[dto.AIConfigDiffApprovalRequest](r)
|
||||
if err != nil {
|
||||
writeDecodeError(w, err)
|
||||
return
|
||||
}
|
||||
result, err := h.core.ApproveAIConfigDiffForSession(bearerToken(r), request.ToDomain(r.PathValue("id")))
|
||||
if err != nil {
|
||||
writeServiceError(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusAccepted, dto.AIConfigDiffApprovalFromDomain(result))
|
||||
}
|
||||
|
||||
// authRegister godoc
|
||||
@@ -554,7 +853,7 @@ func (h *coreHandlers) aiProviders(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// aiProviderDetail godoc
|
||||
// @Summary Get AI provider
|
||||
// @Description Returns one platform-managed AI provider by ID without raw key material.
|
||||
// @Description Returns one platform-managed AI provider by ID without raw key or base URL material.
|
||||
// @Tags ai-providers
|
||||
// @Produce json
|
||||
// @Param id path string true "AI provider ID"
|
||||
@@ -589,6 +888,9 @@ func (h *coreHandlers) aiProviderDetail(w http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
}
|
||||
update := request.ToDomain(r.PathValue("id"), existing.Status)
|
||||
if strings.TrimSpace(update.BaseURL) == "" {
|
||||
update.BaseURL = existing.BaseURL
|
||||
}
|
||||
if strings.TrimSpace(update.APIKeyRef) == "" {
|
||||
update.APIKeyRef = existing.APIKeyRef
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user