api_meta.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. package clashapi
  2. import (
  3. "bytes"
  4. "context"
  5. "net"
  6. "net/http"
  7. "runtime/debug"
  8. "time"
  9. "github.com/sagernet/sing-box/experimental/clashapi/trafficontrol"
  10. "github.com/sagernet/sing/common/json"
  11. "github.com/sagernet/ws"
  12. "github.com/sagernet/ws/wsutil"
  13. "github.com/go-chi/chi/v5"
  14. "github.com/go-chi/chi/v5/middleware"
  15. "github.com/go-chi/render"
  16. )
  17. // API created by Clash.Meta
  18. func (s *Server) setupMetaAPI(r chi.Router) {
  19. if s.logDebug {
  20. r := chi.NewRouter()
  21. r.Put("/gc", func(w http.ResponseWriter, r *http.Request) {
  22. debug.FreeOSMemory()
  23. })
  24. r.Mount("/", middleware.Profiler())
  25. }
  26. r.Get("/memory", memory(s.ctx, s.trafficManager))
  27. r.Mount("/group", groupRouter(s))
  28. r.Mount("/upgrade", upgradeRouter(s))
  29. }
  30. type Memory struct {
  31. Inuse uint64 `json:"inuse"`
  32. OSLimit uint64 `json:"oslimit"` // maybe we need it in the future
  33. }
  34. func memory(ctx context.Context, trafficManager *trafficontrol.Manager) func(w http.ResponseWriter, r *http.Request) {
  35. return func(w http.ResponseWriter, r *http.Request) {
  36. var conn net.Conn
  37. if r.Header.Get("Upgrade") == "websocket" {
  38. var err error
  39. conn, _, _, err = ws.UpgradeHTTP(r, w)
  40. if err != nil {
  41. return
  42. }
  43. defer conn.Close()
  44. }
  45. if conn == nil {
  46. w.Header().Set("Content-Type", "application/json")
  47. render.Status(r, http.StatusOK)
  48. }
  49. tick := time.NewTicker(time.Second)
  50. defer tick.Stop()
  51. buf := &bytes.Buffer{}
  52. var err error
  53. first := true
  54. for {
  55. select {
  56. case <-ctx.Done():
  57. return
  58. case <-tick.C:
  59. }
  60. buf.Reset()
  61. inuse := trafficManager.Snapshot().Memory
  62. // make chat.js begin with zero
  63. // this is shit var,but we need output 0 for first time
  64. if first {
  65. first = false
  66. inuse = 0
  67. }
  68. if err := json.NewEncoder(buf).Encode(Memory{
  69. Inuse: inuse,
  70. OSLimit: 0,
  71. }); err != nil {
  72. break
  73. }
  74. if conn == nil {
  75. _, err = w.Write(buf.Bytes())
  76. w.(http.Flusher).Flush()
  77. } else {
  78. err = wsutil.WriteServerText(conn, buf.Bytes())
  79. }
  80. if err != nil {
  81. break
  82. }
  83. }
  84. }
  85. }