mirror of
https://github.com/wyx2685/V2bX.git
synced 2025-01-22 18:08:14 -05:00
add dynamic speed limit
fix old user limit info not clear fix some wrong names
This commit is contained in:
parent
52134c6e4e
commit
5fd09079e3
@ -1,78 +0,0 @@
|
|||||||
// Package api contains all the api used by XrayR
|
|
||||||
// To implement an api , one needs to implement the interface below.
|
|
||||||
|
|
||||||
package panel
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/Yuzuki616/V2bX/conf"
|
|
||||||
"github.com/go-resty/resty/v2"
|
|
||||||
"log"
|
|
||||||
"strconv"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Panel is the interface for different panel's api.
|
|
||||||
|
|
||||||
type ClientInfo struct {
|
|
||||||
APIHost string
|
|
||||||
NodeID int
|
|
||||||
Key string
|
|
||||||
NodeType string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Client struct {
|
|
||||||
client *resty.Client
|
|
||||||
APIHost string
|
|
||||||
NodeID int
|
|
||||||
Key string
|
|
||||||
NodeType string
|
|
||||||
//EnableSS2022 bool
|
|
||||||
EnableVless bool
|
|
||||||
EnableXTLS bool
|
|
||||||
SpeedLimit float64
|
|
||||||
DeviceLimit int
|
|
||||||
LocalRuleList []DetectRule
|
|
||||||
RemoteRuleCache *[]Rule
|
|
||||||
access sync.Mutex
|
|
||||||
NodeInfoRspMd5 [16]byte
|
|
||||||
NodeRuleRspMd5 [16]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(apiConfig *conf.ApiConfig) Panel {
|
|
||||||
client := resty.New()
|
|
||||||
client.SetRetryCount(3)
|
|
||||||
if apiConfig.Timeout > 0 {
|
|
||||||
client.SetTimeout(time.Duration(apiConfig.Timeout) * time.Second)
|
|
||||||
} else {
|
|
||||||
client.SetTimeout(5 * time.Second)
|
|
||||||
}
|
|
||||||
client.OnError(func(req *resty.Request, err error) {
|
|
||||||
if v, ok := err.(*resty.ResponseError); ok {
|
|
||||||
// v.Response contains the last response from the server
|
|
||||||
// v.Err contains the original error
|
|
||||||
log.Print(v.Err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
client.SetBaseURL(apiConfig.APIHost)
|
|
||||||
// Create Key for each requests
|
|
||||||
client.SetQueryParams(map[string]string{
|
|
||||||
"node_id": strconv.Itoa(apiConfig.NodeID),
|
|
||||||
"token": apiConfig.Key,
|
|
||||||
})
|
|
||||||
// Read local rule list
|
|
||||||
localRuleList := readLocalRuleList(apiConfig.RuleListPath)
|
|
||||||
return &Client{
|
|
||||||
client: client,
|
|
||||||
NodeID: apiConfig.NodeID,
|
|
||||||
Key: apiConfig.Key,
|
|
||||||
APIHost: apiConfig.APIHost,
|
|
||||||
NodeType: apiConfig.NodeType,
|
|
||||||
//EnableSS2022: apiConfig.EnableSS2022,
|
|
||||||
EnableVless: apiConfig.EnableVless,
|
|
||||||
EnableXTLS: apiConfig.EnableXTLS,
|
|
||||||
SpeedLimit: apiConfig.SpeedLimit,
|
|
||||||
DeviceLimit: apiConfig.DeviceLimit,
|
|
||||||
LocalRuleList: localRuleList,
|
|
||||||
}
|
|
||||||
}
|
|
10
api/panel/interface.go
Normal file
10
api/panel/interface.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package panel
|
||||||
|
|
||||||
|
type Panel interface {
|
||||||
|
GetNodeInfo() (nodeInfo *NodeInfo, err error)
|
||||||
|
GetUserList() (userList []UserInfo, err error)
|
||||||
|
ReportUserTraffic(userTraffic []UserTraffic) (err error)
|
||||||
|
Describe() ClientInfo
|
||||||
|
GetNodeRule() (ruleList []DetectRule, protocolList []string, err error)
|
||||||
|
Debug()
|
||||||
|
}
|
@ -1,10 +1,75 @@
|
|||||||
package panel
|
package panel
|
||||||
|
|
||||||
type Panel interface {
|
import (
|
||||||
GetNodeInfo() (nodeInfo *NodeInfo, err error)
|
"github.com/Yuzuki616/V2bX/conf"
|
||||||
GetUserList() (userList []UserInfo, err error)
|
"github.com/go-resty/resty/v2"
|
||||||
ReportUserTraffic(userTraffic []UserTraffic) (err error)
|
"log"
|
||||||
Describe() ClientInfo
|
"strconv"
|
||||||
GetNodeRule() (ruleList []DetectRule, protocolList []string, err error)
|
"sync"
|
||||||
Debug()
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Panel is the interface for different panel's api.
|
||||||
|
|
||||||
|
type ClientInfo struct {
|
||||||
|
APIHost string
|
||||||
|
NodeID int
|
||||||
|
Key string
|
||||||
|
NodeType string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
client *resty.Client
|
||||||
|
APIHost string
|
||||||
|
NodeID int
|
||||||
|
Key string
|
||||||
|
NodeType string
|
||||||
|
//EnableSS2022 bool
|
||||||
|
EnableVless bool
|
||||||
|
EnableXTLS bool
|
||||||
|
SpeedLimit float64
|
||||||
|
DeviceLimit int
|
||||||
|
LocalRuleList []DetectRule
|
||||||
|
RemoteRuleCache *[]Rule
|
||||||
|
access sync.Mutex
|
||||||
|
NodeInfoRspMd5 [16]byte
|
||||||
|
NodeRuleRspMd5 [16]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(apiConfig *conf.ApiConfig) Panel {
|
||||||
|
client := resty.New()
|
||||||
|
client.SetRetryCount(3)
|
||||||
|
if apiConfig.Timeout > 0 {
|
||||||
|
client.SetTimeout(time.Duration(apiConfig.Timeout) * time.Second)
|
||||||
|
} else {
|
||||||
|
client.SetTimeout(5 * time.Second)
|
||||||
|
}
|
||||||
|
client.OnError(func(req *resty.Request, err error) {
|
||||||
|
if v, ok := err.(*resty.ResponseError); ok {
|
||||||
|
// v.Response contains the last response from the server
|
||||||
|
// v.Err contains the original error
|
||||||
|
log.Print(v.Err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
client.SetBaseURL(apiConfig.APIHost)
|
||||||
|
// Create Key for each requests
|
||||||
|
client.SetQueryParams(map[string]string{
|
||||||
|
"node_id": strconv.Itoa(apiConfig.NodeID),
|
||||||
|
"token": apiConfig.Key,
|
||||||
|
})
|
||||||
|
// Read local rule list
|
||||||
|
localRuleList := readLocalRuleList(apiConfig.RuleListPath)
|
||||||
|
return &Client{
|
||||||
|
client: client,
|
||||||
|
NodeID: apiConfig.NodeID,
|
||||||
|
Key: apiConfig.Key,
|
||||||
|
APIHost: apiConfig.APIHost,
|
||||||
|
NodeType: apiConfig.NodeType,
|
||||||
|
//EnableSS2022: apiConfig.EnableSS2022,
|
||||||
|
EnableVless: apiConfig.EnableVless,
|
||||||
|
EnableXTLS: apiConfig.EnableXTLS,
|
||||||
|
SpeedLimit: apiConfig.SpeedLimit,
|
||||||
|
DeviceLimit: apiConfig.DeviceLimit,
|
||||||
|
LocalRuleList: localRuleList,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ type UserInfo struct {
|
|||||||
/*DeviceLimit int `json:"device_limit"`
|
/*DeviceLimit int `json:"device_limit"`
|
||||||
SpeedLimit uint64 `json:"speed_limit"`*/
|
SpeedLimit uint64 `json:"speed_limit"`*/
|
||||||
UID int `json:"id"`
|
UID int `json:"id"`
|
||||||
|
Traffic int64 `json:"-"`
|
||||||
Port int `json:"port"`
|
Port int `json:"port"`
|
||||||
Cipher string `json:"cipher"`
|
Cipher string `json:"cipher"`
|
||||||
Secret string `json:"secret"`
|
Secret string `json:"secret"`
|
||||||
|
@ -27,6 +27,13 @@ type IpReportConfig struct {
|
|||||||
EnableIpSync bool `mapstructure:"EnableIpSync"`
|
EnableIpSync bool `mapstructure:"EnableIpSync"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DynamicSpeedLimitConfig struct {
|
||||||
|
Periodic int `mapstructure:"Periodic"`
|
||||||
|
Traffic int64 `mapstructure:"Traffic"`
|
||||||
|
SpeedLimit uint64 `mapstructure:"SpeedLimit"`
|
||||||
|
ExpireTime int `mapstructure:"ExpireTime"`
|
||||||
|
}
|
||||||
|
|
||||||
type ControllerConfig struct {
|
type ControllerConfig struct {
|
||||||
ListenIP string `mapstructure:"ListenIP"`
|
ListenIP string `mapstructure:"ListenIP"`
|
||||||
SendIP string `mapstructure:"SendIP"`
|
SendIP string `mapstructure:"SendIP"`
|
||||||
@ -42,6 +49,8 @@ type ControllerConfig struct {
|
|||||||
FallBackConfigs []*FallBackConfig `mapstructure:"FallBackConfigs"`
|
FallBackConfigs []*FallBackConfig `mapstructure:"FallBackConfigs"`
|
||||||
EnableIpRecorder bool `mapstructure:"EnableIpRecorder"`
|
EnableIpRecorder bool `mapstructure:"EnableIpRecorder"`
|
||||||
IpRecorderConfig *IpReportConfig `mapstructure:"IpRecorderConfig"`
|
IpRecorderConfig *IpReportConfig `mapstructure:"IpRecorderConfig"`
|
||||||
|
EnableDynamicSpeedLimit bool `mapstructure:"EnableDynamicSpeedLimit"`
|
||||||
|
DynamicSpeedLimitConfig *DynamicSpeedLimitConfig `mapstructure:"DynamicSpeedLimitConfig"`
|
||||||
CertConfig *CertConfig `mapstructure:"CertConfig"`
|
CertConfig *CertConfig `mapstructure:"CertConfig"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
type UserInfo struct {
|
type UserInfo struct {
|
||||||
UID int
|
UID int
|
||||||
SpeedLimit uint64
|
SpeedLimit uint64
|
||||||
|
ExpireTime int64
|
||||||
DeviceLimit int
|
DeviceLimit int
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +52,7 @@ func (l *Limiter) AddInboundLimiter(tag string, nodeInfo *panel.NodeInfo, userLi
|
|||||||
(*userList)[i].DeviceLimit = nodeInfo.DeviceLimit
|
(*userList)[i].DeviceLimit = nodeInfo.DeviceLimit
|
||||||
}*/
|
}*/
|
||||||
userMap.Store(fmt.Sprintf("%s|%s|%d", tag, (userList)[i].V2rayUser.Email, (userList)[i].UID),
|
userMap.Store(fmt.Sprintf("%s|%s|%d", tag, (userList)[i].V2rayUser.Email, (userList)[i].UID),
|
||||||
UserInfo{
|
&UserInfo{
|
||||||
UID: (userList)[i].UID,
|
UID: (userList)[i].UID,
|
||||||
SpeedLimit: nodeInfo.SpeedLimit,
|
SpeedLimit: nodeInfo.SpeedLimit,
|
||||||
DeviceLimit: nodeInfo.DeviceLimit,
|
DeviceLimit: nodeInfo.DeviceLimit,
|
||||||
@ -62,19 +63,23 @@ func (l *Limiter) AddInboundLimiter(tag string, nodeInfo *panel.NodeInfo, userLi
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Limiter) UpdateInboundLimiter(tag string, nodeInfo *panel.NodeInfo, updatedUserList []panel.UserInfo) error {
|
func (l *Limiter) UpdateInboundLimiter(tag string, nodeInfo *panel.NodeInfo, added, deleted []panel.UserInfo) error {
|
||||||
if value, ok := l.InboundInfo.Load(tag); ok {
|
if value, ok := l.InboundInfo.Load(tag); ok {
|
||||||
inboundInfo := value.(*InboundInfo)
|
inboundInfo := value.(*InboundInfo)
|
||||||
// Update User info
|
// Update User info
|
||||||
for i := range updatedUserList {
|
for i := range added {
|
||||||
inboundInfo.UserInfo.Store(fmt.Sprintf("%s|%s|%d", tag,
|
inboundInfo.UserInfo.Store(fmt.Sprintf("%s|%s|%d", tag,
|
||||||
(updatedUserList)[i].V2rayUser.Email, (updatedUserList)[i].UID), UserInfo{
|
(added)[i].V2rayUser.Email, (added)[i].UID), &UserInfo{
|
||||||
UID: (updatedUserList)[i].UID,
|
UID: (added)[i].UID,
|
||||||
SpeedLimit: nodeInfo.SpeedLimit,
|
SpeedLimit: nodeInfo.SpeedLimit,
|
||||||
DeviceLimit: nodeInfo.DeviceLimit,
|
DeviceLimit: nodeInfo.DeviceLimit,
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
for i := range deleted {
|
||||||
|
inboundInfo.UserInfo.Delete(fmt.Sprintf("%s|%s|%d", tag,
|
||||||
|
(deleted)[i].V2rayUser.Email, (deleted)[i].UID))
|
||||||
inboundInfo.SpeedLimiter.Delete(fmt.Sprintf("%s|%s|%d", tag,
|
inboundInfo.SpeedLimiter.Delete(fmt.Sprintf("%s|%s|%d", tag,
|
||||||
(updatedUserList)[i].V2rayUser.Email, (updatedUserList)[i].UID)) // Delete old limiter bucket
|
(deleted)[i].V2rayUser.Email, (deleted)[i].UID)) // Delete limiter bucket
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("no such inbound in limiter: %s", tag)
|
return fmt.Errorf("no such inbound in limiter: %s", tag)
|
||||||
@ -87,6 +92,22 @@ func (l *Limiter) DeleteInboundLimiter(tag string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *Limiter) UpdateUserSpeedLimit(tag string, userInfo *panel.UserInfo, limit uint64, expire int64) error {
|
||||||
|
if value, ok := l.InboundInfo.Load(tag); ok {
|
||||||
|
inboundInfo := value.(*InboundInfo)
|
||||||
|
if user, ok := inboundInfo.UserInfo.Load(fmt.Sprintf("%s|%s|%d", tag, userInfo.GetUserEmail(), userInfo.UID)); ok {
|
||||||
|
user.(*UserInfo).SpeedLimit = limit
|
||||||
|
user.(*UserInfo).ExpireTime = time.Now().Add(time.Duration(expire) * time.Second).Unix()
|
||||||
|
inboundInfo.SpeedLimiter.Delete(fmt.Sprintf("%s|%s|%d", tag, userInfo.GetUserEmail(), userInfo.UID))
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("no such user in limiter: %s", userInfo.GetUserEmail())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("no such inbound in limiter: %s", tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type UserIpList struct {
|
type UserIpList struct {
|
||||||
Uid int `json:"Uid"`
|
Uid int `json:"Uid"`
|
||||||
IpList []string `json:"Ips"`
|
IpList []string `json:"Ips"`
|
||||||
@ -109,7 +130,7 @@ func (l *Limiter) ListOnlineUserIp(tag string) ([]UserIpList, error) {
|
|||||||
if len(ip) > 0 {
|
if len(ip) > 0 {
|
||||||
if u, ok := inboundInfo.UserInfo.Load(key.(string)); ok {
|
if u, ok := inboundInfo.UserInfo.Load(key.(string)); ok {
|
||||||
onlineUser = append(onlineUser, UserIpList{
|
onlineUser = append(onlineUser, UserIpList{
|
||||||
Uid: u.(UserInfo).UID,
|
Uid: u.(*UserInfo).UID,
|
||||||
IpList: ip,
|
IpList: ip,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -172,9 +193,15 @@ func (l *Limiter) CheckSpeedAndDeviceLimit(tag string, email string, ip string)
|
|||||||
nodeLimit := inboundInfo.NodeSpeedLimit
|
nodeLimit := inboundInfo.NodeSpeedLimit
|
||||||
var userLimit uint64 = 0
|
var userLimit uint64 = 0
|
||||||
var deviceLimit = 0
|
var deviceLimit = 0
|
||||||
|
expired := false
|
||||||
if v, ok := inboundInfo.UserInfo.Load(email); ok {
|
if v, ok := inboundInfo.UserInfo.Load(email); ok {
|
||||||
u := v.(UserInfo)
|
u := v.(*UserInfo)
|
||||||
|
if u.ExpireTime < time.Now().Unix() && u.ExpireTime != 0 {
|
||||||
|
userLimit = 0
|
||||||
|
expired = true
|
||||||
|
} else {
|
||||||
userLimit = u.SpeedLimit
|
userLimit = u.SpeedLimit
|
||||||
|
}
|
||||||
deviceLimit = u.DeviceLimit
|
deviceLimit = u.DeviceLimit
|
||||||
}
|
}
|
||||||
ipMap := new(sync.Map)
|
ipMap := new(sync.Map)
|
||||||
@ -203,6 +230,10 @@ func (l *Limiter) CheckSpeedAndDeviceLimit(tag string, email string, ip string)
|
|||||||
if limit > 0 {
|
if limit > 0 {
|
||||||
limiter := ratelimit.NewBucketWithQuantum(time.Second, int64(limit), int64(limit)) // Byte/s
|
limiter := ratelimit.NewBucketWithQuantum(time.Second, int64(limit), int64(limit)) // Byte/s
|
||||||
if v, ok := inboundInfo.SpeedLimiter.LoadOrStore(email, limiter); ok {
|
if v, ok := inboundInfo.SpeedLimiter.LoadOrStore(email, limiter); ok {
|
||||||
|
if expired {
|
||||||
|
inboundInfo.SpeedLimiter.Store(email, limiter)
|
||||||
|
return limiter, true, false
|
||||||
|
}
|
||||||
bucket := v.(*ratelimit.Bucket)
|
bucket := v.(*ratelimit.Bucket)
|
||||||
return bucket, true, false
|
return bucket, true, false
|
||||||
} else {
|
} else {
|
||||||
|
@ -10,8 +10,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (p *Core) RemoveInbound(tag string) error {
|
func (p *Core) RemoveInbound(tag string) error {
|
||||||
err := p.ihm.RemoveHandler(context.Background(), tag)
|
return p.ihm.RemoveHandler(context.Background(), tag)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Core) AddInbound(config *core.InboundHandlerConfig) error {
|
func (p *Core) AddInbound(config *core.InboundHandlerConfig) error {
|
||||||
@ -30,8 +29,7 @@ func (p *Core) AddInbound(config *core.InboundHandlerConfig) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *Core) AddInboundLimiter(tag string, nodeInfo *panel.NodeInfo, userList []panel.UserInfo) error {
|
func (p *Core) AddInboundLimiter(tag string, nodeInfo *panel.NodeInfo, userList []panel.UserInfo) error {
|
||||||
err := p.dispatcher.Limiter.AddInboundLimiter(tag, nodeInfo, userList)
|
return p.dispatcher.Limiter.AddInboundLimiter(tag, nodeInfo, userList)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Core) GetInboundLimiter(tag string) (*dispatcher.InboundInfo, error) {
|
func (p *Core) GetInboundLimiter(tag string) (*dispatcher.InboundInfo, error) {
|
||||||
@ -42,12 +40,10 @@ func (p *Core) GetInboundLimiter(tag string) (*dispatcher.InboundInfo, error) {
|
|||||||
return nil, fmt.Errorf("not found limiter")
|
return nil, fmt.Errorf("not found limiter")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Core) UpdateInboundLimiter(tag string, nodeInfo *panel.NodeInfo, updatedUserList []panel.UserInfo) error {
|
func (p *Core) UpdateInboundLimiter(tag string, nodeInfo *panel.NodeInfo, added, deleted []panel.UserInfo) error {
|
||||||
err := p.dispatcher.Limiter.UpdateInboundLimiter(tag, nodeInfo, updatedUserList)
|
return p.dispatcher.Limiter.UpdateInboundLimiter(tag, nodeInfo, added, deleted)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Core) DeleteInboundLimiter(tag string) error {
|
func (p *Core) DeleteInboundLimiter(tag string) error {
|
||||||
err := p.dispatcher.Limiter.DeleteInboundLimiter(tag)
|
return p.dispatcher.Limiter.DeleteInboundLimiter(tag)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package core
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/Yuzuki616/V2bX/api/panel"
|
||||||
"github.com/Yuzuki616/V2bX/core/app/dispatcher"
|
"github.com/Yuzuki616/V2bX/core/app/dispatcher"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/proxy"
|
"github.com/xtls/xray-core/proxy"
|
||||||
@ -79,6 +80,10 @@ func (p *Core) GetUserTraffic(email string, reset bool) (up int64, down int64) {
|
|||||||
return up, down
|
return up, down
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Core) UpdateUserSpeedLimit(tag string, user *panel.UserInfo, speedLimit uint64, expire int64) error {
|
||||||
|
return p.dispatcher.Limiter.UpdateUserSpeedLimit(tag, user, speedLimit, expire)
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Core) ListOnlineIp(tag string) ([]dispatcher.UserIpList, error) {
|
func (p *Core) ListOnlineIp(tag string) ([]dispatcher.UserIpList, error) {
|
||||||
return p.dispatcher.Limiter.ListOnlineUserIp(tag)
|
return p.dispatcher.Limiter.ListOnlineUserIp(tag)
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,12 @@ Nodes:
|
|||||||
Periodic: 60 # Report interval, sec.
|
Periodic: 60 # Report interval, sec.
|
||||||
Timeout: 10 # Report timeout, sec.
|
Timeout: 10 # Report timeout, sec.
|
||||||
EnableIpSync: false # Enable online ip sync
|
EnableIpSync: false # Enable online ip sync
|
||||||
|
EnableDynamicSpeedLimit: false # Enable dynamic speed limit
|
||||||
|
DynamicSpeedLimitConfig:
|
||||||
|
Periodic: 60 # Time to check the user traffic , sec.
|
||||||
|
Traffic: 0 # Traffic limit, MB
|
||||||
|
SpeedLimit: 0 # Speed limit, Mbps
|
||||||
|
ExpireTime: 0 # Time limit, sec.
|
||||||
CertConfig:
|
CertConfig:
|
||||||
CertMode: dns # Option about how to get certificate: none, file, http, dns. Choose "none" will forcedly disable the tls config.
|
CertMode: dns # Option about how to get certificate: none, file, http, dns. Choose "none" will forcedly disable the tls config.
|
||||||
CertDomain: "node1.test.com" # Domain to cert
|
CertDomain: "node1.test.com" # Domain to cert
|
||||||
|
40
node/node.go
40
node/node.go
@ -29,6 +29,7 @@ type Node struct {
|
|||||||
nodeInfoMonitorPeriodic *task.Periodic
|
nodeInfoMonitorPeriodic *task.Periodic
|
||||||
userReportPeriodic *task.Periodic
|
userReportPeriodic *task.Periodic
|
||||||
onlineIpReportPeriodic *task.Periodic
|
onlineIpReportPeriodic *task.Periodic
|
||||||
|
DynamicSpeedLimitPeriodic *task.Periodic
|
||||||
}
|
}
|
||||||
|
|
||||||
// New return a Node service with default parameters.
|
// New return a Node service with default parameters.
|
||||||
@ -113,11 +114,22 @@ func (c *Node) Start() error {
|
|||||||
Execute: c.onlineIpReport,
|
Execute: c.onlineIpReport,
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
time.Sleep(time.Duration(c.config.UpdatePeriodic) * time.Second)
|
time.Sleep(time.Duration(c.config.IpRecorderConfig.Periodic) * time.Second)
|
||||||
_ = c.onlineIpReportPeriodic.Start()
|
_ = c.onlineIpReportPeriodic.Start()
|
||||||
}()
|
}()
|
||||||
log.Printf("[%s: %d] Start report online ip", c.nodeInfo.NodeType, c.nodeInfo.NodeId)
|
log.Printf("[%s: %d] Start report online ip", c.nodeInfo.NodeType, c.nodeInfo.NodeId)
|
||||||
}
|
}
|
||||||
|
if c.config.EnableDynamicSpeedLimit {
|
||||||
|
c.DynamicSpeedLimitPeriodic = &task.Periodic{
|
||||||
|
Interval: time.Duration(c.config.DynamicSpeedLimitConfig.Periodic) * time.Second,
|
||||||
|
Execute: c.DynamicSpeedLimit,
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
time.Sleep(time.Duration(c.config.DynamicSpeedLimitConfig.Periodic) * time.Second)
|
||||||
|
_ = c.DynamicSpeedLimitPeriodic.Start()
|
||||||
|
}()
|
||||||
|
log.Printf("[%s: %d] Start dynamic speed limit", c.nodeInfo.NodeType, c.nodeInfo.NodeId)
|
||||||
|
}
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -252,8 +264,10 @@ func (c *Node) nodeInfoMonitor() (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if len(added) > 0 || len(deleted) > 0 {
|
||||||
// Update Limiter
|
// Update Limiter
|
||||||
if err := c.server.UpdateInboundLimiter(c.Tag, c.nodeInfo, added); err != nil {
|
if err := c.server.UpdateInboundLimiter(c.Tag, c.nodeInfo, added, deleted); err != nil {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -365,6 +379,9 @@ func (c *Node) userInfoMonitor() (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.config.EnableDynamicSpeedLimit {
|
||||||
|
c.userList[i].Traffic += up + down
|
||||||
|
}
|
||||||
userTraffic = append(userTraffic, panel.UserTraffic{
|
userTraffic = append(userTraffic, panel.UserTraffic{
|
||||||
UID: (c.userList)[i].UID,
|
UID: (c.userList)[i].UID,
|
||||||
Upload: up,
|
Upload: up,
|
||||||
@ -423,6 +440,25 @@ func (c *Node) onlineIpReport() (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Node) DynamicSpeedLimit() error {
|
||||||
|
if c.config.EnableDynamicSpeedLimit {
|
||||||
|
for i := range c.userList {
|
||||||
|
up, down := c.server.GetUserTraffic(c.buildUserTag(&(c.userList)[i]), false)
|
||||||
|
if c.userList[i].Traffic+down+up/1024/1024 > c.config.DynamicSpeedLimitConfig.Traffic {
|
||||||
|
err := c.server.UpdateUserSpeedLimit(c.Tag,
|
||||||
|
&c.userList[i],
|
||||||
|
c.config.DynamicSpeedLimitConfig.SpeedLimit,
|
||||||
|
time.Now().Add(time.Second*time.Duration(c.config.DynamicSpeedLimitConfig.ExpireTime)).Unix())
|
||||||
|
if err != nil {
|
||||||
|
log.Print(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.userList[i].Traffic = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Node) buildNodeTag() string {
|
func (c *Node) buildNodeTag() string {
|
||||||
return fmt.Sprintf("%s_%s_%d", c.nodeInfo.NodeType, c.config.ListenIP, c.nodeInfo.NodeId)
|
return fmt.Sprintf("%s_%s_%d", c.nodeInfo.NodeType, c.config.ListenIP, c.nodeInfo.NodeId)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user