github.com/sagernet/sing-box@v1.9.0-rc.20/experimental/clashapi/trafficontrol/manager.go (about)

     1  package trafficontrol
     2  
     3  import (
     4  	"runtime"
     5  	"time"
     6  
     7  	"github.com/sagernet/sing-box/experimental/clashapi/compatible"
     8  	"github.com/sagernet/sing/common/atomic"
     9  )
    10  
    11  type Manager struct {
    12  	uploadTemp    atomic.Int64
    13  	downloadTemp  atomic.Int64
    14  	uploadBlip    atomic.Int64
    15  	downloadBlip  atomic.Int64
    16  	uploadTotal   atomic.Int64
    17  	downloadTotal atomic.Int64
    18  
    19  	connections compatible.Map[string, tracker]
    20  	ticker      *time.Ticker
    21  	done        chan struct{}
    22  	// process     *process.Process
    23  	memory uint64
    24  }
    25  
    26  func NewManager() *Manager {
    27  	manager := &Manager{
    28  		ticker: time.NewTicker(time.Second),
    29  		done:   make(chan struct{}),
    30  		// process: &process.Process{Pid: int32(os.Getpid())},
    31  	}
    32  	go manager.handle()
    33  	return manager
    34  }
    35  
    36  func (m *Manager) Join(c tracker) {
    37  	m.connections.Store(c.ID(), c)
    38  }
    39  
    40  func (m *Manager) Leave(c tracker) {
    41  	m.connections.Delete(c.ID())
    42  }
    43  
    44  func (m *Manager) PushUploaded(size int64) {
    45  	m.uploadTemp.Add(size)
    46  	m.uploadTotal.Add(size)
    47  }
    48  
    49  func (m *Manager) PushDownloaded(size int64) {
    50  	m.downloadTemp.Add(size)
    51  	m.downloadTotal.Add(size)
    52  }
    53  
    54  func (m *Manager) Now() (up int64, down int64) {
    55  	return m.uploadBlip.Load(), m.downloadBlip.Load()
    56  }
    57  
    58  func (m *Manager) Total() (up int64, down int64) {
    59  	return m.uploadTotal.Load(), m.downloadTotal.Load()
    60  }
    61  
    62  func (m *Manager) Connections() int {
    63  	return m.connections.Len()
    64  }
    65  
    66  func (m *Manager) Snapshot() *Snapshot {
    67  	var connections []tracker
    68  	m.connections.Range(func(_ string, value tracker) bool {
    69  		connections = append(connections, value)
    70  		return true
    71  	})
    72  
    73  	var memStats runtime.MemStats
    74  	runtime.ReadMemStats(&memStats)
    75  	m.memory = memStats.StackInuse + memStats.HeapInuse + memStats.HeapIdle - memStats.HeapReleased
    76  
    77  	return &Snapshot{
    78  		UploadTotal:   m.uploadTotal.Load(),
    79  		DownloadTotal: m.downloadTotal.Load(),
    80  		Connections:   connections,
    81  		Memory:        m.memory,
    82  	}
    83  }
    84  
    85  func (m *Manager) ResetStatistic() {
    86  	m.uploadTemp.Store(0)
    87  	m.uploadBlip.Store(0)
    88  	m.uploadTotal.Store(0)
    89  	m.downloadTemp.Store(0)
    90  	m.downloadBlip.Store(0)
    91  	m.downloadTotal.Store(0)
    92  }
    93  
    94  func (m *Manager) handle() {
    95  	var uploadTemp int64
    96  	var downloadTemp int64
    97  	for {
    98  		select {
    99  		case <-m.done:
   100  			return
   101  		case <-m.ticker.C:
   102  		}
   103  		uploadTemp = m.uploadTemp.Swap(0)
   104  		downloadTemp = m.downloadTemp.Swap(0)
   105  		m.uploadBlip.Store(uploadTemp)
   106  		m.downloadBlip.Store(downloadTemp)
   107  	}
   108  }
   109  
   110  func (m *Manager) Close() error {
   111  	m.ticker.Stop()
   112  	close(m.done)
   113  	return nil
   114  }
   115  
   116  type Snapshot struct {
   117  	DownloadTotal int64     `json:"downloadTotal"`
   118  	UploadTotal   int64     `json:"uploadTotal"`
   119  	Connections   []tracker `json:"connections"`
   120  	Memory        uint64    `json:"memory"`
   121  }