manager.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. package trafficontrol
  2. import (
  3. "runtime"
  4. "sync"
  5. "sync/atomic"
  6. "time"
  7. "github.com/sagernet/sing-box/common/compatible"
  8. C "github.com/sagernet/sing-box/constant"
  9. "github.com/sagernet/sing/common"
  10. "github.com/sagernet/sing/common/json"
  11. "github.com/sagernet/sing/common/x/list"
  12. "github.com/gofrs/uuid/v5"
  13. )
  14. type Manager struct {
  15. uploadTotal atomic.Int64
  16. downloadTotal atomic.Int64
  17. connections compatible.Map[uuid.UUID, Tracker]
  18. closedConnectionsAccess sync.Mutex
  19. closedConnections list.List[TrackerMetadata]
  20. // process *process.Process
  21. memory uint64
  22. }
  23. func NewManager() *Manager {
  24. return &Manager{}
  25. }
  26. func (m *Manager) Join(c Tracker) {
  27. m.connections.Store(c.Metadata().ID, c)
  28. }
  29. func (m *Manager) Leave(c Tracker) {
  30. metadata := c.Metadata()
  31. _, loaded := m.connections.LoadAndDelete(metadata.ID)
  32. if loaded {
  33. metadata.ClosedAt = time.Now()
  34. m.closedConnectionsAccess.Lock()
  35. defer m.closedConnectionsAccess.Unlock()
  36. if m.closedConnections.Len() >= 1000 {
  37. m.closedConnections.PopFront()
  38. }
  39. m.closedConnections.PushBack(metadata)
  40. }
  41. }
  42. func (m *Manager) PushUploaded(size int64) {
  43. m.uploadTotal.Add(size)
  44. }
  45. func (m *Manager) PushDownloaded(size int64) {
  46. m.downloadTotal.Add(size)
  47. }
  48. func (m *Manager) Total() (up int64, down int64) {
  49. return m.uploadTotal.Load(), m.downloadTotal.Load()
  50. }
  51. func (m *Manager) ConnectionsLen() int {
  52. return m.connections.Len()
  53. }
  54. func (m *Manager) Connections() []TrackerMetadata {
  55. var connections []TrackerMetadata
  56. m.connections.Range(func(_ uuid.UUID, value Tracker) bool {
  57. connections = append(connections, value.Metadata())
  58. return true
  59. })
  60. return connections
  61. }
  62. func (m *Manager) ClosedConnections() []TrackerMetadata {
  63. m.closedConnectionsAccess.Lock()
  64. defer m.closedConnectionsAccess.Unlock()
  65. return m.closedConnections.Array()
  66. }
  67. func (m *Manager) Connection(id uuid.UUID) Tracker {
  68. connection, loaded := m.connections.Load(id)
  69. if !loaded {
  70. return nil
  71. }
  72. return connection
  73. }
  74. func (m *Manager) Snapshot() *Snapshot {
  75. var connections []Tracker
  76. m.connections.Range(func(_ uuid.UUID, value Tracker) bool {
  77. if value.Metadata().OutboundType != C.TypeDNS {
  78. connections = append(connections, value)
  79. }
  80. return true
  81. })
  82. var memStats runtime.MemStats
  83. runtime.ReadMemStats(&memStats)
  84. m.memory = memStats.StackInuse + memStats.HeapInuse + memStats.HeapIdle - memStats.HeapReleased
  85. return &Snapshot{
  86. Upload: m.uploadTotal.Load(),
  87. Download: m.downloadTotal.Load(),
  88. Connections: connections,
  89. Memory: m.memory,
  90. }
  91. }
  92. func (m *Manager) ResetStatistic() {
  93. m.uploadTotal.Store(0)
  94. m.downloadTotal.Store(0)
  95. }
  96. type Snapshot struct {
  97. Download int64
  98. Upload int64
  99. Connections []Tracker
  100. Memory uint64
  101. }
  102. func (s *Snapshot) MarshalJSON() ([]byte, error) {
  103. return json.Marshal(map[string]any{
  104. "downloadTotal": s.Download,
  105. "uploadTotal": s.Upload,
  106. "connections": common.Map(s.Connections, func(t Tracker) TrackerMetadata { return t.Metadata() }),
  107. "memory": s.Memory,
  108. })
  109. }