package trafficontrol import ( "time" "github.com/sagernet/sing-box/experimental/clashapi/compatible" "go.uber.org/atomic" ) type Manager struct { connections compatible.Map[string, tracker] uploadTemp *atomic.Int64 downloadTemp *atomic.Int64 uploadBlip *atomic.Int64 downloadBlip *atomic.Int64 uploadTotal *atomic.Int64 downloadTotal *atomic.Int64 } func NewManager() *Manager { manager := &Manager{ uploadTemp: atomic.NewInt64(0), downloadTemp: atomic.NewInt64(0), uploadBlip: atomic.NewInt64(0), downloadBlip: atomic.NewInt64(0), uploadTotal: atomic.NewInt64(0), downloadTotal: atomic.NewInt64(0), } go manager.handle() return manager } func (m *Manager) Join(c tracker) { m.connections.Store(c.ID(), c) } func (m *Manager) Leave(c tracker) { m.connections.Delete(c.ID()) } func (m *Manager) PushUploaded(size int64) { m.uploadTemp.Add(size) m.uploadTotal.Add(size) } func (m *Manager) PushDownloaded(size int64) { m.downloadTemp.Add(size) m.downloadTotal.Add(size) } func (m *Manager) Now() (up int64, down int64) { return m.uploadBlip.Load(), m.downloadBlip.Load() } func (m *Manager) Snapshot() *Snapshot { connections := []tracker{} m.connections.Range(func(_ string, value tracker) bool { connections = append(connections, value) return true }) return &Snapshot{ UploadTotal: m.uploadTotal.Load(), DownloadTotal: m.downloadTotal.Load(), Connections: connections, } } func (m *Manager) ResetStatistic() { m.uploadTemp.Store(0) m.uploadBlip.Store(0) m.uploadTotal.Store(0) m.downloadTemp.Store(0) m.downloadBlip.Store(0) m.downloadTotal.Store(0) } func (m *Manager) handle() { ticker := time.NewTicker(time.Second) for range ticker.C { m.uploadBlip.Store(m.uploadTemp.Load()) m.uploadTemp.Store(0) m.downloadBlip.Store(m.downloadTemp.Load()) m.downloadTemp.Store(0) } } type Snapshot struct { DownloadTotal int64 `json:"downloadTotal"` UploadTotal int64 `json:"uploadTotal"` Connections []tracker `json:"connections"` }