feat: 完整游戏运维功能

This commit is contained in:
npc0-hue
2026-07-18 09:04:01 +08:00
parent f3b14b7945
commit 48b8ad8d6c
187 changed files with 16607 additions and 1140 deletions
@@ -0,0 +1,352 @@
package api
import (
"net/http"
"browser.local/platform/dto"
)
// serverClientManagerLifecycles godoc
// @Summary List Client Manager lifecycle installations
// @Description Returns safe durable lifecycle, health, real job progress, and action availability for the authorized server without component secrets or machine details.
// @Tags client-managers
// @Produce json
// @Param id path string true "Server instance ID"
// @Success 200 {object} dto.ClientManagerInstallationListResponse
// @Failure 401 {object} dto.ErrorResponse
// @Failure 403 {object} dto.ErrorResponse
// @Router /api/v1/server-instances/{id}/client-managers [get]
func (h *coreHandlers) serverClientManagerLifecycles(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
writeMethodNotAllowed(w, http.MethodGet)
return
}
views, err := h.core.ListClientManagerLifecyclesForSession(bearerToken(r), r.PathValue("id"))
if err != nil {
writeServiceError(w, err)
return
}
writeJSON(w, http.StatusOK, dto.ClientManagerLifecycleViewsFromDomain(views))
}
// serverClientManagerLifecycleDetail godoc
// @Summary Get one Client Manager lifecycle installation
// @Tags client-managers
// @Produce json
// @Param id path string true "Server instance ID"
// @Param profileKey path string true "Client Manager profile key"
// @Success 200 {object} dto.ClientManagerInstallationResponse
// @Failure 401 {object} dto.ErrorResponse
// @Failure 403 {object} dto.ErrorResponse
// @Failure 404 {object} dto.ErrorResponse
// @Router /api/v1/server-instances/{id}/client-managers/{profileKey} [get]
func (h *coreHandlers) serverClientManagerLifecycleDetail(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
writeMethodNotAllowed(w, http.MethodGet)
return
}
view, err := h.core.GetClientManagerLifecycleForSession(bearerToken(r), r.PathValue("id"), r.PathValue("profileKey"))
if err != nil {
writeServiceError(w, err)
return
}
writeJSON(w, http.StatusOK, dto.ClientManagerLifecycleViewFromDomain(view))
}
// serverClientManagerDeploy godoc
// @Summary Deploy an available Client Manager distribution
// @Description Queues a typed Run deployment after server, endpoint, artifact, target, revision, and key-generation authorization.
// @Tags client-managers
// @Accept json
// @Produce json
// @Param id path string true "Server instance ID"
// @Param body body dto.ClientManagerDeployRequest true "Deployment request"
// @Success 202 {object} dto.ClientManagerInstallationResponse
// @Failure 400 {object} dto.ErrorResponse
// @Failure 401 {object} dto.ErrorResponse
// @Failure 403 {object} dto.ErrorResponse
// @Router /api/v1/server-instances/{id}/client-managers/deploy [post]
func (h *coreHandlers) serverClientManagerDeploy(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
writeMethodNotAllowed(w, http.MethodPost)
return
}
request, err := decodeJSON[dto.ClientManagerDeployRequest](r)
if err != nil {
writeDecodeError(w, err)
return
}
view, err := h.core.DeployClientManagerForSession(bearerToken(r), request.ToDomain(r.PathValue("id")))
if err != nil {
writeServiceError(w, err)
return
}
writeJSON(w, http.StatusAccepted, dto.ClientManagerLifecycleViewFromDomain(view))
}
// serverClientManagerControl godoc
// @Summary Control a deployed Client Manager
// @Description Queues a declared typed start, stop, restart, status, or rollback operation.
// @Tags client-managers
// @Accept json
// @Produce json
// @Param id path string true "Server instance ID"
// @Param body body dto.ClientManagerControlRequest true "Control request"
// @Success 202 {object} dto.ClientManagerInstallationResponse
// @Failure 400 {object} dto.ErrorResponse
// @Failure 401 {object} dto.ErrorResponse
// @Failure 403 {object} dto.ErrorResponse
// @Router /api/v1/server-instances/{id}/client-managers/control [post]
func (h *coreHandlers) serverClientManagerControl(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
writeMethodNotAllowed(w, http.MethodPost)
return
}
request, err := decodeJSON[dto.ClientManagerControlRequest](r)
if err != nil {
writeDecodeError(w, err)
return
}
view, err := h.core.ControlClientManagerForSession(bearerToken(r), request.ToDomain(r.PathValue("id")))
if err != nil {
writeServiceError(w, err)
return
}
writeJSON(w, http.StatusAccepted, dto.ClientManagerLifecycleViewFromDomain(view))
}
// serverClientManagerUpdateLifecycle godoc
// @Summary Update a Client Manager through staged activation
// @Tags client-managers
// @Accept json
// @Produce json
// @Param id path string true "Server instance ID"
// @Param body body dto.ClientManagerUpdateRequest true "Approved staged update request"
// @Success 202 {object} dto.ClientManagerInstallationResponse
// @Failure 400 {object} dto.ErrorResponse
// @Failure 401 {object} dto.ErrorResponse
// @Failure 403 {object} dto.ErrorResponse
// @Router /api/v1/server-instances/{id}/client-managers/update [post]
func (h *coreHandlers) serverClientManagerUpdateLifecycle(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
writeMethodNotAllowed(w, http.MethodPost)
return
}
request, err := decodeJSON[dto.ClientManagerUpdateRequest](r)
if err != nil {
writeDecodeError(w, err)
return
}
view, err := h.core.UpdateClientManagerForSession(bearerToken(r), request.ToDomain(r.PathValue("id")))
if err != nil {
writeServiceError(w, err)
return
}
writeJSON(w, http.StatusAccepted, dto.ClientManagerLifecycleViewFromDomain(view))
}
// serverClientManagerRetry godoc
// @Summary Retry a failed Client Manager lifecycle intent
// @Tags client-managers
// @Accept json
// @Produce json
// @Param id path string true "Server instance ID"
// @Param body body dto.ClientManagerRetryRequest true "Retry request"
// @Success 202 {object} dto.ClientManagerInstallationResponse
// @Failure 400 {object} dto.ErrorResponse
// @Failure 401 {object} dto.ErrorResponse
// @Failure 403 {object} dto.ErrorResponse
// @Router /api/v1/server-instances/{id}/client-managers/retry [post]
func (h *coreHandlers) serverClientManagerRetry(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
writeMethodNotAllowed(w, http.MethodPost)
return
}
request, err := decodeJSON[dto.ClientManagerRetryRequest](r)
if err != nil {
writeDecodeError(w, err)
return
}
view, err := h.core.RetryClientManagerLifecycleForSession(bearerToken(r), request.ToDomain(r.PathValue("id")))
if err != nil {
writeServiceError(w, err)
return
}
writeJSON(w, http.StatusAccepted, dto.ClientManagerLifecycleViewFromDomain(view))
}
// serverClientManagerRevokeSession godoc
// @Summary Revoke the active Client Manager component session
// @Tags client-managers
// @Accept json
// @Produce json
// @Param id path string true "Server instance ID"
// @Param body body dto.ClientManagerRevokeSessionRequest true "Session revoke request"
// @Success 200 {object} dto.ClientManagerInstallationResponse
// @Failure 401 {object} dto.ErrorResponse
// @Failure 403 {object} dto.ErrorResponse
// @Router /api/v1/server-instances/{id}/client-managers/revoke-session [post]
func (h *coreHandlers) serverClientManagerRevokeSession(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
writeMethodNotAllowed(w, http.MethodPost)
return
}
request, err := decodeJSON[dto.ClientManagerRevokeSessionRequest](r)
if err != nil {
writeDecodeError(w, err)
return
}
view, err := h.core.RevokeClientManagerSessionForSession(bearerToken(r), request.ToDomain(r.PathValue("id")))
if err != nil {
writeServiceError(w, err)
return
}
writeJSON(w, http.StatusOK, dto.ClientManagerLifecycleViewFromDomain(view))
}
// serverClientManagerUninstall godoc
// @Summary Safely uninstall a Client Manager
// @Description Stops the supervised process and removes only the controlled installation workspace while retaining audit and distribution history.
// @Tags client-managers
// @Accept json
// @Produce json
// @Param id path string true "Server instance ID"
// @Param body body dto.ClientManagerUninstallRequest true "Confirmed uninstall request"
// @Success 202 {object} dto.ClientManagerInstallationResponse
// @Failure 400 {object} dto.ErrorResponse
// @Failure 401 {object} dto.ErrorResponse
// @Failure 403 {object} dto.ErrorResponse
// @Router /api/v1/server-instances/{id}/client-managers/uninstall [post]
func (h *coreHandlers) serverClientManagerUninstall(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
writeMethodNotAllowed(w, http.MethodPost)
return
}
request, err := decodeJSON[dto.ClientManagerUninstallRequest](r)
if err != nil {
writeDecodeError(w, err)
return
}
view, err := h.core.UninstallClientManagerForSession(bearerToken(r), request.ToDomain(r.PathValue("id")))
if err != nil {
writeServiceError(w, err)
return
}
writeJSON(w, http.StatusAccepted, dto.ClientManagerLifecycleViewFromDomain(view))
}
// runClientManagerLifecycleInput godoc
// @Summary Get fenced Client Manager lifecycle input
// @Description Returns a safe typed lifecycle contract only to the authenticated Run endpoint holding the active job lease.
// @Tags run-job-channel
// @Accept json
// @Produce json
// @Param body body dto.ClientManagerLifecycleInputRequest true "Fenced lifecycle input request"
// @Success 200 {object} dto.ClientManagerLifecycleInputResponse
// @Failure 400 {object} dto.ErrorResponse
// @Failure 401 {object} dto.ErrorResponse
// @Router /api/v1/run/jobs/client-manager-input [post]
func (h *coreHandlers) runClientManagerLifecycleInput(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
writeMethodNotAllowed(w, http.MethodPost)
return
}
request, err := decodeJSON[dto.ClientManagerLifecycleInputRequest](r)
if err != nil {
writeDecodeError(w, err)
return
}
input, err := h.core.GetClientManagerLifecycleInput(request.ToDomain())
if err != nil {
writeServiceError(w, err)
return
}
writeJSON(w, http.StatusOK, dto.ClientManagerLifecycleInputFromDomain(input))
}
// runClientManagerLifecycleChunk godoc
// @Summary Read one fenced Client Manager artifact chunk
// @Description Streams a checksummed artifact chunk only to the active typed lifecycle job lease.
// @Tags run-job-channel
// @Accept json
// @Produce json
// @Param body body dto.RunUpdateChunkRequest true "Fenced chunk request"
// @Success 200 {object} dto.RunUpdateChunkResponse
// @Failure 400 {object} dto.ErrorResponse
// @Failure 401 {object} dto.ErrorResponse
// @Router /api/v1/run/jobs/client-manager-chunk [post]
func (h *coreHandlers) runClientManagerLifecycleChunk(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
writeMethodNotAllowed(w, http.MethodPost)
return
}
request, err := decodeJSON[dto.RunUpdateChunkRequest](r)
if err != nil {
writeDecodeError(w, err)
return
}
chunk, err := h.core.ReadClientManagerLifecycleChunk(request.ToDomain())
if err != nil {
writeServiceError(w, err)
return
}
writeJSON(w, http.StatusOK, dto.RunUpdateChunkFromDomain(chunk))
}
// clientManagerRegister godoc
// @Summary Register an installed Client Manager component
// @Description Verifies a current component-key HMAC, nonce, deployment fence, target, revision, and capabilities before issuing an isolated expiring component session.
// @Tags client-manager-component
// @Accept json
// @Produce json
// @Param body body dto.ClientManagerRegisterRequest true "Signed component registration"
// @Success 200 {object} dto.ClientManagerRegisterResponse
// @Failure 400 {object} dto.ErrorResponse
// @Failure 401 {object} dto.ErrorResponse
// @Router /api/v1/client-managers/register [post]
func (h *coreHandlers) clientManagerRegister(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
writeMethodNotAllowed(w, http.MethodPost)
return
}
request, err := decodeJSON[dto.ClientManagerRegisterRequest](r)
if err != nil {
writeDecodeError(w, err)
return
}
result, err := h.core.RegisterClientManager(request.ToDomain())
if err != nil {
writeServiceError(w, err)
return
}
writeJSON(w, http.StatusOK, dto.ClientManagerRegisterFromDomain(result))
}
// clientManagerHeartbeat godoc
// @Summary Accept a Client Manager component heartbeat
// @Description Accepts monotonic health reports using the isolated component session; Run control credentials are not valid here.
// @Tags client-manager-component
// @Accept json
// @Produce json
// @Param body body dto.ClientManagerHeartbeatRequest true "Component heartbeat"
// @Success 200 {object} dto.ClientManagerHeartbeatResponse
// @Failure 400 {object} dto.ErrorResponse
// @Failure 401 {object} dto.ErrorResponse
// @Router /api/v1/client-managers/heartbeat [post]
func (h *coreHandlers) clientManagerHeartbeat(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
writeMethodNotAllowed(w, http.MethodPost)
return
}
request, err := decodeJSON[dto.ClientManagerHeartbeatRequest](r)
if err != nil {
writeDecodeError(w, err)
return
}
result, err := h.core.AcceptClientManagerHeartbeat(request.ToDomain())
if err != nil {
writeServiceError(w, err)
return
}
writeJSON(w, http.StatusOK, dto.ClientManagerHeartbeatFromDomain(result))
}