V2bX/core/app/dispatcher/limiter.go

288 lines
7.5 KiB
Go
Raw Normal View History

package dispatcher
2022-06-01 13:35:41 -04:00
import (
"fmt"
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/juju/ratelimit"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"io"
2022-06-01 13:35:41 -04:00
"sync"
"time"
)
2022-09-12 22:39:53 -04:00
type UserLimitInfo struct {
UID int
SpeedLimit uint64
ExpireTime int64
//DeviceLimit int
2022-06-01 13:35:41 -04:00
}
type InboundInfo struct {
2022-09-12 22:39:53 -04:00
Tag string
NodeSpeedLimit uint64
NodeDeviceLimit int
UserLimitInfo *sync.Map // Key: Uid value: UserLimitInfo
SpeedLimiter *sync.Map // key: Uid, value: *ratelimit.Bucket
UserOnlineIP *sync.Map // Key: Uid Value: *sync.Map: Key: IP, Value: bool
2022-06-01 13:35:41 -04:00
}
type Limiter struct {
InboundInfo *sync.Map // Key: Tag, Value: *InboundInfo
}
func NewLimiter() *Limiter {
2022-06-01 13:35:41 -04:00
return &Limiter{
InboundInfo: new(sync.Map),
}
}
2022-09-12 22:39:53 -04:00
func (l *Limiter) AddInboundLimiter(tag string, nodeInfo *panel.NodeInfo) error {
2022-06-01 13:35:41 -04:00
inboundInfo := &InboundInfo{
2022-09-12 22:39:53 -04:00
Tag: tag,
NodeSpeedLimit: nodeInfo.SpeedLimit,
NodeDeviceLimit: nodeInfo.DeviceLimit,
SpeedLimiter: new(sync.Map),
UserOnlineIP: new(sync.Map),
2022-06-01 13:35:41 -04:00
}
2022-09-12 22:39:53 -04:00
inboundInfo.UserLimitInfo = new(sync.Map)
2022-06-01 13:35:41 -04:00
l.InboundInfo.Store(tag, inboundInfo) // Replace the old inbound info
return nil
}
2022-09-12 22:39:53 -04:00
func (l *Limiter) UpdateInboundLimiter(tag string, deleted []panel.UserInfo) error {
2022-06-01 13:35:41 -04:00
if value, ok := l.InboundInfo.Load(tag); ok {
inboundInfo := value.(*InboundInfo)
for i := range deleted {
2022-09-12 22:39:53 -04:00
inboundInfo.UserLimitInfo.Delete(fmt.Sprintf("%s|%s|%d", tag,
(deleted)[i].V2rayUser.Email, (deleted)[i].UID))
2022-09-05 20:28:57 -04:00
inboundInfo.SpeedLimiter.Delete(fmt.Sprintf("%s|%s|%d", tag,
(deleted)[i].V2rayUser.Email, (deleted)[i].UID)) // Delete limiter bucket
2022-06-01 13:35:41 -04:00
}
} else {
return fmt.Errorf("no such inbound in limiter: %s", tag)
}
return nil
}
func (l *Limiter) DeleteInboundLimiter(tag string) error {
l.InboundInfo.Delete(tag)
return nil
}
2022-09-12 22:39:53 -04:00
func (l *Limiter) AddUserSpeedLimit(tag string, userInfo *panel.UserInfo, limit uint64, expire int64) error {
if value, ok := l.InboundInfo.Load(tag); ok {
inboundInfo := value.(*InboundInfo)
2022-09-12 22:39:53 -04:00
userLimit := &UserLimitInfo{
SpeedLimit: limit,
ExpireTime: time.Now().Add(time.Duration(expire) * time.Second).Unix(),
}
2022-09-12 22:39:53 -04:00
inboundInfo.UserLimitInfo.Store(fmt.Sprintf("%s|%s|%d", tag, userInfo.GetUserEmail(), userInfo.UID), userLimit)
return nil
} else {
return fmt.Errorf("no such inbound in limiter: %s", tag)
}
}
2022-09-05 20:28:57 -04:00
type UserIpList struct {
Uid int `json:"Uid"`
IpList []string `json:"Ips"`
}
2022-09-05 20:28:57 -04:00
func (l *Limiter) ListOnlineUserIp(tag string) ([]UserIpList, error) {
2022-06-01 13:35:41 -04:00
if value, ok := l.InboundInfo.Load(tag); ok {
inboundInfo := value.(*InboundInfo)
2022-09-05 20:28:57 -04:00
onlineUser := make([]UserIpList, 0)
var ipMap *sync.Map
2022-06-01 13:35:41 -04:00
inboundInfo.UserOnlineIP.Range(func(key, value interface{}) bool {
ipMap = value.(*sync.Map)
var ip []string
ipMap.Range(func(key, v interface{}) bool {
if v.(bool) {
ip = append(ip, key.(string))
}
2022-06-01 13:35:41 -04:00
return true
})
if len(ip) > 0 {
2022-09-12 22:39:53 -04:00
if u, ok := inboundInfo.UserLimitInfo.Load(key.(string)); ok {
2022-09-05 20:28:57 -04:00
onlineUser = append(onlineUser, UserIpList{
2022-09-12 22:39:53 -04:00
Uid: u.(*UserLimitInfo).UID,
2022-09-05 20:28:57 -04:00
IpList: ip,
})
}
}
2022-06-01 13:35:41 -04:00
return true
})
if len(onlineUser) == 0 {
return nil, nil
}
return onlineUser, nil
2022-06-01 13:35:41 -04:00
} else {
return nil, fmt.Errorf("no such inbound in limiter: %s", tag)
}
}
2022-09-05 20:28:57 -04:00
func (l *Limiter) UpdateOnlineUserIP(tag string, userIpList []UserIpList) {
if v, ok := l.InboundInfo.Load(tag); ok {
inboundInfo := v.(*InboundInfo)
//Clear old IP
inboundInfo.UserOnlineIP.Range(func(key, value interface{}) bool {
inboundInfo.UserOnlineIP.Delete(key)
return true
})
// Update User Online IP
for i := range userIpList {
ipMap := new(sync.Map)
2022-09-05 20:28:57 -04:00
for _, userIp := range (userIpList)[i].IpList {
ipMap.Store(userIp, false)
}
inboundInfo.UserOnlineIP.Store((userIpList)[i].Uid, ipMap)
}
2022-09-05 20:28:57 -04:00
inboundInfo.SpeedLimiter.Range(func(key, value interface{}) bool {
if _, exists := inboundInfo.UserOnlineIP.Load(key.(string)); !exists {
inboundInfo.SpeedLimiter.Delete(key.(string))
}
return true
})
}
}
2022-09-05 20:28:57 -04:00
func (l *Limiter) ClearOnlineUserIpAndSpeedLimiter(tag string) {
if v, ok := l.InboundInfo.Load(tag); ok {
inboundInfo := v.(*InboundInfo)
2022-09-05 20:28:57 -04:00
inboundInfo.SpeedLimiter.Range(func(key, value interface{}) bool {
if _, exists := inboundInfo.UserOnlineIP.Load(key.(string)); !exists {
inboundInfo.SpeedLimiter.Delete(key.(string))
}
return true
})
inboundInfo.UserOnlineIP.Range(func(key, value interface{}) bool {
inboundInfo.UserOnlineIP.Delete(key)
return true
})
}
2022-06-01 13:35:41 -04:00
}
2022-09-05 20:28:57 -04:00
func (l *Limiter) CheckSpeedAndDeviceLimit(tag string, email string, ip string) (speedLimiter *ratelimit.Bucket, SpeedLimit bool, Reject bool) {
2022-06-01 13:35:41 -04:00
if value, ok := l.InboundInfo.Load(tag); ok {
inboundInfo := value.(*InboundInfo)
nodeLimit := inboundInfo.NodeSpeedLimit
var userLimit uint64 = 0
expired := false
2022-09-12 22:39:53 -04:00
if v, ok := inboundInfo.UserLimitInfo.Load(email); ok {
u := v.(*UserLimitInfo)
if u.ExpireTime < time.Now().Unix() && u.ExpireTime != 0 {
userLimit = 0
expired = true
} else {
userLimit = u.SpeedLimit
}
2022-06-01 13:35:41 -04:00
}
ipMap := new(sync.Map)
ipMap.Store(ip, true)
2022-06-01 13:35:41 -04:00
// If any device is online
if v, ok := inboundInfo.UserOnlineIP.LoadOrStore(email, ipMap); ok {
ipMap := v.(*sync.Map)
// If this ip is a new device
if online, ok := ipMap.LoadOrStore(ip, true); !ok {
2022-06-01 13:35:41 -04:00
counter := 0
ipMap.Range(func(key, value interface{}) bool {
counter++
return true
})
2022-09-12 22:39:53 -04:00
if counter > inboundInfo.NodeDeviceLimit && inboundInfo.NodeDeviceLimit > 0 {
2022-06-01 13:35:41 -04:00
ipMap.Delete(ip)
return nil, false, true
}
} else {
if !online.(bool) {
ipMap.Store(ip, true)
}
2022-06-01 13:35:41 -04:00
}
}
2022-09-12 22:39:53 -04:00
limit := determineSpeedLimit(nodeLimit, userLimit) // If you need the Speed limit
2022-06-01 13:35:41 -04:00
if limit > 0 {
2022-06-02 13:22:56 -04:00
limiter := ratelimit.NewBucketWithQuantum(time.Second, int64(limit), int64(limit)) // Byte/s
2022-09-05 20:28:57 -04:00
if v, ok := inboundInfo.SpeedLimiter.LoadOrStore(email, limiter); ok {
if expired {
inboundInfo.SpeedLimiter.Store(email, limiter)
2022-09-12 22:39:53 -04:00
inboundInfo.UserLimitInfo.Delete(email)
return limiter, true, false
}
2022-06-01 13:35:41 -04:00
bucket := v.(*ratelimit.Bucket)
return bucket, true, false
} else {
return limiter, true, false
}
} else {
return nil, false, false
}
} else {
newError("Get Inbound Limiter information failed").AtDebug().WriteToLog()
return nil, false, false
}
}
type Writer struct {
writer buf.Writer
limiter *ratelimit.Bucket
w io.Writer
}
func (l *Limiter) RateWriter(writer buf.Writer, limiter *ratelimit.Bucket) buf.Writer {
return &Writer{
writer: writer,
limiter: limiter,
}
}
func (w *Writer) Close() error {
return common.Close(w.writer)
}
func (w *Writer) WriteMultiBuffer(mb buf.MultiBuffer) error {
w.limiter.Wait(int64(mb.Len()))
return w.writer.WriteMultiBuffer(mb)
}
2022-09-12 22:39:53 -04:00
// determineSpeedLimit returns the minimum non-zero rate
func determineSpeedLimit(nodeLimit, userLimit uint64) (limit uint64) {
if nodeLimit == 0 || userLimit == 0 {
if nodeLimit > userLimit {
return nodeLimit
} else if nodeLimit < userLimit {
return userLimit
} else {
return 0
}
} else {
if nodeLimit > userLimit {
return userLimit
} else if nodeLimit < userLimit {
return nodeLimit
} else {
return nodeLimit
}
}
}
func determineDeviceLimit(nodeLimit, userLimit int) (limit int) {
2022-06-01 13:35:41 -04:00
if nodeLimit == 0 || userLimit == 0 {
if nodeLimit > userLimit {
return nodeLimit
} else if nodeLimit < userLimit {
return userLimit
} else {
return 0
}
} else {
if nodeLimit > userLimit {
return userLimit
} else if nodeLimit < userLimit {
return nodeLimit
} else {
return nodeLimit
}
}
}