github.com/yaling888/clash@v1.53.0/hub/route/connections.go (about)

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