package server import ( "io" "net/http" "time" "github.com/x-grk/longpolling-remote-access/internal/proto" ) // fsOps maps the URL op segment to a proto task type. var fsOps = map[string]string{ "list": proto.TaskFSList, "read": proto.TaskFSRead, "write": proto.TaskFSWrite, "mkdir": proto.TaskFSMkdir, "delete": proto.TaskFSDelete, "deltree": proto.TaskFSDelTree, "unzip": proto.TaskFSUnzip, "zip": proto.TaskFSZip, "move": proto.TaskFSMove, "stat": proto.TaskFSStat, "chmod": proto.TaskFSChmod, "copy": proto.TaskFSCopy, } // fsTaskTimeout bounds how long we wait for an agent to answer a file op. const fsTaskTimeout = 60 * time.Second func (s *Server) handleFilesPage(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") a, err := s.db.GetAgent(id) if err != nil || a == nil { http.NotFound(w, r) return } s.render(w, "files.html", map[string]any{"Agent": a, "EditLimit": proto.FSReadCap}) } // POST /api/panel/agents/{id}/fs/{op} - run a file-manager operation on the // agent and return its result. The request body is the op's JSON args and is // forwarded verbatim to the agent. func (s *Server) handleFSOp(w http.ResponseWriter, r *http.Request) { agentID := r.PathValue("id") op := r.PathValue("op") taskType, ok := fsOps[op] if !ok { http.Error(w, "unknown op", http.StatusBadRequest) return } a, err := s.db.GetAgent(agentID) if err != nil || a == nil { http.NotFound(w, r) return } if !s.online(a) { writeJSON(w, proto.TaskResult{Error: "машина офлайн"}) return } args, err := io.ReadAll(http.MaxBytesReader(w, r.Body, 64<<20)) if err != nil { http.Error(w, "bad request", http.StatusBadRequest) return } taskID, resultCh := s.hub.CreateTask(agentID, taskType, args) defer s.hub.DiscardTask(taskID) select { case res := <-resultCh: writeJSON(w, res) case <-time.After(fsTaskTimeout): writeJSON(w, proto.TaskResult{Error: "таймаут ожидания агента"}) } }