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  }