package api import ( "encoding/json" "fmt" "net/http" "time" "proxmox-router/internal/bwtest" ) // handleGetBwTestServer returns status and metrics for the local BwTest server func (s *Server) handleGetBwTestServer(w http.ResponseWriter, r *http.Request) { status := s.bwtestMgr.GetServerStatus() writeJSON(w, http.StatusOK, status) } // handleUpdateBwTestServer updates the server configuration func (s *Server) handleUpdateBwTestServer(w http.ResponseWriter, r *http.Request) { var cfg bwtest.ServerConfig if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()}) return } if err := s.bwtestMgr.SetServerConfig(cfg); err != nil { writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, s.bwtestMgr.GetServerStatus()) } // handleStartBwTest initiates a bandwidth test func (s *Server) handleStartBwTest(w http.ResponseWriter, r *http.Request) { var req bwtest.SessionRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()}) return } if req.Target == "" { req.Target = "127.0.0.1" } if req.Port <= 0 { req.Port = 2000 } if err := s.bwtestMgr.StartTest(r.Context(), req); err != nil { writeJSON(w, http.StatusConflict, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, s.bwtestMgr.GetTestStatus()) } // handleStopBwTest terminates any running test func (s *Server) handleStopBwTest(w http.ResponseWriter, r *http.Request) { s.bwtestMgr.StopTest() writeJSON(w, http.StatusOK, map[string]bool{"stopped": true}) } // handleGetBwTestStatus retrieves current status, telemetry, and metrics func (s *Server) handleGetBwTestStatus(w http.ResponseWriter, r *http.Request) { status := s.bwtestMgr.GetTestStatus() writeJSON(w, http.StatusOK, status) } // handleStreamBwTest streams real-time telemetry samples over Server-Sent Events (SSE) func (s *Server) handleStreamBwTest(w http.ResponseWriter, r *http.Request) { flusher, ok := w.(http.Flusher) if !ok { http.Error(w, "Streaming unsupported", http.StatusInternalServerError) return } 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") subCh, unsubscribe := s.bwtestMgr.SubscribeClient() defer unsubscribe() ticker := time.NewTicker(500 * time.Millisecond) defer ticker.Stop() for { select { case <-r.Context().Done(): return case sample, ok := <-subCh: if !ok { return } data, err := json.Marshal(sample) if err == nil { fmt.Fprintf(w, "data: %s\n\n", data) flusher.Flush() } case <-ticker.C: // Send heartbeat/current status snapshot if no sample arrives status := s.bwtestMgr.GetTestStatus() if !status.Running { summaryData, _ := json.Marshal(map[string]interface{}{ "type": "status", "running": false, "summary": status.Summary, "error": status.Error, }) fmt.Fprintf(w, "data: %s\n\n", summaryData) flusher.Flush() return } } } } // handleGetBwTestHistory returns historical test records func (s *Server) handleGetBwTestHistory(w http.ResponseWriter, r *http.Request) { history := s.bwtestMgr.GetHistory() writeJSON(w, http.StatusOK, history) }