add config watch

This commit is contained in:
yuzuki999
2022-10-10 11:31:15 +08:00
parent 231678cc8d
commit baab76d667
32 changed files with 320 additions and 247 deletions

View File

@@ -1,12 +1,12 @@
// Package node the InbounderConfig used by add inbound
package node
package controller
import (
"encoding/json"
"fmt"
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/conf"
"github.com/Yuzuki616/V2bX/node/legoCmd"
"github.com/Yuzuki616/V2bX/node/controller/legoCmd"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/uuid"
"github.com/xtls/xray-core/core"

View File

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

View File

@@ -7,7 +7,7 @@ import (
"encoding/pem"
"errors"
"fmt"
"github.com/Yuzuki616/V2bX/node/legoCmd/log"
"github.com/Yuzuki616/V2bX/node/controller/legoCmd/log"
"io/ioutil"
"net/url"
"os"
@@ -30,36 +30,35 @@ const (
//
// rootPath:
//
// ./.lego/accounts/
// │ └── root accounts directory
// └── "path" option
// ./.lego/accounts/
// │ └── root accounts directory
// └── "path" option
//
// rootUserPath:
//
// ./.lego/accounts/localhost_14000/hubert@hubert.com/
// │ │ │ └── userID ("email" option)
// │ │ └── CA server ("server" option)
// │ └── root accounts directory
// └── "path" option
// ./.lego/accounts/localhost_14000/hubert@hubert.com/
// │ │ │ └── userID ("email" option)
// │ │ └── CA server ("server" option)
// │ └── root accounts directory
// └── "path" option
//
// keysPath:
//
// ./.lego/accounts/localhost_14000/hubert@hubert.com/keys/
// │ │ │ │ └── root keys directory
// │ │ │ └── userID ("email" option)
// │ │ └── CA server ("server" option)
// │ └── root accounts directory
// └── "path" option
// ./.lego/accounts/localhost_14000/hubert@hubert.com/keys/
// │ │ │ │ └── root keys directory
// │ │ │ └── userID ("email" option)
// │ │ └── CA server ("server" option)
// │ └── root accounts directory
// └── "path" option
//
// accountFilePath:
//
// ./.lego/accounts/localhost_14000/hubert@hubert.com/account.json
// │ │ │ │ └── account file
// │ │ │ └── userID ("email" option)
// │ │ └── CA server ("server" option)
// │ └── root accounts directory
// └── "path" option
//
// ./.lego/accounts/localhost_14000/hubert@hubert.com/account.json
// │ │ │ │ └── account file
// │ │ │ └── userID ("email" option)
// │ │ └── CA server ("server" option)
// │ └── root accounts directory
// └── "path" option
type AccountsStorage struct {
userID string
rootPath string

View File

@@ -4,7 +4,7 @@ import (
"bytes"
"crypto/x509"
"encoding/json"
"github.com/Yuzuki616/V2bX/node/legoCmd/log"
"github.com/Yuzuki616/V2bX/node/controller/legoCmd/log"
"io/ioutil"
"os"
"path/filepath"
@@ -27,16 +27,15 @@ const (
//
// rootPath:
//
// ./.lego/certificates/
// │ └── root certificates directory
// └── "path" option
// ./.lego/certificates/
// │ └── root certificates directory
// └── "path" option
//
// archivePath:
//
// ./.lego/archives/
// │ └── archived certificates directory
// └── "path" option
//
// ./.lego/archives/
// │ └── archived certificates directory
// └── "path" option
type CertificatesStorage struct {
rootPath string
archivePath string

View File

@@ -1,7 +1,7 @@
package cmd
import (
"github.com/Yuzuki616/V2bX/node/legoCmd/log"
"github.com/Yuzuki616/V2bX/node/controller/legoCmd/log"
"github.com/urfave/cli"
)

View File

@@ -3,7 +3,7 @@ package cmd
import (
"crypto"
"crypto/x509"
"github.com/Yuzuki616/V2bX/node/legoCmd/log"
"github.com/Yuzuki616/V2bX/node/controller/legoCmd/log"
"time"
"github.com/go-acme/lego/v4/certcrypto"

View File

@@ -1,7 +1,7 @@
package cmd
import (
"github.com/Yuzuki616/V2bX/node/legoCmd/log"
"github.com/Yuzuki616/V2bX/node/controller/legoCmd/log"
"github.com/urfave/cli"
)

View File

@@ -3,7 +3,7 @@ package cmd
import (
"bufio"
"fmt"
"github.com/Yuzuki616/V2bX/node/legoCmd/log"
"github.com/Yuzuki616/V2bX/node/controller/legoCmd/log"
"os"
"strings"

View File

@@ -4,7 +4,7 @@ import (
"crypto/x509"
"encoding/pem"
"fmt"
"github.com/Yuzuki616/V2bX/node/legoCmd/log"
"github.com/Yuzuki616/V2bX/node/controller/legoCmd/log"
"io/ioutil"
"os"
"strings"

View File

@@ -1,7 +1,7 @@
package cmd
import (
"github.com/Yuzuki616/V2bX/node/legoCmd/log"
"github.com/Yuzuki616/V2bX/node/controller/legoCmd/log"
"net"
"strings"
"time"

View File

@@ -5,7 +5,7 @@ package legoCmd
import (
"errors"
"fmt"
cmd2 "github.com/Yuzuki616/V2bX/node/legoCmd/cmd"
"github.com/Yuzuki616/V2bX/node/controller/legoCmd/cmd"
"os"
"path"
"path/filepath"
@@ -47,11 +47,11 @@ func New() (*LegoCMD, error) {
defaultPath = filepath.Join(pathTemp, "cert")
app.Flags = cmd2.CreateFlags(defaultPath)
app.Flags = cmd.CreateFlags(defaultPath)
app.Before = cmd2.Before
app.Before = cmd.Before
app.Commands = cmd2.CreateCommands()
app.Commands = cmd.CreateCommands()
lego := &LegoCMD{
cmdClient: app,

View File

@@ -1,7 +1,7 @@
package legoCmd_test
import (
"github.com/Yuzuki616/V2bX/node/legoCmd"
"github.com/Yuzuki616/V2bX/node/controller/legoCmd"
"testing"
)

160
node/controller/node.go Normal file
View File

@@ -0,0 +1,160 @@
package controller
import (
"errors"
"fmt"
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/conf"
"github.com/Yuzuki616/V2bX/core"
"github.com/xtls/xray-core/common/task"
"log"
"time"
)
type Node struct {
server *core.Core
config *conf.ControllerConfig
clientInfo panel.ClientInfo
apiClient panel.Panel
nodeInfo *panel.NodeInfo
Tag string
userList []panel.UserInfo
nodeInfoMonitorPeriodic *task.Periodic
userReportPeriodic *task.Periodic
onlineIpReportPeriodic *task.Periodic
DynamicSpeedLimitPeriodic *task.Periodic
}
// New return a Node service with default parameters.
func New(server *core.Core, api panel.Panel, config *conf.ControllerConfig) *Node {
controller := &Node{
server: server,
config: config,
apiClient: api,
}
return controller
}
// Start implement the Start() function of the service interface
func (c *Node) Start() error {
c.clientInfo = c.apiClient.Describe()
// First fetch Node Info
newNodeInfo, err := c.apiClient.GetNodeInfo()
if err != nil {
return fmt.Errorf("get node info failed: %s", err)
}
c.nodeInfo = newNodeInfo
c.Tag = c.buildNodeTag()
// Add new tag
err = c.addNewTag(newNodeInfo)
if err != nil {
return fmt.Errorf("add new tag failed: %s", err)
}
// Update user
c.userList, err = c.apiClient.GetUserList()
if err != nil {
return fmt.Errorf("get user list failed: %s", err)
}
if len(c.userList) == 0 {
return errors.New("add users failed: not have any user")
}
err = c.addNewUser(c.userList, newNodeInfo)
if err != nil {
return err
}
if err := c.server.AddInboundLimiter(c.Tag, c.nodeInfo); err != nil {
return fmt.Errorf("add inbound limiter failed: %s", err)
}
// Add Rule Manager
if !c.config.DisableGetRule {
if ruleList, err := c.apiClient.GetNodeRule(); err != nil {
log.Printf("Get rule list filed: %s", err)
} else if ruleList != nil {
if err := c.server.UpdateRule(c.Tag, ruleList); err != nil {
log.Printf("Update rule filed: %s", err)
}
}
}
// fetch node info task
c.nodeInfoMonitorPeriodic = &task.Periodic{
Interval: time.Duration(c.config.UpdatePeriodic) * time.Second,
Execute: c.nodeInfoMonitor,
}
// fetch user list task
c.userReportPeriodic = &task.Periodic{
Interval: time.Duration(c.config.UpdatePeriodic) * time.Second,
Execute: c.reportUserTraffic,
}
log.Printf("[%s: %d] Start monitor node status", c.nodeInfo.NodeType, c.nodeInfo.NodeId)
// delay to start nodeInfoMonitor
go func() {
time.Sleep(time.Duration(c.config.UpdatePeriodic) * time.Second)
_ = c.nodeInfoMonitorPeriodic.Start()
}()
log.Printf("[%s: %d] Start report node status", c.nodeInfo.NodeType, c.nodeInfo.NodeId)
// delay to start userReport
go func() {
time.Sleep(time.Duration(c.config.UpdatePeriodic) * time.Second)
_ = c.userReportPeriodic.Start()
}()
if c.config.EnableIpRecorder {
// report and fetch online ip list task
c.onlineIpReportPeriodic = &task.Periodic{
Interval: time.Duration(c.config.IpRecorderConfig.Periodic) * time.Second,
Execute: c.reportOnlineIp,
}
go func() {
time.Sleep(time.Duration(c.config.IpRecorderConfig.Periodic) * time.Second)
_ = c.onlineIpReportPeriodic.Start()
}()
log.Printf("[%s: %d] Start report online ip", c.nodeInfo.NodeType, c.nodeInfo.NodeId)
}
if c.config.EnableDynamicSpeedLimit {
// Check dynamic speed limit task
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)
}
return nil
}
// Close implement the Close() function of the service interface
func (c *Node) Close() error {
if c.nodeInfoMonitorPeriodic != nil {
err := c.nodeInfoMonitorPeriodic.Close()
if err != nil {
log.Panicf("node info periodic close failed: %s", err)
}
}
if c.nodeInfoMonitorPeriodic != nil {
err := c.userReportPeriodic.Close()
if err != nil {
log.Panicf("user report periodic close failed: %s", err)
}
}
if c.onlineIpReportPeriodic != nil {
err := c.onlineIpReportPeriodic.Close()
if err != nil {
log.Panicf("online ip report periodic close failed: %s", err)
}
}
if c.DynamicSpeedLimitPeriodic != nil {
err := c.DynamicSpeedLimitPeriodic.Close()
if err != nil {
log.Panicf("dynamic speed limit periodic close failed: %s", err)
}
}
return nil
}
func (c *Node) buildNodeTag() string {
return fmt.Sprintf("%s_%s_%d", c.nodeInfo.NodeType, c.config.ListenIP, c.nodeInfo.NodeId)
}

View File

@@ -1,4 +1,4 @@
package node_test
package controller_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"
. "github.com/Yuzuki616/V2bX/node/controller"
xCore "github.com/xtls/xray-core/core"
coreConf "github.com/xtls/xray-core/infra/conf"
"os"

View File

@@ -1,4 +1,4 @@
package node
package controller
import (
"encoding/json"

View File

@@ -1,10 +1,10 @@
package node
package controller
import (
"fmt"
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/core/app/dispatcher"
"github.com/Yuzuki616/V2bX/node/legoCmd"
"github.com/Yuzuki616/V2bX/node/controller/legoCmd"
"github.com/go-resty/resty/v2"
"github.com/goccy/go-json"
"github.com/xtls/xray-core/common/protocol"

View File

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

View File

@@ -1,160 +1,39 @@
package node
import (
"errors"
"fmt"
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/conf"
"github.com/Yuzuki616/V2bX/core"
"github.com/xtls/xray-core/common/task"
"log"
"time"
"github.com/Yuzuki616/V2bX/node/controller"
)
type Node struct {
server *core.Core
config *conf.ControllerConfig
clientInfo panel.ClientInfo
apiClient panel.Panel
nodeInfo *panel.NodeInfo
Tag string
userList []panel.UserInfo
nodeInfoMonitorPeriodic *task.Periodic
userReportPeriodic *task.Periodic
onlineIpReportPeriodic *task.Periodic
DynamicSpeedLimitPeriodic *task.Periodic
controllers []*controller.Node
}
// New return a Node service with default parameters.
func New(server *core.Core, api panel.Panel, config *conf.ControllerConfig) *Node {
controller := &Node{
server: server,
config: config,
apiClient: api,
}
return controller
func New() *Node {
return &Node{}
}
// Start implement the Start() function of the service interface
func (c *Node) Start() error {
c.clientInfo = c.apiClient.Describe()
// First fetch Node Info
newNodeInfo, err := c.apiClient.GetNodeInfo()
if err != nil {
return fmt.Errorf("get node info failed: %s", err)
}
c.nodeInfo = newNodeInfo
c.Tag = c.buildNodeTag()
// Add new tag
err = c.addNewTag(newNodeInfo)
if err != nil {
return fmt.Errorf("add new tag failed: %s", err)
}
// Update user
c.userList, err = c.apiClient.GetUserList()
if err != nil {
return fmt.Errorf("get user list failed: %s", err)
}
if len(c.userList) == 0 {
return errors.New("add users failed: not have any user")
}
err = c.addNewUser(c.userList, newNodeInfo)
if err != nil {
return err
}
if err := c.server.AddInboundLimiter(c.Tag, c.nodeInfo); err != nil {
return fmt.Errorf("add inbound limiter failed: %s", err)
}
// Add Rule Manager
if !c.config.DisableGetRule {
if ruleList, err := c.apiClient.GetNodeRule(); err != nil {
log.Printf("Get rule list filed: %s", err)
} else if ruleList != nil {
if err := c.server.UpdateRule(c.Tag, ruleList); err != nil {
log.Printf("Update rule filed: %s", err)
}
}
}
// fetch node info task
c.nodeInfoMonitorPeriodic = &task.Periodic{
Interval: time.Duration(c.config.UpdatePeriodic) * time.Second,
Execute: c.nodeInfoMonitor,
}
// fetch user list task
c.userReportPeriodic = &task.Periodic{
Interval: time.Duration(c.config.UpdatePeriodic) * time.Second,
Execute: c.reportUserTraffic,
}
log.Printf("[%s: %d] Start monitor node status", c.nodeInfo.NodeType, c.nodeInfo.NodeId)
// delay to start nodeInfoMonitor
go func() {
time.Sleep(time.Duration(c.config.UpdatePeriodic) * time.Second)
_ = c.nodeInfoMonitorPeriodic.Start()
}()
log.Printf("[%s: %d] Start report node status", c.nodeInfo.NodeType, c.nodeInfo.NodeId)
// delay to start userReport
go func() {
time.Sleep(time.Duration(c.config.UpdatePeriodic) * time.Second)
_ = c.userReportPeriodic.Start()
}()
if c.config.EnableIpRecorder {
// report and fetch online ip list task
c.onlineIpReportPeriodic = &task.Periodic{
Interval: time.Duration(c.config.IpRecorderConfig.Periodic) * time.Second,
Execute: c.reportOnlineIp,
}
go func() {
time.Sleep(time.Duration(c.config.IpRecorderConfig.Periodic) * time.Second)
_ = c.onlineIpReportPeriodic.Start()
}()
log.Printf("[%s: %d] Start report online ip", c.nodeInfo.NodeType, c.nodeInfo.NodeId)
}
if c.config.EnableDynamicSpeedLimit {
// Check dynamic speed limit task
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)
}
return nil
}
// Close implement the Close() function of the service interface
func (c *Node) Close() error {
if c.nodeInfoMonitorPeriodic != nil {
err := c.nodeInfoMonitorPeriodic.Close()
func (n *Node) Start(nodes []*conf.NodeConfig, core *core.Core) error {
n.controllers = make([]*controller.Node, len(nodes))
for i, c := range nodes {
// Register controller service
n.controllers[i] = controller.New(core, panel.New(c.ApiConfig), c.ControllerConfig)
err := n.controllers[i].Start()
if err != nil {
log.Panicf("node info periodic close failed: %s", err)
}
}
if c.nodeInfoMonitorPeriodic != nil {
err := c.userReportPeriodic.Close()
if err != nil {
log.Panicf("user report periodic close failed: %s", err)
}
}
if c.onlineIpReportPeriodic != nil {
err := c.onlineIpReportPeriodic.Close()
if err != nil {
log.Panicf("online ip report periodic close failed: %s", err)
}
}
if c.DynamicSpeedLimitPeriodic != nil {
err := c.DynamicSpeedLimitPeriodic.Close()
if err != nil {
log.Panicf("dynamic speed limit periodic close failed: %s", err)
return err
}
}
return nil
}
func (c *Node) buildNodeTag() string {
return fmt.Sprintf("%s_%s_%d", c.nodeInfo.NodeType, c.config.ListenIP, c.nodeInfo.NodeId)
func (n *Node) Close() {
for _, c := range n.controllers {
err := c.Close()
if err != nil {
panic(err)
}
}
n.controllers = nil
}