connections.go 2.4 KB

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