tools_handlers.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. package api
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "net/http"
  6. "strconv"
  7. "time"
  8. "proxmox-router/internal/tools"
  9. )
  10. func (s *Server) handleToolsPing(w http.ResponseWriter, r *http.Request) {
  11. var req tools.PingRequest
  12. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  13. writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()})
  14. return
  15. }
  16. timeoutSec := req.Timeout
  17. if timeoutSec <= 0 {
  18. timeoutSec = 10
  19. }
  20. ctx, cancel := r.Context(), func() {}
  21. if timeoutSec > 0 {
  22. ctx, cancel = r.Context(), func() {}
  23. // Allow up to 35 seconds for ping
  24. _ = time.Duration(timeoutSec) * time.Second
  25. }
  26. defer cancel()
  27. resp, err := s.toolsMgr.RunPing(ctx, req)
  28. if err != nil {
  29. writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
  30. return
  31. }
  32. writeJSON(w, http.StatusOK, resp)
  33. }
  34. func (s *Server) handleToolsPingStream(w http.ResponseWriter, r *http.Request) {
  35. flusher, ok := w.(http.Flusher)
  36. if !ok {
  37. http.Error(w, "Streaming unsupported", http.StatusInternalServerError)
  38. return
  39. }
  40. var req tools.PingRequest
  41. if r.Method == http.MethodPost && r.Body != nil {
  42. _ = json.NewDecoder(r.Body).Decode(&req)
  43. }
  44. if req.Target == "" {
  45. q := r.URL.Query()
  46. req.Target = q.Get("target")
  47. req.Count, _ = strconv.Atoi(q.Get("count"))
  48. req.Size, _ = strconv.Atoi(q.Get("size"))
  49. req.Timeout, _ = strconv.Atoi(q.Get("timeout"))
  50. req.Interface = q.Get("interface")
  51. req.DoNotFrag = q.Get("dont_frag") == "true" || q.Get("dont_frag") == "1"
  52. }
  53. w.Header().Set("Content-Type", "text/event-stream")
  54. w.Header().Set("Cache-Control", "no-cache")
  55. w.Header().Set("Connection", "keep-alive")
  56. w.Header().Set("X-Accel-Buffering", "no")
  57. sendSSE := func(evt tools.PingStreamEvent) {
  58. b, err := json.Marshal(evt)
  59. if err == nil {
  60. fmt.Fprintf(w, "data: %s\n\n", b)
  61. flusher.Flush()
  62. }
  63. }
  64. err := s.toolsMgr.StreamPing(r.Context(), req, sendSSE)
  65. if err != nil {
  66. sendSSE(tools.PingStreamEvent{
  67. Type: "error",
  68. Message: err.Error(),
  69. Raw: "Error: " + err.Error(),
  70. })
  71. }
  72. }
  73. func (s *Server) handleToolsTraceroute(w http.ResponseWriter, r *http.Request) {
  74. var req tools.TracerouteRequest
  75. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  76. writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()})
  77. return
  78. }
  79. resp, err := s.toolsMgr.RunTraceroute(r.Context(), req)
  80. if err != nil {
  81. writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
  82. return
  83. }
  84. writeJSON(w, http.StatusOK, resp)
  85. }
  86. func (s *Server) handleToolsTracerouteStream(w http.ResponseWriter, r *http.Request) {
  87. flusher, ok := w.(http.Flusher)
  88. if !ok {
  89. http.Error(w, "Streaming unsupported", http.StatusInternalServerError)
  90. return
  91. }
  92. var req tools.TracerouteRequest
  93. if r.Method == http.MethodPost && r.Body != nil {
  94. _ = json.NewDecoder(r.Body).Decode(&req)
  95. }
  96. if req.Target == "" {
  97. q := r.URL.Query()
  98. req.Target = q.Get("target")
  99. req.MaxHops, _ = strconv.Atoi(q.Get("max_hops"))
  100. req.Protocol = q.Get("protocol")
  101. req.Interface = q.Get("interface")
  102. req.Resolve = q.Get("resolve") == "true" || q.Get("resolve") == "1"
  103. }
  104. w.Header().Set("Content-Type", "text/event-stream")
  105. w.Header().Set("Cache-Control", "no-cache")
  106. w.Header().Set("Connection", "keep-alive")
  107. w.Header().Set("X-Accel-Buffering", "no")
  108. sendSSE := func(evt tools.TracerouteStreamEvent) {
  109. b, err := json.Marshal(evt)
  110. if err == nil {
  111. fmt.Fprintf(w, "data: %s\n\n", b)
  112. flusher.Flush()
  113. }
  114. }
  115. err := s.toolsMgr.StreamTraceroute(r.Context(), req, sendSSE)
  116. if err != nil {
  117. sendSSE(tools.TracerouteStreamEvent{
  118. Type: "error",
  119. Message: err.Error(),
  120. Raw: "Error: " + err.Error(),
  121. })
  122. }
  123. }
  124. func (s *Server) handleToolsDNS(w http.ResponseWriter, r *http.Request) {
  125. var req tools.DNSRequest
  126. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  127. writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()})
  128. return
  129. }
  130. resp, err := s.toolsMgr.RunDNSLookup(r.Context(), req)
  131. if err != nil {
  132. writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
  133. return
  134. }
  135. writeJSON(w, http.StatusOK, resp)
  136. }
  137. func (s *Server) handleToolsPortProbe(w http.ResponseWriter, r *http.Request) {
  138. var req tools.PortProbeRequest
  139. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  140. writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()})
  141. return
  142. }
  143. resp, err := s.toolsMgr.RunPortProbe(r.Context(), req)
  144. if err != nil {
  145. writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
  146. return
  147. }
  148. writeJSON(w, http.StatusOK, resp)
  149. }
  150. func (s *Server) handleToolsMTR(w http.ResponseWriter, r *http.Request) {
  151. var req tools.MTRRequest
  152. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  153. writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid JSON: " + err.Error()})
  154. return
  155. }
  156. resp, err := s.toolsMgr.RunMTR(r.Context(), req)
  157. if err != nil {
  158. writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
  159. return
  160. }
  161. writeJSON(w, http.StatusOK, resp)
  162. }