github.com/yaling888/clash@v1.53.0/tunnel/statistic/tracker.go (about) 1 package statistic 2 3 import ( 4 "net" 5 "time" 6 7 "github.com/samber/lo" 8 "go.uber.org/atomic" 9 10 "github.com/yaling888/clash/common/uuid" 11 C "github.com/yaling888/clash/constant" 12 ) 13 14 type tracker interface { 15 ID() string 16 Close() error 17 } 18 19 type trackerInfo struct { 20 UUID uuid.UUID `json:"id"` 21 Metadata *C.Metadata `json:"metadata"` 22 UploadTotal *atomic.Int64 `json:"upload"` 23 DownloadTotal *atomic.Int64 `json:"download"` 24 Start time.Time `json:"start"` 25 Chain C.Chain `json:"chains"` 26 Rule string `json:"rule"` 27 RulePayload string `json:"rulePayload"` 28 RuleGroup C.RuleGroup `json:"ruleGroup"` 29 } 30 31 type tcpTracker struct { 32 C.Conn `json:"-"` 33 *trackerInfo 34 manager *Manager 35 } 36 37 func (tt *tcpTracker) ID() string { 38 return tt.UUID.String() 39 } 40 41 func (tt *tcpTracker) Read(b []byte) (int, error) { 42 n, err := tt.Conn.Read(b) 43 download := int64(n) 44 tt.manager.PushDownloaded(download) 45 tt.DownloadTotal.Add(download) 46 return n, err 47 } 48 49 func (tt *tcpTracker) Write(b []byte) (int, error) { 50 n, err := tt.Conn.Write(b) 51 upload := int64(n) 52 tt.manager.PushUploaded(upload) 53 tt.UploadTotal.Add(upload) 54 return n, err 55 } 56 57 func (tt *tcpTracker) Close() error { 58 tt.manager.Leave(tt) 59 return tt.Conn.Close() 60 } 61 62 func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.Rule) C.Conn { 63 id := uuid.RandomB64Hlf() 64 65 t := &tcpTracker{ 66 Conn: conn, 67 manager: manager, 68 trackerInfo: &trackerInfo{ 69 UUID: id, 70 Start: time.Now(), 71 Metadata: metadata, 72 Chain: conn.Chains(), 73 UploadTotal: atomic.NewInt64(0), 74 DownloadTotal: atomic.NewInt64(0), 75 }, 76 } 77 78 if rule != nil { 79 t.trackerInfo.Rule = rule.RuleType().String() 80 t.trackerInfo.RulePayload = rule.Payload() 81 t.trackerInfo.RuleGroup = lo.WithoutEmpty(rule.RuleGroups()) 82 } 83 84 manager.Join(t) 85 return t 86 } 87 88 type udpTracker struct { 89 C.PacketConn `json:"-"` 90 *trackerInfo 91 manager *Manager 92 } 93 94 func (ut *udpTracker) ID() string { 95 return ut.UUID.String() 96 } 97 98 func (ut *udpTracker) ReadFrom(b []byte) (int, net.Addr, error) { 99 n, addr, err := ut.PacketConn.ReadFrom(b) 100 download := int64(n) 101 ut.manager.PushDownloaded(download) 102 ut.DownloadTotal.Add(download) 103 return n, addr, err 104 } 105 106 func (ut *udpTracker) WriteTo(b []byte, addr net.Addr) (int, error) { 107 n, err := ut.PacketConn.WriteTo(b, addr) 108 upload := int64(n) 109 ut.manager.PushUploaded(upload) 110 ut.UploadTotal.Add(upload) 111 return n, err 112 } 113 114 func (ut *udpTracker) Close() error { 115 ut.manager.Leave(ut) 116 return ut.PacketConn.Close() 117 } 118 119 func NewUDPTracker(conn C.PacketConn, manager *Manager, metadata *C.Metadata, rule C.Rule) *udpTracker { 120 id := uuid.RandomB64Hlf() 121 122 ut := &udpTracker{ 123 PacketConn: conn, 124 manager: manager, 125 trackerInfo: &trackerInfo{ 126 UUID: id, 127 Start: time.Now(), 128 Metadata: metadata, 129 Chain: conn.Chains(), 130 UploadTotal: atomic.NewInt64(0), 131 DownloadTotal: atomic.NewInt64(0), 132 }, 133 } 134 135 if rule != nil { 136 ut.trackerInfo.Rule = rule.RuleType().String() 137 ut.trackerInfo.RulePayload = rule.Payload() 138 ut.trackerInfo.RuleGroup = lo.WithoutEmpty(rule.RuleGroups()) 139 } 140 141 manager.Join(ut) 142 return ut 143 }