connections.go 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. package clashapi
  2. import (
  3. "bytes"
  4. "net/http"
  5. "strconv"
  6. "time"
  7. "github.com/sagernet/sing-box/common/json"
  8. "github.com/sagernet/sing-box/experimental/clashapi/trafficontrol"
  9. "github.com/go-chi/chi/v5"
  10. "github.com/go-chi/render"
  11. "github.com/gorilla/websocket"
  12. )
  13. func connectionRouter(trafficManager *trafficontrol.Manager) http.Handler {
  14. r := chi.NewRouter()
  15. r.Get("/", getConnections(trafficManager))
  16. r.Delete("/", closeAllConnections(trafficManager))
  17. r.Delete("/{id}", closeConnection(trafficManager))
  18. return r
  19. }
  20. func getConnections(trafficManager *trafficontrol.Manager) func(w http.ResponseWriter, r *http.Request) {
  21. return func(w http.ResponseWriter, r *http.Request) {
  22. if !websocket.IsWebSocketUpgrade(r) {
  23. snapshot := trafficManager.Snapshot()
  24. render.JSON(w, r, snapshot)
  25. return
  26. }
  27. conn, err := upgrader.Upgrade(w, r, nil)
  28. if err != nil {
  29. return
  30. }
  31. intervalStr := r.URL.Query().Get("interval")
  32. interval := 1000
  33. if intervalStr != "" {
  34. t, err := strconv.Atoi(intervalStr)
  35. if err != nil {
  36. render.Status(r, http.StatusBadRequest)
  37. render.JSON(w, r, ErrBadRequest)
  38. return
  39. }
  40. interval = t
  41. }
  42. buf := &bytes.Buffer{}
  43. sendSnapshot := func() error {
  44. buf.Reset()
  45. snapshot := trafficManager.Snapshot()
  46. if err := json.NewEncoder(buf).Encode(snapshot); err != nil {
  47. return err
  48. }
  49. return conn.WriteMessage(websocket.TextMessage, buf.Bytes())
  50. }
  51. if err = sendSnapshot(); err != nil {
  52. return
  53. }
  54. tick := time.NewTicker(time.Millisecond * time.Duration(interval))
  55. defer tick.Stop()
  56. for range tick.C {
  57. if err = sendSnapshot(); err != nil {
  58. break
  59. }
  60. }
  61. }
  62. }
  63. func closeConnection(trafficManager *trafficontrol.Manager) func(w http.ResponseWriter, r *http.Request) {
  64. return func(w http.ResponseWriter, r *http.Request) {
  65. id := chi.URLParam(r, "id")
  66. snapshot := trafficManager.Snapshot()
  67. for _, c := range snapshot.Connections {
  68. if id == c.ID() {
  69. c.Close()
  70. break
  71. }
  72. }
  73. render.NoContent(w, r)
  74. }
  75. }
  76. func closeAllConnections(trafficManager *trafficontrol.Manager) func(w http.ResponseWriter, r *http.Request) {
  77. return func(w http.ResponseWriter, r *http.Request) {
  78. snapshot := trafficManager.Snapshot()
  79. for _, c := range snapshot.Connections {
  80. c.Close()
  81. }
  82. render.NoContent(w, r)
  83. }
  84. }