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  }