package server import ( "encoding/json" "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, "db.tables": proto.TaskDBTables, "db.rows": proto.TaskDBRows, "db.set": proto.TaskDBSet, "db.add": proto.TaskDBAdd, "db.del": proto.TaskDBDel, "db.sql": proto.TaskDBSQL, } // 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 } // Changes to a database go to the audit log, with what was done. if op == "db.set" || op == "db.add" || op == "db.del" || op == "db.sql" { var d struct { Path, Table, Column, SQL string } _ = json.Unmarshal(args, &d) what := d.Path + " " + d.Table if d.Column != "" { what += "." + d.Column } if d.SQL != "" { what += " " + d.SQL } if len(what) > 300 { what = what[:300] } if admin := s.currentAdmin(r); admin != nil { s.db.Audit(admin.ID, agentID, op+":"+what) } } 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: "таймаут ожидания агента"}) } }