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