mirror of
https://github.com/wyx2685/V2bX.git
synced 2025-03-16 01:08:13 -04:00
update example, add realtime option, fix ip limit bug for packet protocol
This commit is contained in:
parent
c6658c2ce1
commit
48da83fc3d
@ -58,6 +58,7 @@ func (p *Conf) Watch(filePath string, reload func()) error {
|
|||||||
case event := <-watcher.Events:
|
case event := <-watcher.Events:
|
||||||
if event.Has(fsnotify.Write) {
|
if event.Has(fsnotify.Write) {
|
||||||
log.Println("config dir changed, reloading...")
|
log.Println("config dir changed, reloading...")
|
||||||
|
*p = *New()
|
||||||
err := p.LoadFromPath(filePath)
|
err := p.LoadFromPath(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("reload config error: %s", err)
|
log.Printf("reload config error: %s", err)
|
||||||
|
95
conf/node.go
95
conf/node.go
@ -1,14 +1,46 @@
|
|||||||
package conf
|
package conf
|
||||||
|
|
||||||
type CertConfig struct {
|
type NodeConfig struct {
|
||||||
CertMode string `yaml:"CertMode"` // none, file, http, dns
|
ApiConfig *ApiConfig `yaml:"ApiConfig"`
|
||||||
RejectUnknownSni bool `yaml:"RejectUnknownSni"`
|
ControllerConfig *ControllerConfig `yaml:"ControllerConfig"`
|
||||||
CertDomain string `yaml:"CertDomain"`
|
}
|
||||||
CertFile string `yaml:"CertFile"`
|
|
||||||
KeyFile string `yaml:"KeyFile"`
|
type ApiConfig struct {
|
||||||
Provider string `yaml:"Provider"` // alidns, cloudflare, gandi, godaddy....
|
APIHost string `yaml:"ApiHost"`
|
||||||
Email string `yaml:"Email"`
|
NodeID int `yaml:"NodeID"`
|
||||||
DNSEnv map[string]string `yaml:"DNSEnv"`
|
Key string `yaml:"ApiKey"`
|
||||||
|
NodeType string `yaml:"NodeType"`
|
||||||
|
Timeout int `yaml:"Timeout"`
|
||||||
|
RuleListPath string `yaml:"RuleListPath"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ControllerConfig struct {
|
||||||
|
ListenIP string `yaml:"ListenIP"`
|
||||||
|
SendIP string `yaml:"SendIP"`
|
||||||
|
EnableDNS bool `yaml:"EnableDNS"`
|
||||||
|
DNSType string `yaml:"DNSType"`
|
||||||
|
EnableVless bool `yaml:"EnableVless"`
|
||||||
|
EnableTls bool `yaml:"EnableTls"`
|
||||||
|
LimitConfig LimitConfig `yaml:"LimitConfig"`
|
||||||
|
DisableUploadTraffic bool `yaml:"DisableUploadTraffic"`
|
||||||
|
DisableGetRule bool `yaml:"DisableGetRule"`
|
||||||
|
EnableProxyProtocol bool `yaml:"EnableProxyProtocol"`
|
||||||
|
EnableFallback bool `yaml:"EnableFallback"`
|
||||||
|
DisableIVCheck bool `yaml:"DisableIVCheck"`
|
||||||
|
DisableSniffing bool `yaml:"DisableSniffing"`
|
||||||
|
FallBackConfigs []*FallBackConfig `yaml:"FallBackConfigs"`
|
||||||
|
CertConfig *CertConfig `yaml:"CertConfig"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LimitConfig struct {
|
||||||
|
EnableRealtime bool `yaml:"EnableRealtime"`
|
||||||
|
SpeedLimit int `yaml:"SpeedLimit"`
|
||||||
|
IPLimit int `yaml:"DeviceLimit"`
|
||||||
|
ConnLimit int `yaml:"ConnLimit"`
|
||||||
|
EnableIpRecorder bool `yaml:"EnableIpRecorder"`
|
||||||
|
IpRecorderConfig *IpReportConfig `yaml:"IpRecorderConfig"`
|
||||||
|
EnableDynamicSpeedLimit bool `yaml:"EnableDynamicSpeedLimit"`
|
||||||
|
DynamicSpeedLimitConfig *DynamicSpeedLimitConfig `yaml:"DynamicSpeedLimitConfig"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FallBackConfig struct {
|
type FallBackConfig struct {
|
||||||
@ -47,40 +79,13 @@ type DynamicSpeedLimitConfig struct {
|
|||||||
ExpireTime int `yaml:"ExpireTime"`
|
ExpireTime int `yaml:"ExpireTime"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ControllerConfig struct {
|
type CertConfig struct {
|
||||||
ListenIP string `yaml:"ListenIP"`
|
CertMode string `yaml:"CertMode"` // none, file, http, dns
|
||||||
SendIP string `yaml:"SendIP"`
|
RejectUnknownSni bool `yaml:"RejectUnknownSni"`
|
||||||
EnableDNS bool `yaml:"EnableDNS"`
|
CertDomain string `yaml:"CertDomain"`
|
||||||
DNSType string `yaml:"DNSType"`
|
CertFile string `yaml:"CertFile"`
|
||||||
EnableVless bool `yaml:"EnableVless"`
|
KeyFile string `yaml:"KeyFile"`
|
||||||
EnableTls bool `yaml:"EnableTls"`
|
Provider string `yaml:"Provider"` // alidns, cloudflare, gandi, godaddy....
|
||||||
SpeedLimit int `yaml:"SpeedLimit"`
|
Email string `yaml:"Email"`
|
||||||
IPLimit int `yaml:"DeviceLimit"`
|
DNSEnv map[string]string `yaml:"DNSEnv"`
|
||||||
ConnLimit int `yaml:"ConnLimit"`
|
|
||||||
DisableUploadTraffic bool `yaml:"DisableUploadTraffic"`
|
|
||||||
DisableGetRule bool `yaml:"DisableGetRule"`
|
|
||||||
EnableProxyProtocol bool `yaml:"EnableProxyProtocol"`
|
|
||||||
EnableFallback bool `yaml:"EnableFallback"`
|
|
||||||
DisableIVCheck bool `yaml:"DisableIVCheck"`
|
|
||||||
DisableSniffing bool `yaml:"DisableSniffing"`
|
|
||||||
FallBackConfigs []*FallBackConfig `yaml:"FallBackConfigs"`
|
|
||||||
EnableIpRecorder bool `yaml:"EnableIpRecorder"`
|
|
||||||
IpRecorderConfig *IpReportConfig `yaml:"IpRecorderConfig"`
|
|
||||||
EnableDynamicSpeedLimit bool `yaml:"EnableDynamicSpeedLimit"`
|
|
||||||
DynamicSpeedLimitConfig *DynamicSpeedLimitConfig `yaml:"DynamicSpeedLimitConfig"`
|
|
||||||
CertConfig *CertConfig `yaml:"CertConfig"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ApiConfig struct {
|
|
||||||
APIHost string `yaml:"ApiHost"`
|
|
||||||
NodeID int `yaml:"NodeID"`
|
|
||||||
Key string `yaml:"ApiKey"`
|
|
||||||
NodeType string `yaml:"NodeType"`
|
|
||||||
Timeout int `yaml:"Timeout"`
|
|
||||||
RuleListPath string `yaml:"RuleListPath"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type NodeConfig struct {
|
|
||||||
ApiConfig *ApiConfig `yaml:"ApiConfig"`
|
|
||||||
ControllerConfig *ControllerConfig `yaml:"ControllerConfig"`
|
|
||||||
}
|
}
|
||||||
|
@ -13,31 +13,32 @@ ConnetionConfig:
|
|||||||
DownlinkOnly: 4 # Time limit when the connection is closed after the uplink is closed, Second
|
DownlinkOnly: 4 # Time limit when the connection is closed after the uplink is closed, Second
|
||||||
BufferSize: 64 # The internal cache size of each connection, kB
|
BufferSize: 64 # The internal cache size of each connection, kB
|
||||||
Nodes:
|
Nodes:
|
||||||
-
|
- ApiConfig:
|
||||||
ApiConfig:
|
|
||||||
ApiHost: "http://127.0.0.1:667"
|
ApiHost: "http://127.0.0.1:667"
|
||||||
ApiKey: "123"
|
ApiKey: "123"
|
||||||
NodeID: 41
|
NodeID: 41
|
||||||
NodeType: V2ray # Node type: V2ray, Shadowsocks, Trojan
|
NodeType: V2ray # Node type: V2ray, Shadowsocks, Trojan
|
||||||
Timeout: 30 # Timeout for the api request
|
Timeout: 30 # Timeout for the api request
|
||||||
EnableVless: false # Enable Vless for V2ray Type
|
|
||||||
SpeedLimit: 0 # Mbps, Local settings will replace remote settings, 0 means disable
|
|
||||||
DeviceLimit: 0 # Local settings will replace remote settings, 0 means disable
|
|
||||||
RuleListPath: # /etc/XrayR/rulelist Path to local rulelist file
|
RuleListPath: # /etc/XrayR/rulelist Path to local rulelist file
|
||||||
ControllerConfig:
|
ControllerConfig:
|
||||||
ListenIP: 0.0.0.0 # IP address you want to listen
|
ListenIP: 0.0.0.0 # IP address you want to listen
|
||||||
SendIP: 0.0.0.0 # IP address you want to send pacakage
|
SendIP: 0.0.0.0 # IP address you want to send pacakage
|
||||||
EnableDNS: false # Use custom DNS config, Please ensure that you set the dns.json well
|
EnableDNS: false # Use custom DNS config, Please ensure that you set the dns.json well
|
||||||
DNSType: AsIs # AsIs, UseIP, UseIPv4, UseIPv6, DNS strategy
|
DNSType: AsIs # AsIs, UseIP, UseIPv4, UseIPv6, DNS strategy
|
||||||
|
EnableVless: false # Enable Vless for V2ray Type
|
||||||
EnableProxyProtocol: false # Only works for WebSocket and TCP
|
EnableProxyProtocol: false # Only works for WebSocket and TCP
|
||||||
EnableFallback: false # Only support for Trojan and Vless
|
EnableFallback: false # Only support for Trojan and Vless
|
||||||
FallBackConfigs: # Support multiple fallbacks
|
FallBackConfigs: # Support multiple fallbacks
|
||||||
-
|
- SNI: # TLS SNI(Server Name Indication), Empty for any
|
||||||
SNI: # TLS SNI(Server Name Indication), Empty for any
|
|
||||||
Alpn: # Alpn, Empty for any
|
Alpn: # Alpn, Empty for any
|
||||||
Path: # HTTP PATH, Empty for any
|
Path: # HTTP PATH, Empty for any
|
||||||
Dest: 80 # Required, Destination of fallback, check https://xtls.github.io/config/features/fallback.html for details.
|
Dest: 80 # Required, Destination of fallback, check https://xtls.github.io/config/features/fallback.html for details.
|
||||||
ProxyProtocolVer: 0 # Send PROXY protocol version, 0 for dsable
|
ProxyProtocolVer: 0 # Send PROXY protocol version, 0 for dsable
|
||||||
|
LimitConfig:
|
||||||
|
EnableRealtime: false # Check device limit on real time
|
||||||
|
SpeedLimit: 0 # Mbps, Local settings will replace remote settings, 0 means disable
|
||||||
|
DeviceLimit: 0 # Local settings will replace remote settings, 0 means disable
|
||||||
|
ConnLimit: 0 # Connecting limit, only working for TCP, 0mean
|
||||||
EnableIpRecorder: false # Enable online ip report
|
EnableIpRecorder: false # Enable online ip report
|
||||||
IpRecorderConfig:
|
IpRecorderConfig:
|
||||||
Type: "Recorder" # Recorder type: Recorder, Redis
|
Type: "Recorder" # Recorder type: Recorder, Redis
|
||||||
|
@ -2,13 +2,13 @@ package limiter
|
|||||||
|
|
||||||
import "log"
|
import "log"
|
||||||
|
|
||||||
func ClearPacketOnlineIP() error {
|
func ClearOnlineIP() error {
|
||||||
log.Println("Limiter: Clear packet online ip...")
|
log.Println("Limiter: Clear online ip...")
|
||||||
limitLock.RLock()
|
limitLock.RLock()
|
||||||
for _, l := range limiter {
|
for _, l := range limiter {
|
||||||
l.ConnLimiter.ClearPacketOnlineIP()
|
l.ConnLimiter.ClearOnlineIP()
|
||||||
}
|
}
|
||||||
limitLock.RUnlock()
|
limitLock.RUnlock()
|
||||||
log.Println("Limiter: Clear packet online ip done")
|
log.Println("Limiter: Clear online ip done")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -5,15 +5,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ConnLimiter struct {
|
type ConnLimiter struct {
|
||||||
realTime bool
|
realtime bool
|
||||||
ipLimit int
|
ipLimit int
|
||||||
connLimit int
|
connLimit int
|
||||||
count sync.Map // map[string]int
|
count sync.Map // map[string]int
|
||||||
ip sync.Map // map[string]map[string]int
|
ip sync.Map // map[string]map[string]int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConnLimiter(conn int, ip int) *ConnLimiter {
|
func NewConnLimiter(conn int, ip int, realtime bool) *ConnLimiter {
|
||||||
return &ConnLimiter{
|
return &ConnLimiter{
|
||||||
|
realtime: realtime,
|
||||||
connLimit: conn,
|
connLimit: conn,
|
||||||
ipLimit: ip,
|
ipLimit: ip,
|
||||||
count: sync.Map{},
|
count: sync.Map{},
|
||||||
@ -38,11 +39,15 @@ func (c *ConnLimiter) AddConnCount(user string, ip string, isTcp bool) (limit bo
|
|||||||
}
|
}
|
||||||
// default user map
|
// default user map
|
||||||
ipMap := new(sync.Map)
|
ipMap := new(sync.Map)
|
||||||
|
if c.realtime {
|
||||||
if isTcp {
|
if isTcp {
|
||||||
ipMap.Store(ip, 2)
|
ipMap.Store(ip, 2)
|
||||||
} else {
|
} else {
|
||||||
ipMap.Store(ip, 1)
|
ipMap.Store(ip, 1)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
ipMap.Store(ip, struct{}{})
|
||||||
|
}
|
||||||
// check user online ip
|
// check user online ip
|
||||||
if v, ok := c.ip.LoadOrStore(user, ipMap); ok {
|
if v, ok := c.ip.LoadOrStore(user, ipMap); ok {
|
||||||
// have user
|
// have user
|
||||||
@ -50,10 +55,12 @@ func (c *ConnLimiter) AddConnCount(user string, ip string, isTcp bool) (limit bo
|
|||||||
cn := 0
|
cn := 0
|
||||||
if online, ok := ips.Load(ip); ok {
|
if online, ok := ips.Load(ip); ok {
|
||||||
// online ip
|
// online ip
|
||||||
if isTcp {
|
if c.realtime {
|
||||||
|
if online.(int)%2 == 0 && isTcp {
|
||||||
// count add
|
// count add
|
||||||
ips.Store(ip, online.(int)+2)
|
ips.Store(ip, online.(int)+2)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// not online ip
|
// not online ip
|
||||||
ips.Range(func(_, _ interface{}) bool {
|
ips.Range(func(_, _ interface{}) bool {
|
||||||
@ -67,11 +74,15 @@ func (c *ConnLimiter) AddConnCount(user string, ip string, isTcp bool) (limit bo
|
|||||||
if limit {
|
if limit {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if c.realtime {
|
||||||
if isTcp {
|
if isTcp {
|
||||||
ips.Store(ip, 2)
|
ips.Store(ip, 2)
|
||||||
} else {
|
} else {
|
||||||
ips.Store(ip, 1)
|
ips.Store(ip, 1)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
ips.Store(ip, struct{}{})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -79,6 +90,9 @@ func (c *ConnLimiter) AddConnCount(user string, ip string, isTcp bool) (limit bo
|
|||||||
|
|
||||||
// DelConnCount Delete tcp connection count, no tcp do not use
|
// DelConnCount Delete tcp connection count, no tcp do not use
|
||||||
func (c *ConnLimiter) DelConnCount(user string, ip string) {
|
func (c *ConnLimiter) DelConnCount(user string, ip string) {
|
||||||
|
if !c.realtime {
|
||||||
|
return
|
||||||
|
}
|
||||||
if c.connLimit != 0 {
|
if c.connLimit != 0 {
|
||||||
if v, ok := c.count.Load(user); ok {
|
if v, ok := c.count.Load(user); ok {
|
||||||
if v.(int) == 1 {
|
if v.(int) == 1 {
|
||||||
@ -111,12 +125,18 @@ func (c *ConnLimiter) DelConnCount(user string, ip string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearPacketOnlineIP Clear udp,icmp and other packet protocol online ip
|
// ClearOnlineIP Clear udp,icmp and other packet protocol online ip
|
||||||
func (c *ConnLimiter) ClearPacketOnlineIP() {
|
func (c *ConnLimiter) ClearOnlineIP() {
|
||||||
c.ip.Range(func(_, v any) bool {
|
c.ip.Range(func(_, v any) bool {
|
||||||
userIp := v.(*sync.Map)
|
userIp := v.(*sync.Map)
|
||||||
userIp.Range(func(ip, v any) bool {
|
userIp.Range(func(ip, v any) bool {
|
||||||
|
if c.realtime {
|
||||||
|
// clear not realtime ip
|
||||||
|
userIp.Delete(ip)
|
||||||
|
return true
|
||||||
|
}
|
||||||
if v.(int) == 1 {
|
if v.(int) == 1 {
|
||||||
|
// clear packet ip for realtime
|
||||||
userIp.Delete(ip)
|
userIp.Delete(ip)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -26,7 +26,7 @@ func TestConnLimiter_DelConnCount(t *testing.T) {
|
|||||||
func TestConnLimiter_ClearPacketOnlineIP(t *testing.T) {
|
func TestConnLimiter_ClearPacketOnlineIP(t *testing.T) {
|
||||||
t.Log(c.AddConnCount("1", "1", false))
|
t.Log(c.AddConnCount("1", "1", false))
|
||||||
t.Log(c.AddConnCount("1", "2", false))
|
t.Log(c.AddConnCount("1", "2", false))
|
||||||
c.ClearPacketOnlineIP()
|
c.ClearOnlineIP()
|
||||||
t.Log(c.AddConnCount("1", "2", true))
|
t.Log(c.AddConnCount("1", "2", true))
|
||||||
c.DelConnCount("1", "2")
|
c.DelConnCount("1", "2")
|
||||||
t.Log(c.AddConnCount("1", "1", false))
|
t.Log(c.AddConnCount("1", "1", false))
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Yuzuki616/V2bX/api/panel"
|
"github.com/Yuzuki616/V2bX/api/panel"
|
||||||
|
"github.com/Yuzuki616/V2bX/conf"
|
||||||
"github.com/juju/ratelimit"
|
"github.com/juju/ratelimit"
|
||||||
"github.com/xtls/xray-core/common/task"
|
"github.com/xtls/xray-core/common/task"
|
||||||
"log"
|
"log"
|
||||||
@ -18,10 +19,10 @@ func Init() {
|
|||||||
limiter = map[string]*Limiter{}
|
limiter = map[string]*Limiter{}
|
||||||
c := task.Periodic{
|
c := task.Periodic{
|
||||||
Interval: time.Minute * 2,
|
Interval: time.Minute * 2,
|
||||||
Execute: ClearPacketOnlineIP,
|
Execute: ClearOnlineIP,
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
log.Println("Limiter: ClearPacketOnlineIP started")
|
log.Println("Limiter: ClearOnlineIP started")
|
||||||
time.Sleep(time.Minute * 2)
|
time.Sleep(time.Minute * 2)
|
||||||
c.Start()
|
c.Start()
|
||||||
}()
|
}()
|
||||||
@ -43,17 +44,11 @@ type UserLimitInfo struct {
|
|||||||
ExpireTime int64
|
ExpireTime int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type LimitConfig struct {
|
func AddLimiter(tag string, l *conf.LimitConfig, users []panel.UserInfo) *Limiter {
|
||||||
SpeedLimit int
|
|
||||||
IpLimit int
|
|
||||||
ConnLimit int
|
|
||||||
}
|
|
||||||
|
|
||||||
func AddLimiter(tag string, l *LimitConfig, users []panel.UserInfo) *Limiter {
|
|
||||||
info := &Limiter{
|
info := &Limiter{
|
||||||
SpeedLimit: l.SpeedLimit,
|
SpeedLimit: l.SpeedLimit,
|
||||||
UserLimitInfo: new(sync.Map),
|
UserLimitInfo: new(sync.Map),
|
||||||
ConnLimiter: NewConnLimiter(l.ConnLimit, l.IpLimit),
|
ConnLimiter: NewConnLimiter(l.ConnLimit, l.IPLimit, l.EnableRealtime),
|
||||||
SpeedLimiter: new(sync.Map),
|
SpeedLimiter: new(sync.Map),
|
||||||
}
|
}
|
||||||
for i := range users {
|
for i := range users {
|
||||||
|
@ -58,11 +58,7 @@ func (c *Controller) Start() error {
|
|||||||
c.Tag = c.buildNodeTag()
|
c.Tag = c.buildNodeTag()
|
||||||
|
|
||||||
// add limiter
|
// add limiter
|
||||||
l := limiter.AddLimiter(c.Tag, &limiter.LimitConfig{
|
l := limiter.AddLimiter(c.Tag, &c.LimitConfig, c.userList)
|
||||||
SpeedLimit: c.SpeedLimit,
|
|
||||||
IpLimit: c.IPLimit,
|
|
||||||
ConnLimit: c.ConnLimit,
|
|
||||||
}, c.userList)
|
|
||||||
// add rule limiter
|
// add rule limiter
|
||||||
if !c.DisableGetRule {
|
if !c.DisableGetRule {
|
||||||
if err = l.UpdateRule(c.nodeInfo.Rules); err != nil {
|
if err = l.UpdateRule(c.nodeInfo.Rules); err != nil {
|
||||||
|
@ -88,11 +88,7 @@ func (c *Controller) nodeInfoMonitor() (err error) {
|
|||||||
if nodeInfoChanged {
|
if nodeInfoChanged {
|
||||||
c.userList = newUserInfo
|
c.userList = newUserInfo
|
||||||
// Add new Limiter
|
// Add new Limiter
|
||||||
l := limiter.AddLimiter(c.Tag, &limiter.LimitConfig{
|
l := limiter.AddLimiter(c.Tag, &c.LimitConfig, newUserInfo)
|
||||||
SpeedLimit: c.SpeedLimit,
|
|
||||||
IpLimit: c.IPLimit,
|
|
||||||
ConnLimit: c.ConnLimit,
|
|
||||||
}, newUserInfo)
|
|
||||||
err = c.addNewUser(newUserInfo, newNodeInfo)
|
err = c.addNewUser(newUserInfo, newNodeInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
@ -243,7 +239,7 @@ func (c *Controller) reportUserTraffic() (err error) {
|
|||||||
for i := range c.userList {
|
for i := range c.userList {
|
||||||
up, down := c.server.GetUserTraffic(c.buildUserTag(&(c.userList)[i]), true)
|
up, down := c.server.GetUserTraffic(c.buildUserTag(&(c.userList)[i]), true)
|
||||||
if up > 0 || down > 0 {
|
if up > 0 || down > 0 {
|
||||||
if c.EnableDynamicSpeedLimit {
|
if c.LimitConfig.EnableDynamicSpeedLimit {
|
||||||
c.userList[i].Traffic += up + down
|
c.userList[i].Traffic += up + down
|
||||||
}
|
}
|
||||||
userTraffic = append(userTraffic, panel.UserTraffic{
|
userTraffic = append(userTraffic, panel.UserTraffic{
|
||||||
|
Loading…
Reference in New Issue
Block a user