tools_handlers.go 5.2 KB

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