219 lines
6.8 KiB
Go
219 lines
6.8 KiB
Go
//go:build ignore
|
|
// +build ignore
|
|
|
|
package admin
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"stream.api/pkg/response"
|
|
)
|
|
|
|
type createJobRequest struct {
|
|
Command string `json:"command"`
|
|
Image string `json:"image"`
|
|
Env map[string]string `json:"env"`
|
|
Priority int `json:"priority"`
|
|
UserID string `json:"user_id"`
|
|
Name string `json:"name"`
|
|
TimeLimit int64 `json:"time_limit"`
|
|
}
|
|
|
|
// @Summary List render jobs
|
|
// @Description Returns paginated render jobs for admin management
|
|
// @Tags admin-render
|
|
// @Security BearerAuth
|
|
// @Produce json
|
|
// @Param offset query int false "Offset"
|
|
// @Param limit query int false "Limit"
|
|
// @Param agent_id query string false "Agent ID"
|
|
// @Success 200 {object} response.Response
|
|
// @Failure 500 {object} response.Response
|
|
// @Router /admin/jobs [get]
|
|
func (h *Handler) ListJobs(c *gin.Context) {
|
|
offset := parseInt(c.Query("offset"), 0)
|
|
limit := parseInt(c.Query("limit"), 20)
|
|
if agentID := c.Query("agent_id"); agentID != "" {
|
|
items, err := h.runtime.JobService().ListJobsByAgent(c.Request.Context(), agentID, offset, limit)
|
|
if err != nil {
|
|
response.Error(c, http.StatusInternalServerError, "Failed to list jobs")
|
|
return
|
|
}
|
|
response.Success(c, items)
|
|
return
|
|
}
|
|
items, err := h.runtime.JobService().ListJobs(c.Request.Context(), offset, limit)
|
|
if err != nil {
|
|
response.Error(c, http.StatusInternalServerError, "Failed to list jobs")
|
|
return
|
|
}
|
|
response.Success(c, items)
|
|
}
|
|
|
|
// @Summary Get render job detail
|
|
// @Description Returns a render job by ID
|
|
// @Tags admin-render
|
|
// @Security BearerAuth
|
|
// @Produce json
|
|
// @Param id path string true "Job ID"
|
|
// @Success 200 {object} response.Response
|
|
// @Failure 404 {object} response.Response
|
|
// @Router /admin/jobs/{id} [get]
|
|
func (h *Handler) GetJob(c *gin.Context) {
|
|
job, err := h.runtime.JobService().GetJob(c.Request.Context(), c.Param("id"))
|
|
if err != nil {
|
|
response.Error(c, http.StatusNotFound, "Job not found")
|
|
return
|
|
}
|
|
response.Success(c, gin.H{"job": job})
|
|
}
|
|
|
|
// @Summary Get render job logs
|
|
// @Description Returns plain text logs for a render job
|
|
// @Tags admin-render
|
|
// @Security BearerAuth
|
|
// @Produce plain
|
|
// @Param id path string true "Job ID"
|
|
// @Success 200 {string} string
|
|
// @Failure 404 {object} response.Response
|
|
// @Router /admin/jobs/{id}/logs [get]
|
|
func (h *Handler) GetJobLogs(c *gin.Context) {
|
|
job, err := h.runtime.JobService().GetJob(c.Request.Context(), c.Param("id"))
|
|
if err != nil {
|
|
response.Error(c, http.StatusNotFound, "Job not found")
|
|
return
|
|
}
|
|
c.String(http.StatusOK, job.Logs)
|
|
}
|
|
|
|
// @Summary Create render job
|
|
// @Description Queues a new render job for agents
|
|
// @Tags admin-render
|
|
// @Security BearerAuth
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param payload body createJobRequest true "Job payload"
|
|
// @Success 201 {object} response.Response
|
|
// @Failure 400 {object} response.Response
|
|
// @Failure 500 {object} response.Response
|
|
// @Router /admin/jobs [post]
|
|
func (h *Handler) CreateJob(c *gin.Context) {
|
|
var req createJobRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, http.StatusBadRequest, err.Error())
|
|
return
|
|
}
|
|
if req.Command == "" {
|
|
response.Error(c, http.StatusBadRequest, "Command is required")
|
|
return
|
|
}
|
|
if req.Image == "" {
|
|
req.Image = "alpine"
|
|
}
|
|
if req.Name == "" {
|
|
req.Name = req.Command
|
|
}
|
|
payload, _ := json.Marshal(map[string]interface{}{"image": req.Image, "commands": []string{req.Command}, "environment": req.Env})
|
|
job, err := h.runtime.JobService().CreateJob(c.Request.Context(), req.UserID, req.Name, payload, req.Priority, req.TimeLimit)
|
|
if err != nil {
|
|
response.Error(c, http.StatusInternalServerError, "Failed to create job")
|
|
return
|
|
}
|
|
response.Created(c, gin.H{"job": job})
|
|
}
|
|
|
|
// @Summary Cancel render job
|
|
// @Description Cancels a pending or running render job
|
|
// @Tags admin-render
|
|
// @Security BearerAuth
|
|
// @Produce json
|
|
// @Param id path string true "Job ID"
|
|
// @Success 200 {object} response.Response
|
|
// @Failure 400 {object} response.Response
|
|
// @Router /admin/jobs/{id}/cancel [post]
|
|
func (h *Handler) CancelJob(c *gin.Context) {
|
|
if err := h.runtime.JobService().CancelJob(c.Request.Context(), c.Param("id")); err != nil {
|
|
response.Error(c, http.StatusBadRequest, err.Error())
|
|
return
|
|
}
|
|
response.Success(c, gin.H{"status": "cancelled", "job_id": c.Param("id")})
|
|
}
|
|
|
|
// @Summary Retry render job
|
|
// @Description Retries a failed or cancelled render job
|
|
// @Tags admin-render
|
|
// @Security BearerAuth
|
|
// @Produce json
|
|
// @Param id path string true "Job ID"
|
|
// @Success 200 {object} response.Response
|
|
// @Failure 400 {object} response.Response
|
|
// @Router /admin/jobs/{id}/retry [post]
|
|
func (h *Handler) RetryJob(c *gin.Context) {
|
|
job, err := h.runtime.JobService().RetryJob(c.Request.Context(), c.Param("id"))
|
|
if err != nil {
|
|
response.Error(c, http.StatusBadRequest, err.Error())
|
|
return
|
|
}
|
|
response.Success(c, gin.H{"job": job})
|
|
}
|
|
|
|
// @Summary List connected render agents
|
|
// @Description Returns currently connected render agents and current runtime stats
|
|
// @Tags admin-render
|
|
// @Security BearerAuth
|
|
// @Produce json
|
|
// @Success 200 {object} response.Response
|
|
// @Failure 500 {object} response.Response
|
|
// @Router /admin/agents [get]
|
|
func (h *Handler) ListAgents(c *gin.Context) {
|
|
response.Success(c, gin.H{"agents": h.runtime.AgentRuntime().ListAgentsWithStats()})
|
|
}
|
|
|
|
// @Summary Restart connected render agent
|
|
// @Description Sends a restart command to a currently connected render agent
|
|
// @Tags admin-render
|
|
// @Security BearerAuth
|
|
// @Produce json
|
|
// @Param id path string true "Agent ID"
|
|
// @Success 200 {object} response.Response
|
|
// @Failure 503 {object} response.Response
|
|
// @Router /admin/agents/{id}/restart [post]
|
|
func (h *Handler) RestartAgent(c *gin.Context) {
|
|
if ok := h.runtime.AgentRuntime().SendCommand(c.Param("id"), "restart"); !ok {
|
|
response.Error(c, http.StatusServiceUnavailable, "Agent not active or command channel full")
|
|
return
|
|
}
|
|
response.Success(c, gin.H{"status": "restart command sent"})
|
|
}
|
|
|
|
// @Summary Update connected render agent
|
|
// @Description Sends an update command to a currently connected render agent
|
|
// @Tags admin-render
|
|
// @Security BearerAuth
|
|
// @Produce json
|
|
// @Param id path string true "Agent ID"
|
|
// @Success 200 {object} response.Response
|
|
// @Failure 503 {object} response.Response
|
|
// @Router /admin/agents/{id}/update [post]
|
|
func (h *Handler) UpdateAgent(c *gin.Context) {
|
|
if ok := h.runtime.AgentRuntime().SendCommand(c.Param("id"), "update"); !ok {
|
|
response.Error(c, http.StatusServiceUnavailable, "Agent not active or command channel full")
|
|
return
|
|
}
|
|
response.Success(c, gin.H{"status": "update command sent"})
|
|
}
|
|
|
|
func parseInt(value string, fallback int) int {
|
|
if value == "" {
|
|
return fallback
|
|
}
|
|
var result int
|
|
if _, err := fmt.Sscanf(value, "%d", &result); err != nil {
|
|
return fallback
|
|
}
|
|
return result
|
|
}
|