sing-box/experimental/clashapi/connections.go

102 lines
2.5 KiB
Go
Raw Normal View History

2022-07-19 14:16:49 +00:00
package clashapi
import (
"bytes"
"net/http"
"strconv"
"time"
"github.com/sagernet/sing-box/adapter"
2022-07-22 01:29:13 +00:00
"github.com/sagernet/sing-box/experimental/clashapi/trafficontrol"
"github.com/sagernet/sing/common/json"
2023-11-09 08:59:44 +00:00
"github.com/sagernet/ws"
"github.com/sagernet/ws/wsutil"
2022-07-19 14:16:49 +00:00
"github.com/go-chi/chi/v5"
"github.com/go-chi/render"
2024-06-11 13:16:33 +00:00
"github.com/gofrs/uuid/v5"
2022-07-19 14:16:49 +00:00
)
func connectionRouter(router adapter.Router, trafficManager *trafficontrol.Manager) http.Handler {
2022-07-19 14:16:49 +00:00
r := chi.NewRouter()
r.Get("/", getConnections(trafficManager))
r.Delete("/", closeAllConnections(router, trafficManager))
2022-07-19 14:16:49 +00:00
r.Delete("/{id}", closeConnection(trafficManager))
return r
}
2022-07-22 01:29:13 +00:00
func getConnections(trafficManager *trafficontrol.Manager) func(w http.ResponseWriter, r *http.Request) {
2022-07-19 14:16:49 +00:00
return func(w http.ResponseWriter, r *http.Request) {
2023-11-09 08:59:44 +00:00
if r.Header.Get("Upgrade") != "websocket" {
2022-07-19 14:16:49 +00:00
snapshot := trafficManager.Snapshot()
render.JSON(w, r, snapshot)
return
}
2023-11-09 08:59:44 +00:00
conn, _, _, err := ws.UpgradeHTTP(r, w)
2022-07-19 14:16:49 +00:00
if err != nil {
return
}
intervalStr := r.URL.Query().Get("interval")
interval := 1000
if intervalStr != "" {
t, err := strconv.Atoi(intervalStr)
if err != nil {
render.Status(r, http.StatusBadRequest)
render.JSON(w, r, ErrBadRequest)
return
}
interval = t
}
buf := &bytes.Buffer{}
sendSnapshot := func() error {
buf.Reset()
snapshot := trafficManager.Snapshot()
if err := json.NewEncoder(buf).Encode(snapshot); err != nil {
return err
}
2023-11-09 08:59:44 +00:00
return wsutil.WriteServerText(conn, buf.Bytes())
2022-07-19 14:16:49 +00:00
}
if err = sendSnapshot(); err != nil {
return
}
tick := time.NewTicker(time.Millisecond * time.Duration(interval))
defer tick.Stop()
for range tick.C {
if err = sendSnapshot(); err != nil {
break
}
}
}
}
2022-07-22 01:29:13 +00:00
func closeConnection(trafficManager *trafficontrol.Manager) func(w http.ResponseWriter, r *http.Request) {
2022-07-19 14:16:49 +00:00
return func(w http.ResponseWriter, r *http.Request) {
2024-06-11 13:16:33 +00:00
id := uuid.FromStringOrNil(chi.URLParam(r, "id"))
2022-07-19 14:16:49 +00:00
snapshot := trafficManager.Snapshot()
for _, c := range snapshot.Connections {
2024-06-11 13:16:33 +00:00
if id == c.Metadata().ID {
2022-07-19 14:16:49 +00:00
c.Close()
break
}
}
render.NoContent(w, r)
}
}
func closeAllConnections(router adapter.Router, trafficManager *trafficontrol.Manager) func(w http.ResponseWriter, r *http.Request) {
2022-07-19 14:16:49 +00:00
return func(w http.ResponseWriter, r *http.Request) {
snapshot := trafficManager.Snapshot()
for _, c := range snapshot.Connections {
c.Close()
}
router.ResetNetwork()
2022-07-19 14:16:49 +00:00
render.NoContent(w, r)
}
}