sing-box/experimental/clashapi/trafficontrol/manager.go

175 lines
4.0 KiB
Go
Raw Normal View History

2022-07-22 09:29:13 +08:00
package trafficontrol
2022-07-19 22:16:49 +08:00
import (
2023-04-11 16:43:45 +08:00
"runtime"
2024-06-11 21:16:33 +08:00
"sync"
2022-07-19 22:16:49 +08:00
"time"
2024-06-11 21:16:33 +08:00
C "github.com/sagernet/sing-box/constant"
2022-07-19 22:16:49 +08:00
"github.com/sagernet/sing-box/experimental/clashapi/compatible"
2024-06-11 21:16:33 +08:00
"github.com/sagernet/sing/common"
2023-04-14 20:55:05 +08:00
"github.com/sagernet/sing/common/atomic"
2024-06-11 21:16:33 +08:00
"github.com/sagernet/sing/common/json"
"github.com/sagernet/sing/common/x/list"
"github.com/gofrs/uuid/v5"
2022-07-19 22:16:49 +08:00
)
type Manager struct {
2023-04-14 20:55:05 +08:00
uploadTemp atomic.Int64
downloadTemp atomic.Int64
uploadBlip atomic.Int64
downloadBlip atomic.Int64
uploadTotal atomic.Int64
downloadTotal atomic.Int64
2024-06-11 21:16:33 +08:00
connections compatible.Map[uuid.UUID, Tracker]
closedConnectionsAccess sync.Mutex
closedConnections list.List[TrackerMetadata]
ticker *time.Ticker
done chan struct{}
2023-04-11 16:43:45 +08:00
// process *process.Process
memory uint64
2022-07-19 22:16:49 +08:00
}
func NewManager() *Manager {
manager := &Manager{
2023-04-14 20:55:05 +08:00
ticker: time.NewTicker(time.Second),
done: make(chan struct{}),
2023-04-11 16:43:45 +08:00
// process: &process.Process{Pid: int32(os.Getpid())},
2022-07-19 22:16:49 +08:00
}
go manager.handle()
return manager
}
2024-06-11 21:16:33 +08:00
func (m *Manager) Join(c Tracker) {
m.connections.Store(c.Metadata().ID, c)
2022-07-19 22:16:49 +08:00
}
2024-06-11 21:16:33 +08:00
func (m *Manager) Leave(c Tracker) {
metadata := c.Metadata()
_, loaded := m.connections.LoadAndDelete(metadata.ID)
if loaded {
metadata.ClosedAt = time.Now()
m.closedConnectionsAccess.Lock()
defer m.closedConnectionsAccess.Unlock()
if m.closedConnections.Len() >= 1000 {
m.closedConnections.PopFront()
}
m.closedConnections.PushBack(metadata)
}
2022-07-19 22:16:49 +08:00
}
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()
}
2023-07-16 14:08:45 +08:00
func (m *Manager) Total() (up int64, down int64) {
return m.uploadTotal.Load(), m.downloadTotal.Load()
}
2024-06-11 21:16:33 +08:00
func (m *Manager) ConnectionsLen() int {
2023-07-16 14:08:45 +08:00
return m.connections.Len()
}
2024-06-11 21:16:33 +08:00
func (m *Manager) Connections() []TrackerMetadata {
var connections []TrackerMetadata
m.connections.Range(func(_ uuid.UUID, value Tracker) bool {
connections = append(connections, value.Metadata())
return true
})
return connections
}
func (m *Manager) ClosedConnections() []TrackerMetadata {
m.closedConnectionsAccess.Lock()
defer m.closedConnectionsAccess.Unlock()
return m.closedConnections.Array()
}
func (m *Manager) Connection(id uuid.UUID) Tracker {
connection, loaded := m.connections.Load(id)
if !loaded {
return nil
}
return connection
}
2022-07-19 22:16:49 +08:00
func (m *Manager) Snapshot() *Snapshot {
2024-06-11 21:16:33 +08:00
var connections []Tracker
m.connections.Range(func(_ uuid.UUID, value Tracker) bool {
if value.Metadata().OutboundType != C.TypeDNS {
connections = append(connections, value)
}
2022-07-19 22:16:49 +08:00
return true
})
2023-04-11 16:43:45 +08:00
var memStats runtime.MemStats
runtime.ReadMemStats(&memStats)
m.memory = memStats.StackInuse + memStats.HeapInuse + memStats.HeapIdle - memStats.HeapReleased
2022-07-19 22:16:49 +08:00
return &Snapshot{
2024-06-11 21:16:33 +08:00
Upload: m.uploadTotal.Load(),
Download: m.downloadTotal.Load(),
Connections: connections,
Memory: m.memory,
2022-07-19 22:16:49 +08:00
}
}
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() {
2022-08-02 18:47:23 +08:00
var uploadTemp int64
var downloadTemp int64
2022-07-30 14:50:33 +08:00
for {
select {
case <-m.done:
return
case <-m.ticker.C:
}
2022-08-02 18:47:23 +08:00
uploadTemp = m.uploadTemp.Swap(0)
downloadTemp = m.downloadTemp.Swap(0)
m.uploadBlip.Store(uploadTemp)
m.downloadBlip.Store(downloadTemp)
2022-07-19 22:16:49 +08:00
}
}
2022-07-30 14:50:33 +08:00
func (m *Manager) Close() error {
m.ticker.Stop()
close(m.done)
return nil
}
2022-07-19 22:16:49 +08:00
type Snapshot struct {
2024-06-11 21:16:33 +08:00
Download int64
Upload int64
Connections []Tracker
Memory uint64
}
func (s *Snapshot) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]any{
"downloadTotal": s.Download,
"uploadTotal": s.Upload,
"connections": common.Map(s.Connections, func(t Tracker) TrackerMetadata { return t.Metadata() }),
"memory": s.Memory,
})
2022-07-19 22:16:49 +08:00
}