refactor limiter
fix getLink bug
add connection limit
move limit config to ControllerConfig
del dynamic speed limit (next version will be re add)
del online ip sync (next version will be re add)
This commit is contained in:
yuzuki999
2023-05-16 09:15:29 +08:00
parent 2d7aaef066
commit 15c36a9580
35 changed files with 564 additions and 617 deletions

View File

@@ -1,4 +1,4 @@
package controller
package node
import (
"errors"
@@ -7,11 +7,12 @@ import (
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/conf"
"github.com/Yuzuki616/V2bX/core"
"github.com/Yuzuki616/V2bX/limiter"
"github.com/xtls/xray-core/common/task"
"log"
)
type Node struct {
type Controller struct {
server *core.Core
clientInfo panel.ClientInfo
apiClient panel.Panel
@@ -27,9 +28,9 @@ type Node struct {
*conf.ControllerConfig
}
// New return a Node service with default parameters.
func New(server *core.Core, api panel.Panel, config *conf.ControllerConfig) *Node {
controller := &Node{
// NewController return a Node controller with default parameters.
func NewController(server *core.Core, api panel.Panel, config *conf.ControllerConfig) *Controller {
controller := &Controller{
server: server,
ControllerConfig: config,
apiClient: api,
@@ -38,7 +39,7 @@ func New(server *core.Core, api panel.Panel, config *conf.ControllerConfig) *Nod
}
// Start implement the Start() function of the service interface
func (c *Node) Start() error {
func (c *Controller) Start() error {
c.clientInfo = c.apiClient.Describe()
// First fetch Node Info
var err error
@@ -46,12 +47,6 @@ func (c *Node) Start() error {
if err != nil {
return fmt.Errorf("get node info failed: %s", err)
}
c.Tag = c.buildNodeTag()
// Add new tag
err = c.addNewTag(c.nodeInfo)
if err != nil {
return fmt.Errorf("add new tag failed: %s", err)
}
// Update user
c.userList, err = c.apiClient.GetUserList()
if err != nil {
@@ -60,25 +55,36 @@ func (c *Node) Start() error {
if len(c.userList) == 0 {
return errors.New("add users failed: not have any user")
}
c.Tag = c.buildNodeTag()
// add limiter
l := limiter.AddLimiter(c.Tag, &limiter.LimitConfig{
SpeedLimit: c.SpeedLimit,
IpLimit: c.IPLimit,
ConnLimit: c.ConnLimit,
}, c.userList)
// add rule limiter
if !c.DisableGetRule {
if err = l.UpdateRule(c.nodeInfo.Rules); err != nil {
log.Printf("Update rule filed: %s", err)
}
}
// Add new tag
err = c.addNewNode(c.nodeInfo)
if err != nil {
return fmt.Errorf("add new tag failed: %s", err)
}
err = c.addNewUser(c.userList, c.nodeInfo)
if err != nil {
return err
}
if err := c.server.AddInboundLimiter(c.Tag, c.nodeInfo, c.userList); err != nil {
return fmt.Errorf("add inbound limiter failed: %s", err)
}
// Add Rule Manager
if !c.DisableGetRule {
if err := c.server.UpdateRule(c.Tag, c.nodeInfo.Rules); err != nil {
log.Printf("Update rule filed: %s", err)
}
}
c.initTask()
return nil
}
// Close implement the Close() function of the service interface
func (c *Node) Close() error {
func (c *Controller) Close() error {
limiter.DeleteLimiter(c.Tag)
if c.nodeInfoMonitorPeriodic != nil {
err := c.nodeInfoMonitorPeriodic.Close()
if err != nil {
@@ -112,6 +118,6 @@ func (c *Node) Close() error {
return nil
}
func (c *Node) buildNodeTag() string {
func (c *Controller) buildNodeTag() string {
return fmt.Sprintf("%s_%s_%d", c.nodeInfo.NodeType, c.ListenIP, c.nodeInfo.NodeId)
}

View File

@@ -1,4 +1,4 @@
package controller_test
package node_test
import (
"fmt"
@@ -6,7 +6,7 @@ import (
"github.com/Yuzuki616/V2bX/conf"
"github.com/Yuzuki616/V2bX/core"
_ "github.com/Yuzuki616/V2bX/core/distro/all"
. "github.com/Yuzuki616/V2bX/node/controller"
. "github.com/Yuzuki616/V2bX/node"
xCore "github.com/xtls/xray-core/core"
coreConf "github.com/xtls/xray-core/infra/conf"
"os"

View File

@@ -1,4 +1,4 @@
package controller
package node
import (
"crypto/rand"
@@ -8,7 +8,7 @@ import (
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/common/file"
"github.com/Yuzuki616/V2bX/conf"
"github.com/Yuzuki616/V2bX/node/controller/lego"
"github.com/Yuzuki616/V2bX/node/lego"
"github.com/goccy/go-json"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/core"
@@ -65,7 +65,7 @@ func buildInbound(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, tag s
AcceptProxyProtocol: config.EnableProxyProtocol} //Enable proxy protocol
}
// Set TLS and XTLS settings
if nodeInfo.EnableTls && config.CertConfig.CertMode != "none" {
if config.EnableTls && config.CertConfig.CertMode != "none" {
inbound.StreamSetting.Security = "tls"
certFile, keyFile, err := getCertFile(config.CertConfig)
if err != nil {
@@ -91,7 +91,7 @@ func buildInbound(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, tag s
}
func buildV2ray(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, inbound *coreConf.InboundDetourConfig) error {
if nodeInfo.EnableVless {
if config.EnableVless {
//Set vless
inbound.Protocol = "vless"
if config.EnableFallback {

View File

@@ -1,8 +1,8 @@
package controller_test
package node_test
import (
"github.com/Yuzuki616/V2bX/api/panel"
. "github.com/Yuzuki616/V2bX/node/controller"
. "github.com/Yuzuki616/V2bX/node"
"testing"
)

View File

@@ -4,11 +4,10 @@ import (
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/conf"
"github.com/Yuzuki616/V2bX/core"
"github.com/Yuzuki616/V2bX/node/controller"
)
type Node struct {
controllers []*controller.Node
controllers []*Controller
}
func New() *Node {
@@ -16,14 +15,14 @@ func New() *Node {
}
func (n *Node) Start(nodes []*conf.NodeConfig, core *core.Core) error {
n.controllers = make([]*controller.Node, len(nodes))
n.controllers = make([]*Controller, len(nodes))
for i, c := range nodes {
p, err := panel.New(c.ApiConfig)
if err != nil {
return err
}
// Register controller service
n.controllers[i] = controller.New(core, p, c.ControllerConfig)
n.controllers[i] = NewController(core, p, c.ControllerConfig)
err = n.controllers[i].Start()
if err != nil {
return err

View File

@@ -1,4 +1,4 @@
package controller
package node
import (
"fmt"

View File

@@ -1,10 +1,10 @@
package controller
package node
import (
"fmt"
"github.com/Yuzuki616/V2bX/api/iprecoder"
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/node/controller/lego"
"github.com/Yuzuki616/V2bX/limiter"
"github.com/Yuzuki616/V2bX/node/lego"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/task"
"log"
@@ -13,7 +13,7 @@ import (
"time"
)
func (c *Node) initTask() {
func (c *Controller) initTask() {
// fetch node info task
c.nodeInfoMonitorPeriodic = &task.Periodic{
Interval: time.Duration(c.nodeInfo.BaseConfig.PullInterval.(int)) * time.Second,
@@ -36,7 +36,7 @@ func (c *Node) initTask() {
time.Sleep(time.Duration(c.nodeInfo.BaseConfig.PushInterval.(int)) * time.Second)
_ = c.userReportPeriodic.Start()
}()
if c.nodeInfo.EnableTls && c.CertConfig.CertMode != "none" &&
if c.EnableTls && c.CertConfig.CertMode != "none" &&
(c.CertConfig.CertMode == "dns" || c.CertConfig.CertMode == "http") {
c.renewCertPeriodic = &task.Periodic{
Interval: time.Hour * 24,
@@ -48,42 +48,9 @@ func (c *Node) initTask() {
_ = c.renewCertPeriodic.Start()
}()
}
if c.EnableDynamicSpeedLimit {
// Check dynamic speed limit task
c.dynamicSpeedLimitPeriodic = &task.Periodic{
Interval: time.Duration(c.DynamicSpeedLimitConfig.Periodic) * time.Second,
Execute: c.dynamicSpeedLimit,
}
go func() {
time.Sleep(time.Duration(c.DynamicSpeedLimitConfig.Periodic) * time.Second)
_ = c.dynamicSpeedLimitPeriodic.Start()
}()
log.Printf("[%s: %d] Start dynamic speed limit", c.nodeInfo.NodeType, c.nodeInfo.NodeId)
}
if c.EnableIpRecorder {
switch c.IpRecorderConfig.Type {
case "Recorder":
c.ipRecorder = iprecoder.NewRecorder(c.IpRecorderConfig.RecorderConfig)
case "Redis":
c.ipRecorder = iprecoder.NewRedis(c.IpRecorderConfig.RedisConfig)
default:
log.Printf("recorder type: %s is not vail, disable recorder", c.IpRecorderConfig.Type)
return
}
// report and fetch online ip list task
c.onlineIpReportPeriodic = &task.Periodic{
Interval: time.Duration(c.IpRecorderConfig.Periodic) * time.Second,
Execute: c.reportOnlineIp,
}
go func() {
time.Sleep(time.Duration(c.IpRecorderConfig.Periodic) * time.Second)
_ = c.onlineIpReportPeriodic.Start()
}()
log.Printf("[%s: %d] Start report online ip", c.nodeInfo.NodeType, c.nodeInfo.NodeId)
}
}
func (c *Node) nodeInfoMonitor() (err error) {
func (c *Controller) nodeInfoMonitor() (err error) {
// First fetch Node Info
newNodeInfo, err := c.apiClient.GetNodeInfo()
if err != nil {
@@ -95,28 +62,22 @@ func (c *Node) nodeInfoMonitor() (err error) {
if newNodeInfo != nil {
// Remove old tag
oldTag := c.Tag
err := c.removeOldTag(oldTag)
err := c.removeOldNode(oldTag)
if err != nil {
log.Print(err)
return nil
}
// Remove Old limiter
limiter.DeleteLimiter(oldTag)
// Add new tag
c.nodeInfo = newNodeInfo
c.Tag = c.buildNodeTag()
err = c.addNewTag(newNodeInfo)
err = c.addNewNode(newNodeInfo)
if err != nil {
log.Print(err)
return nil
}
nodeInfoChanged = true
// Remove Old limiter
if err = c.server.DeleteInboundLimiter(oldTag); err != nil {
log.Print(err)
return nil
}
if err := c.server.UpdateRule(c.Tag, newNodeInfo.Rules); err != nil {
log.Print(err)
}
}
// Update User
newUserInfo, err := c.apiClient.GetUserList()
@@ -126,15 +87,20 @@ func (c *Node) nodeInfoMonitor() (err error) {
}
if nodeInfoChanged {
c.userList = newUserInfo
err = c.addNewUser(c.userList, newNodeInfo)
// Add new Limiter
l := limiter.AddLimiter(c.Tag, &limiter.LimitConfig{
SpeedLimit: c.SpeedLimit,
IpLimit: c.IPLimit,
ConnLimit: c.ConnLimit,
}, newUserInfo)
err = c.addNewUser(newUserInfo, newNodeInfo)
if err != nil {
log.Print(err)
return nil
}
// Add Limiter
if err := c.server.AddInboundLimiter(c.Tag, newNodeInfo, newUserInfo); err != nil {
log.Print(err)
return nil
err = l.UpdateRule(newNodeInfo.Rules)
if err != nil {
log.Printf("Update Rule error: %s", err)
}
// Check interval
if c.nodeInfoMonitorPeriodic.Interval != time.Duration(newNodeInfo.BaseConfig.PullInterval.(int))*time.Second {
@@ -176,8 +142,9 @@ func (c *Node) nodeInfoMonitor() (err error) {
}
if len(added) > 0 || len(deleted) > 0 {
// Update Limiter
if err := c.server.UpdateInboundLimiter(c.Tag, added, deleted); err != nil {
log.Print(err)
err = limiter.UpdateLimiter(c.Tag, added, deleted)
if err != nil {
log.Print("update limiter:", err)
}
}
log.Printf("[%s: %d] %d user deleted, %d user added", c.nodeInfo.NodeType, c.nodeInfo.NodeId,
@@ -187,7 +154,7 @@ func (c *Node) nodeInfoMonitor() (err error) {
return nil
}
func (c *Node) removeOldTag(oldTag string) (err error) {
func (c *Controller) removeOldNode(oldTag string) (err error) {
err = c.server.RemoveInbound(oldTag)
if err != nil {
return err
@@ -199,7 +166,7 @@ func (c *Node) removeOldTag(oldTag string) (err error) {
return nil
}
func (c *Node) addNewTag(newNodeInfo *panel.NodeInfo) (err error) {
func (c *Controller) addNewNode(newNodeInfo *panel.NodeInfo) (err error) {
inboundConfig, err := buildInbound(c.ControllerConfig, newNodeInfo, c.Tag)
if err != nil {
return fmt.Errorf("build inbound error: %s", err)
@@ -219,10 +186,10 @@ func (c *Node) addNewTag(newNodeInfo *panel.NodeInfo) (err error) {
return nil
}
func (c *Node) addNewUser(userInfo []panel.UserInfo, nodeInfo *panel.NodeInfo) (err error) {
func (c *Controller) addNewUser(userInfo []panel.UserInfo, nodeInfo *panel.NodeInfo) (err error) {
users := make([]*protocol.User, 0)
if nodeInfo.NodeType == "V2ray" {
if nodeInfo.EnableVless {
if c.EnableVless {
users = c.buildVlessUsers(userInfo)
} else {
users = c.buildVmessUsers(userInfo)
@@ -270,7 +237,7 @@ func compareUserList(old, new []panel.UserInfo) (deleted, added []panel.UserInfo
return deleted, added
}
func (c *Node) reportUserTraffic() (err error) {
func (c *Controller) reportUserTraffic() (err error) {
// Get User traffic
userTraffic := make([]panel.UserTraffic, 0)
for i := range c.userList {
@@ -294,52 +261,11 @@ func (c *Node) reportUserTraffic() (err error) {
}
}
userTraffic = nil
if !c.EnableIpRecorder {
c.server.ClearOnlineIp(c.Tag)
}
runtime.GC()
return nil
}
func (c *Node) reportOnlineIp() (err error) {
onlineIp, err := c.server.ListOnlineIp(c.Tag)
if err != nil {
log.Print(err)
return nil
}
onlineIp, err = c.ipRecorder.SyncOnlineIp(onlineIp)
if err != nil {
log.Print("Report online ip error: ", err)
c.server.ClearOnlineIp(c.Tag)
}
if c.IpRecorderConfig.EnableIpSync {
c.server.UpdateOnlineIp(c.Tag, onlineIp)
log.Printf("[Node: %d] Updated %d online ip", c.nodeInfo.NodeId, len(onlineIp))
}
log.Printf("[Node: %d] Report %d online ip", c.nodeInfo.NodeId, len(onlineIp))
return nil
}
func (c *Node) dynamicSpeedLimit() error {
if c.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.DynamicSpeedLimitConfig.Traffic {
err := c.server.AddUserSpeedLimit(c.Tag,
&c.userList[i],
c.DynamicSpeedLimitConfig.SpeedLimit,
time.Now().Add(time.Second*time.Duration(c.DynamicSpeedLimitConfig.ExpireTime)).Unix())
if err != nil {
log.Print(err)
}
}
c.userList[i].Traffic = 0
}
}
return nil
}
func (c *Node) RenewCert() {
func (c *Controller) RenewCert() {
l, err := lego.New(c.CertConfig)
if err != nil {
log.Print(err)

View File

@@ -1,4 +1,4 @@
package controller
package node
import (
"encoding/base64"
@@ -14,7 +14,7 @@ import (
"strings"
)
func (c *Node) buildVmessUsers(userInfo []panel.UserInfo) (users []*protocol.User) {
func (c *Controller) buildVmessUsers(userInfo []panel.UserInfo) (users []*protocol.User) {
users = make([]*protocol.User, len(userInfo))
for i, user := range userInfo {
users[i] = c.buildVmessUser(&user, 0)
@@ -22,7 +22,7 @@ func (c *Node) buildVmessUsers(userInfo []panel.UserInfo) (users []*protocol.Use
return users
}
func (c *Node) buildVmessUser(userInfo *panel.UserInfo, serverAlterID uint16) (user *protocol.User) {
func (c *Controller) buildVmessUser(userInfo *panel.UserInfo, serverAlterID uint16) (user *protocol.User) {
vmessAccount := &conf.VMessAccount{
ID: userInfo.Uuid,
AlterIds: serverAlterID,
@@ -35,7 +35,7 @@ func (c *Node) buildVmessUser(userInfo *panel.UserInfo, serverAlterID uint16) (u
}
}
func (c *Node) buildVlessUsers(userInfo []panel.UserInfo) (users []*protocol.User) {
func (c *Controller) buildVlessUsers(userInfo []panel.UserInfo) (users []*protocol.User) {
users = make([]*protocol.User, len(userInfo))
for i := range userInfo {
users[i] = c.buildVlessUser(&(userInfo)[i])
@@ -43,7 +43,7 @@ func (c *Node) buildVlessUsers(userInfo []panel.UserInfo) (users []*protocol.Use
return users
}
func (c *Node) buildVlessUser(userInfo *panel.UserInfo) (user *protocol.User) {
func (c *Controller) buildVlessUser(userInfo *panel.UserInfo) (user *protocol.User) {
vlessAccount := &vless.Account{
Id: userInfo.Uuid,
Flow: "xtls-rprx-direct",
@@ -55,7 +55,7 @@ func (c *Node) buildVlessUser(userInfo *panel.UserInfo) (user *protocol.User) {
}
}
func (c *Node) buildTrojanUsers(userInfo []panel.UserInfo) (users []*protocol.User) {
func (c *Controller) buildTrojanUsers(userInfo []panel.UserInfo) (users []*protocol.User) {
users = make([]*protocol.User, len(userInfo))
for i := range userInfo {
users[i] = c.buildTrojanUser(&(userInfo)[i])
@@ -63,7 +63,7 @@ func (c *Node) buildTrojanUsers(userInfo []panel.UserInfo) (users []*protocol.Us
return users
}
func (c *Node) buildTrojanUser(userInfo *panel.UserInfo) (user *protocol.User) {
func (c *Controller) buildTrojanUser(userInfo *panel.UserInfo) (user *protocol.User) {
trojanAccount := &trojan.Account{
Password: userInfo.Uuid,
Flow: "xtls-rprx-direct",
@@ -90,7 +90,7 @@ func getCipherFromString(c string) shadowsocks.CipherType {
}
}
func (c *Node) buildSSUsers(userInfo []panel.UserInfo, cypher shadowsocks.CipherType) (users []*protocol.User) {
func (c *Controller) buildSSUsers(userInfo []panel.UserInfo, cypher shadowsocks.CipherType) (users []*protocol.User) {
users = make([]*protocol.User, len(userInfo))
for i := range userInfo {
users[i] = c.buildSSUser(&(userInfo)[i], cypher)
@@ -98,7 +98,7 @@ func (c *Node) buildSSUsers(userInfo []panel.UserInfo, cypher shadowsocks.Cipher
return users
}
func (c *Node) buildSSUser(userInfo *panel.UserInfo, cypher shadowsocks.CipherType) (user *protocol.User) {
func (c *Controller) buildSSUser(userInfo *panel.UserInfo, cypher shadowsocks.CipherType) (user *protocol.User) {
if c.nodeInfo.ServerKey == "" {
ssAccount := &shadowsocks.Account{
Password: userInfo.Uuid,
@@ -121,6 +121,6 @@ func (c *Node) buildSSUser(userInfo *panel.UserInfo, cypher shadowsocks.CipherTy
}
}
func (c *Node) buildUserTag(user *panel.UserInfo) string {
func (c *Controller) buildUserTag(user *panel.UserInfo) string {
return fmt.Sprintf("%s|%s|%d", c.Tag, user.Uuid, user.Id)
}