package api import ( "encoding/json" "fmt" "net/http" "strconv" "time" "proxmox-router/internal/tools" ) func (s *Server) handleToolsPing(w http.ResponseWriter, r *http.Request) { var req tools.PingRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()}) return } timeoutSec := req.Timeout if timeoutSec <= 0 { timeoutSec = 10 } ctx, cancel := r.Context(), func() {} if timeoutSec > 0 { ctx, cancel = r.Context(), func() {} // Allow up to 35 seconds for ping _ = time.Duration(timeoutSec) * time.Second } defer cancel() resp, err := s.toolsMgr.RunPing(ctx, req) if err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, resp) } func (s *Server) handleToolsPingStream(w http.ResponseWriter, r *http.Request) { flusher, ok := w.(http.Flusher) if !ok { http.Error(w, "Streaming unsupported", http.StatusInternalServerError) return } var req tools.PingRequest if r.Method == http.MethodPost && r.Body != nil { _ = json.NewDecoder(r.Body).Decode(&req) } if req.Target == "" { q := r.URL.Query() req.Target = q.Get("target") req.Count, _ = strconv.Atoi(q.Get("count")) req.Size, _ = strconv.Atoi(q.Get("size")) req.Timeout, _ = strconv.Atoi(q.Get("timeout")) req.Interface = q.Get("interface") req.DoNotFrag = q.Get("dont_frag") == "true" || q.Get("dont_frag") == "1" } w.Header().Set("Content-Type", "text/event-stream") w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Connection", "keep-alive") w.Header().Set("X-Accel-Buffering", "no") sendSSE := func(evt tools.PingStreamEvent) { b, err := json.Marshal(evt) if err == nil { fmt.Fprintf(w, "data: %s\n\n", b) flusher.Flush() } } err := s.toolsMgr.StreamPing(r.Context(), req, sendSSE) if err != nil { sendSSE(tools.PingStreamEvent{ Type: "error", Message: err.Error(), Raw: "Error: " + err.Error(), }) } } func (s *Server) handleToolsTraceroute(w http.ResponseWriter, r *http.Request) { var req tools.TracerouteRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()}) return } resp, err := s.toolsMgr.RunTraceroute(r.Context(), req) if err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, resp) } func (s *Server) handleToolsTracerouteStream(w http.ResponseWriter, r *http.Request) { flusher, ok := w.(http.Flusher) if !ok { http.Error(w, "Streaming unsupported", http.StatusInternalServerError) return } var req tools.TracerouteRequest if r.Method == http.MethodPost && r.Body != nil { _ = json.NewDecoder(r.Body).Decode(&req) } if req.Target == "" { q := r.URL.Query() req.Target = q.Get("target") req.MaxHops, _ = strconv.Atoi(q.Get("max_hops")) req.Protocol = q.Get("protocol") req.Interface = q.Get("interface") req.Resolve = q.Get("resolve") == "true" || q.Get("resolve") == "1" } w.Header().Set("Content-Type", "text/event-stream") w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Connection", "keep-alive") w.Header().Set("X-Accel-Buffering", "no") sendSSE := func(evt tools.TracerouteStreamEvent) { b, err := json.Marshal(evt) if err == nil { fmt.Fprintf(w, "data: %s\n\n", b) flusher.Flush() } } err := s.toolsMgr.StreamTraceroute(r.Context(), req, sendSSE) if err != nil { sendSSE(tools.TracerouteStreamEvent{ Type: "error", Message: err.Error(), Raw: "Error: " + err.Error(), }) } } func (s *Server) handleToolsDNS(w http.ResponseWriter, r *http.Request) { var req tools.DNSRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()}) return } resp, err := s.toolsMgr.RunDNSLookup(r.Context(), req) if err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, resp) } func (s *Server) handleToolsPortProbe(w http.ResponseWriter, r *http.Request) { var req tools.PortProbeRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()}) return } resp, err := s.toolsMgr.RunPortProbe(r.Context(), req) if err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, resp) } func (s *Server) handleToolsMTR(w http.ResponseWriter, r *http.Request) { var req tools.MTRRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()}) return } resp, err := s.toolsMgr.RunMTR(r.Context(), req) if err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, resp) }