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