package handlers import ( "fmt" "net/http" "strconv" "gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/grpcsrv/commander" "gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/models" "gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/repository" "gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/service" "github.com/gin-gonic/gin" ) type ScriptHandlers struct { svc *service.ScriptService tracker *commander.ConnTracker } func NewScriptHandlers(svc *service.ScriptService, tracker *commander.ConnTracker) ScriptHandlers { return ScriptHandlers{svc: svc, tracker: tracker} } type RunScriptIn struct { AgentID string `json:"agent_id" binding:"required"` InterpreterID int64 `json:"interpreter_id" binding:"required"` ScriptText string `json:"script_text" binding:"required"` Stdin *string `json:"stdin"` } type RunScriptOut struct { ID int64 `json:"id"` Command []string `json:"command"` Stdin *string `json:"stdin"` Stdout string `json:"stdout"` Stderr string `json:"stderr"` Status int32 `json:"status"` } // RunScript executes a script on a target agent. // @Summary Run a script on an agent // @Description Resolves interpreter argv[] and sends the full command to the agent // @Tags scripts // @Accept json // @Produce json // @Param body body RunScriptIn true "Script request" // @Success 201 {object} RunScriptOut // @Security Bearer // @Router /scripts/run [post] func (h *ScriptHandlers) RunScript(c *gin.Context) { err := func() error { var in RunScriptIn if err := c.Bind(&in); err != nil { return err } command, err := h.svc.ResolveCommand( c.Request.Context(), in.InterpreterID, in.ScriptText, ) if err != nil { return err } agent, ok := h.tracker.GetAgent(in.AgentID) if !ok { c.Status(http.StatusNotFound) return fmt.Errorf("agent not found") } jid, err := agent.AddJob(models.JobForInsert{ Command: command, Stdin: in.Stdin, }) if err != nil { return err } job, err := agent.WaitJob(jid) if err != nil { return err } c.JSON(http.StatusCreated, RunScriptOut{ ID: job.ID, Command: job.Command, Stdin: job.Stdin, Stdout: job.Stdout, Stderr: job.Stderr, Status: job.Status, }) return nil }() if err != nil { c.Error(err) } } // ListInterpreters returns all registered script interpreters. // @Summary List interpreters // @Description Returns all script interpreters available in the system // @Tags scripts // @Produce json // @Success 200 {array} repository.ScriptInterpreter // @Security Bearer // @Router /scripts/interpreters [get] func (h *ScriptHandlers) ListInterpreters(c *gin.Context) { interpreters, err := h.svc.List(c.Request.Context()) if err != nil { c.Error(err) return } c.JSON(http.StatusOK, interpreters) } // CreateInterpreter registers a new script interpreter. // @Summary Create interpreter // @Description Registers a new script interpreter with name, label, and argv // @Tags scripts // @Accept json // @Produce json // @Param body body repository.ScriptInterpreterCreate true "Interpreter definition" // @Success 201 {object} repository.ScriptInterpreter // @Security Bearer // @Router /scripts/interpreters [post] func (h *ScriptHandlers) CreateInterpreter(c *gin.Context) { var in repository.ScriptInterpreterCreate if err := c.BindJSON(&in); err != nil { c.Error(err) return } si, err := h.svc.Create(c.Request.Context(), in) if err != nil { c.Error(err) return } c.JSON(http.StatusCreated, si) } // GetInterpreter returns a single interpreter by ID. // @Summary Get interpreter // @Description Returns a script interpreter by ID // @Tags scripts // @Produce json // @Param id path int true "Interpreter ID" // @Success 200 {object} repository.ScriptInterpreter // @Security Bearer // @Router /scripts/interpreters/:id [get] func (h *ScriptHandlers) GetInterpreter(c *gin.Context) { id, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { c.Error(err) return } si, err := h.svc.GetByID(c.Request.Context(), id) if err != nil { c.Error(err) return } c.JSON(http.StatusOK, si) } // UpdateInterpreter updates an interpreter. // @Summary Update interpreter // @Description Updates fields of a script interpreter // @Tags scripts // @Accept json // @Produce json // @Param id path int true "Interpreter ID" // @Param body body repository.ScriptInterpreterUpdate true "Interpreter fields" // @Success 200 {object} repository.ScriptInterpreter // @Security Bearer // @Router /scripts/interpreters/:id [put] func (h *ScriptHandlers) UpdateInterpreter(c *gin.Context) { id, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { c.Error(err) return } var in repository.ScriptInterpreterUpdate if err := c.BindJSON(&in); err != nil { c.Error(err) return } si, err := h.svc.Update(c.Request.Context(), id, in) if err != nil { c.Error(err) return } c.JSON(http.StatusOK, si) } // DeleteInterpreter removes an interpreter. // @Summary Delete interpreter // @Description Removes a script interpreter by ID // @Tags scripts // @Param id path int true "Interpreter ID" // @Success 204 // @Security Bearer // @Router /scripts/interpreters/:id [delete] func (h *ScriptHandlers) DeleteInterpreter(c *gin.Context) { id, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { c.Error(err) return } if err := h.svc.Delete(c.Request.Context(), id); err != nil { c.Error(err) return } c.Status(http.StatusNoContent) }