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