mirror of
https://github.com/wyx2685/V2bX.git
synced 2025-02-02 06:48:14 -05:00
Merge remote-tracking branch 'origin/dev' into dev
# Conflicts: # conf/node.go
This commit is contained in:
commit
251702c06a
@ -30,7 +30,7 @@ A V2board node server based on multi core, modified from XrayR.
|
|||||||
| 在线人数统计 | √ | √ | √ | √ |
|
| 在线人数统计 | √ | √ | √ | √ |
|
||||||
| 审计规则 | √ | √ | √ | |
|
| 审计规则 | √ | √ | √ | |
|
||||||
| 自定义DNS | √ | √ | √ | √ |
|
| 自定义DNS | √ | √ | √ | √ |
|
||||||
| 在线IP数限制 | √ | √ | √ | |
|
| 在线IP数限制 | √ | √ | √ | √ |
|
||||||
| 连接数限制 | √ | √ | √ | |
|
| 连接数限制 | √ | √ | √ | |
|
||||||
| 跨节点IP数限制 | √ | √ | √ | |
|
| 跨节点IP数限制 | √ | √ | √ | |
|
||||||
| 按照用户限速 | √ | √ | √ | |
|
| 按照用户限速 | √ | √ | √ | |
|
||||||
@ -43,6 +43,7 @@ A V2board node server based on multi core, modified from XrayR.
|
|||||||
- [x] 集成基本操作Command(Start, Stop, Restart, Status, Uninstall)
|
- [x] 集成基本操作Command(Start, Stop, Restart, Status, Uninstall)
|
||||||
- [ ] 完善Hysteria内核支持
|
- [ ] 完善Hysteria内核支持
|
||||||
- [ ] 完善使用文档
|
- [ ] 完善使用文档
|
||||||
|
- [ ] 尽可能统一日志输出格式
|
||||||
|
|
||||||
## 软件安装
|
## 软件安装
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package panel
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/Yuzuki616/V2bX/conf"
|
||||||
"github.com/goccy/go-json"
|
"github.com/goccy/go-json"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
@ -41,11 +42,6 @@ type ShadowsocksNodeRsp struct {
|
|||||||
ServerKey string `json:"server_key"`
|
ServerKey string `json:"server_key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TrojanNodeRsp struct {
|
|
||||||
Host string `json:"host"`
|
|
||||||
ServerName string `json:"server_name"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type HysteriaNodeRsp struct {
|
type HysteriaNodeRsp struct {
|
||||||
UpMbps int `json:"up_mbps"`
|
UpMbps int `json:"up_mbps"`
|
||||||
DownMbps int `json:"down_mbps"`
|
DownMbps int `json:"down_mbps"`
|
||||||
@ -59,6 +55,7 @@ type NodeInfo struct {
|
|||||||
Host string
|
Host string
|
||||||
Port int
|
Port int
|
||||||
Network string
|
Network string
|
||||||
|
ExtraConfig V2rayExtraConfig
|
||||||
NetworkSettings json.RawMessage
|
NetworkSettings json.RawMessage
|
||||||
Tls bool
|
Tls bool
|
||||||
ServerName string
|
ServerName string
|
||||||
@ -71,13 +68,23 @@ type NodeInfo struct {
|
|||||||
PullInterval time.Duration
|
PullInterval time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type V2rayExtraConfig struct {
|
||||||
|
EnableVless bool `json:"EnableVless"`
|
||||||
|
VlessFlow string `json:"VlessFlow"`
|
||||||
|
EnableReality bool `json:"EnableReality"`
|
||||||
|
RealityConfig conf.RealityConfig `json:"RealityConfig"`
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) GetNodeInfo() (node *NodeInfo, err error) {
|
func (c *Client) GetNodeInfo() (node *NodeInfo, err error) {
|
||||||
const path = "/api/v1/server/UniProxy/config"
|
const path = "/api/v1/server/UniProxy/config"
|
||||||
r, err := c.client.R().Get(path)
|
r, err := c.client.
|
||||||
|
R().
|
||||||
|
SetHeader("If-None-Match", c.etag).
|
||||||
|
Get(path)
|
||||||
if err = c.checkResponse(r, path, err); err != nil {
|
if err = c.checkResponse(r, path, err); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if c.etag == r.Header().Get("ETag") { // node info not changed
|
if r.StatusCode() == 304 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
// parse common params
|
// parse common params
|
||||||
@ -90,17 +97,30 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("decode common params error: %s", err)
|
return nil, fmt.Errorf("decode common params error: %s", err)
|
||||||
}
|
}
|
||||||
|
var extra []byte
|
||||||
for i := range common.Routes { // parse rules from routes
|
for i := range common.Routes { // parse rules from routes
|
||||||
if common.Routes[i].Action == "block" {
|
var matchs []string
|
||||||
var matchs []string
|
if _, ok := common.Routes[i].Match.(string); ok {
|
||||||
if _, ok := common.Routes[i].Match.(string); ok {
|
matchs = strings.Split(common.Routes[i].Match.(string), ",")
|
||||||
matchs = strings.Split(common.Routes[i].Match.(string), ",")
|
} else if _, ok = common.Routes[i].Match.([]string); ok {
|
||||||
} else {
|
matchs = common.Routes[i].Match.([]string)
|
||||||
matchs = common.Routes[i].Match.([]string)
|
} else {
|
||||||
|
temp := common.Routes[i].Match.([]interface{})
|
||||||
|
matchs = make([]string, len(temp))
|
||||||
|
for i := range temp {
|
||||||
|
matchs[i] = temp[i].(string)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
switch common.Routes[i].Action {
|
||||||
|
case "block":
|
||||||
for _, v := range matchs {
|
for _, v := range matchs {
|
||||||
node.Rules = append(node.Rules, regexp.MustCompile(v))
|
node.Rules = append(node.Rules, regexp.MustCompile(v))
|
||||||
}
|
}
|
||||||
|
case "dns":
|
||||||
|
if matchs[0] != "extra" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
extra = []byte(strings.Join(matchs[1:], ""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
node.ServerName = common.ServerName
|
node.ServerName = common.ServerName
|
||||||
@ -122,6 +142,12 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) {
|
|||||||
if rsp.Tls == 1 {
|
if rsp.Tls == 1 {
|
||||||
node.Tls = true
|
node.Tls = true
|
||||||
}
|
}
|
||||||
|
if len(extra) != 0 {
|
||||||
|
err = json.Unmarshal(extra, &node.ExtraConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("decode v2ray extra error: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
case "shadowsocks":
|
case "shadowsocks":
|
||||||
rsp := ShadowsocksNodeRsp{}
|
rsp := ShadowsocksNodeRsp{}
|
||||||
err = json.Unmarshal(r.Body(), &rsp)
|
err = json.Unmarshal(r.Body(), &rsp)
|
||||||
@ -131,11 +157,6 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) {
|
|||||||
node.ServerKey = rsp.ServerKey
|
node.ServerKey = rsp.ServerKey
|
||||||
node.Cipher = rsp.Cipher
|
node.Cipher = rsp.Cipher
|
||||||
case "trojan":
|
case "trojan":
|
||||||
rsp := TrojanNodeRsp{}
|
|
||||||
err = json.Unmarshal(r.Body(), &rsp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("decode v2ray params error: %s", err)
|
|
||||||
}
|
|
||||||
case "hysteria":
|
case "hysteria":
|
||||||
rsp := HysteriaNodeRsp{}
|
rsp := HysteriaNodeRsp{}
|
||||||
err = json.Unmarshal(r.Body(), &rsp)
|
err = json.Unmarshal(r.Body(), &rsp)
|
||||||
@ -146,7 +167,7 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) {
|
|||||||
node.UpMbps = rsp.UpMbps
|
node.UpMbps = rsp.UpMbps
|
||||||
node.HyObfs = rsp.Obfs
|
node.HyObfs = rsp.Obfs
|
||||||
}
|
}
|
||||||
c.etag = r.Header().Get("Etag")
|
c.etag = r.Header().Get("ETag")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ func init() {
|
|||||||
|
|
||||||
func TestClient_GetNodeInfo(t *testing.T) {
|
func TestClient_GetNodeInfo(t *testing.T) {
|
||||||
log.Println(client.GetNodeInfo())
|
log.Println(client.GetNodeInfo())
|
||||||
|
log.Println(client.GetNodeInfo())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClient_ReportUserTraffic(t *testing.T) {
|
func TestClient_ReportUserTraffic(t *testing.T) {
|
||||||
|
@ -18,7 +18,7 @@ func (c *Client) checkResponse(res *resty.Response, path string, err error) erro
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("request %s failed: %s", c.assembleURL(path), err)
|
return fmt.Errorf("request %s failed: %s", c.assembleURL(path), err)
|
||||||
}
|
}
|
||||||
if res.StatusCode() != 200 {
|
if res.StatusCode() >= 400 {
|
||||||
body := res.Body()
|
body := res.Body()
|
||||||
return fmt.Errorf("request %s failed: %s", c.assembleURL(path), string(body))
|
return fmt.Errorf("request %s failed: %s", c.assembleURL(path), string(body))
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
_ "github.com/Yuzuki616/V2bX/core/imports"
|
_ "github.com/Yuzuki616/V2bX/core/imports"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@ -14,6 +14,6 @@ var command = &cobra.Command{
|
|||||||
func Run() {
|
func Run() {
|
||||||
err := command.Execute()
|
err := command.Execute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("execute failed, error:", err)
|
log.WithField("err", err).Error("Execute command failed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
log "github.com/sirupsen/logrus"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -42,23 +42,26 @@ func serverHandle(_ *cobra.Command, _ []string) {
|
|||||||
c := conf.New()
|
c := conf.New()
|
||||||
err := c.LoadFromPath(config)
|
err := c.LoadFromPath(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("can't unmarshal config file: %s \n", err)
|
log.WithField("err", err).Error("Load config file failed")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
limiter.Init()
|
limiter.Init()
|
||||||
log.Println("Start V2bX...")
|
log.Info("Start V2bX...")
|
||||||
vc, err := vCore.NewCore(&c.CoreConfig)
|
vc, err := vCore.NewCore(&c.CoreConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("New core error: %s", err)
|
log.WithField("err", err).Error("new core failed")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
err = vc.Start()
|
err = vc.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Start core error: %s", err)
|
log.WithField("err", err).Error("Start core failed")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
defer vc.Close()
|
defer vc.Close()
|
||||||
nodes := node.New()
|
nodes := node.New()
|
||||||
err = nodes.Start(c.NodesConfig, vc)
|
err = nodes.Start(c.NodesConfig, vc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Run nodes error: %s", err)
|
log.WithField("err", err).Error("Run nodes failed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if watch {
|
if watch {
|
||||||
@ -66,24 +69,29 @@ func serverHandle(_ *cobra.Command, _ []string) {
|
|||||||
nodes.Close()
|
nodes.Close()
|
||||||
err = vc.Close()
|
err = vc.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to restart xray-core: %s", err)
|
log.WithField("err", err).Error("Restart node failed")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
vc, err = vCore.NewCore(&c.CoreConfig)
|
vc, err = vCore.NewCore(&c.CoreConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("New core error: %s", err)
|
log.WithField("err", err).Error("New core failed")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
err = vc.Start()
|
err = vc.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Start core error: %s", err)
|
log.WithField("err", err).Error("Start core failed")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
err = nodes.Start(c.NodesConfig, vc)
|
err = nodes.Start(c.NodesConfig, vc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Run nodes error: %s", err)
|
log.WithField("err", err).Error("Run nodes failed")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Watch config file error: %s", err)
|
log.WithField("err", err).Error("start watch failed")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// clear memory
|
// clear memory
|
||||||
|
@ -90,6 +90,7 @@ func BuildInbound(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, tag s
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// Normal tls
|
// Normal tls
|
||||||
|
in.StreamSetting.Security = "tls"
|
||||||
in.StreamSetting.TLSSettings = &coreConf.TLSConfig{
|
in.StreamSetting.TLSSettings = &coreConf.TLSConfig{
|
||||||
Certs: []*coreConf.TLSCertConfig{
|
Certs: []*coreConf.TLSCertConfig{
|
||||||
{
|
{
|
||||||
@ -102,6 +103,25 @@ func BuildInbound(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, tag s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// use remote reality replace local config
|
||||||
|
if nodeInfo.ExtraConfig.EnableReality {
|
||||||
|
rc := nodeInfo.ExtraConfig.RealityConfig
|
||||||
|
in.StreamSetting.Security = "reality"
|
||||||
|
d, err := json.Marshal(rc.Dest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("marshal reality dest error: %s", err)
|
||||||
|
}
|
||||||
|
in.StreamSetting.REALITYSettings = &coreConf.REALITYConfig{
|
||||||
|
Dest: d,
|
||||||
|
Xver: rc.Xver,
|
||||||
|
ServerNames: rc.ServerNames,
|
||||||
|
PrivateKey: rc.PrivateKey,
|
||||||
|
MinClientVer: rc.MinClientVer,
|
||||||
|
MaxClientVer: rc.MaxClientVer,
|
||||||
|
MaxTimeDiff: rc.MaxTimeDiff,
|
||||||
|
ShortIds: rc.ShortIds,
|
||||||
|
}
|
||||||
|
}
|
||||||
// Support ProxyProtocol for any transport protocol
|
// Support ProxyProtocol for any transport protocol
|
||||||
if *in.StreamSetting.Network != "tcp" &&
|
if *in.StreamSetting.Network != "tcp" &&
|
||||||
*in.StreamSetting.Network != "ws" &&
|
*in.StreamSetting.Network != "ws" &&
|
||||||
@ -117,7 +137,8 @@ func BuildInbound(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, tag s
|
|||||||
}
|
}
|
||||||
|
|
||||||
func buildV2ray(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, inbound *coreConf.InboundDetourConfig) error {
|
func buildV2ray(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, inbound *coreConf.InboundDetourConfig) error {
|
||||||
if config.XrayOptions.EnableVless {
|
if config.XrayOptions.EnableVless ||
|
||||||
|
nodeInfo.ExtraConfig.EnableVless {
|
||||||
//Set vless
|
//Set vless
|
||||||
inbound.Protocol = "vless"
|
inbound.Protocol = "vless"
|
||||||
if config.XrayOptions.EnableFallback {
|
if config.XrayOptions.EnableFallback {
|
||||||
|
@ -14,8 +14,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const xtlsFLow = "xtls-rprx-vision"
|
|
||||||
|
|
||||||
func BuildVmessUsers(tag string, userInfo []panel.UserInfo) (users []*protocol.User) {
|
func BuildVmessUsers(tag string, userInfo []panel.UserInfo) (users []*protocol.User) {
|
||||||
users = make([]*protocol.User, len(userInfo))
|
users = make([]*protocol.User, len(userInfo))
|
||||||
for i, user := range userInfo {
|
for i, user := range userInfo {
|
||||||
@ -37,21 +35,19 @@ func BuildVmessUser(tag string, userInfo *panel.UserInfo) (user *protocol.User)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuildVlessUsers(tag string, userInfo []panel.UserInfo, xtls bool) (users []*protocol.User) {
|
func BuildVlessUsers(tag string, userInfo []panel.UserInfo, flow string) (users []*protocol.User) {
|
||||||
users = make([]*protocol.User, len(userInfo))
|
users = make([]*protocol.User, len(userInfo))
|
||||||
for i := range userInfo {
|
for i := range userInfo {
|
||||||
users[i] = BuildVlessUser(tag, &(userInfo)[i], xtls)
|
users[i] = BuildVlessUser(tag, &(userInfo)[i], flow)
|
||||||
}
|
}
|
||||||
return users
|
return users
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuildVlessUser(tag string, userInfo *panel.UserInfo, xtls bool) (user *protocol.User) {
|
func BuildVlessUser(tag string, userInfo *panel.UserInfo, flow string) (user *protocol.User) {
|
||||||
vlessAccount := &vless.Account{
|
vlessAccount := &vless.Account{
|
||||||
Id: userInfo.Uuid,
|
Id: userInfo.Uuid,
|
||||||
}
|
}
|
||||||
if xtls {
|
vlessAccount.Flow = flow
|
||||||
vlessAccount.Flow = xtlsFLow
|
|
||||||
}
|
|
||||||
return &protocol.User{
|
return &protocol.User{
|
||||||
Level: 0,
|
Level: 0,
|
||||||
Email: BuildUserTag(tag, userInfo.Uuid),
|
Email: BuildUserTag(tag, userInfo.Uuid),
|
||||||
@ -93,7 +89,7 @@ func BuildSSUser(tag string, userInfo *panel.UserInfo, cypher string, serverKey
|
|||||||
}
|
}
|
||||||
return &protocol.User{
|
return &protocol.User{
|
||||||
Level: 0,
|
Level: 0,
|
||||||
Email: tag,
|
Email: BuildUserTag(tag, userInfo.Uuid),
|
||||||
Account: serial.ToTypedMessage(ssAccount),
|
Account: serial.ToTypedMessage(ssAccount),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
78
common/task/task.go
Normal file
78
common/task/task.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package task
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Task is a task that runs periodically.
|
||||||
|
type Task struct {
|
||||||
|
// Interval of the task being run
|
||||||
|
Interval time.Duration
|
||||||
|
// Execute is the task function
|
||||||
|
Execute func() error
|
||||||
|
|
||||||
|
access sync.Mutex
|
||||||
|
timer *time.Timer
|
||||||
|
running bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Task) hasClosed() bool {
|
||||||
|
t.access.Lock()
|
||||||
|
defer t.access.Unlock()
|
||||||
|
|
||||||
|
return !t.running
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Task) checkedExecute(first bool) error {
|
||||||
|
if t.hasClosed() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
t.access.Lock()
|
||||||
|
defer t.access.Unlock()
|
||||||
|
if first {
|
||||||
|
if err := t.Execute(); err != nil {
|
||||||
|
t.running = false
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !t.running {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
t.timer = time.AfterFunc(t.Interval, func() {
|
||||||
|
t.checkedExecute(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start implements common.Runnable.
|
||||||
|
func (t *Task) Start(first bool) error {
|
||||||
|
t.access.Lock()
|
||||||
|
if t.running {
|
||||||
|
t.access.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
t.running = true
|
||||||
|
t.access.Unlock()
|
||||||
|
if err := t.checkedExecute(first); err != nil {
|
||||||
|
t.access.Lock()
|
||||||
|
t.running = false
|
||||||
|
t.access.Unlock()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close implements common.Closable.
|
||||||
|
func (t *Task) Close() {
|
||||||
|
t.access.Lock()
|
||||||
|
defer t.access.Unlock()
|
||||||
|
|
||||||
|
t.running = false
|
||||||
|
if t.timer != nil {
|
||||||
|
t.timer.Stop()
|
||||||
|
t.timer = nil
|
||||||
|
}
|
||||||
|
}
|
15
common/task/task_test.go
Normal file
15
common/task/task_test.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package task
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTask(t *testing.T) {
|
||||||
|
ts := Task{Execute: func() error {
|
||||||
|
log.Println("q")
|
||||||
|
return nil
|
||||||
|
}, Interval: time.Second}
|
||||||
|
ts.Start(false)
|
||||||
|
}
|
50
conf/conf.go
50
conf/conf.go
@ -2,14 +2,9 @@ package conf
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/fsnotify/fsnotify"
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Conf struct {
|
type Conf struct {
|
||||||
@ -56,44 +51,3 @@ func (p *Conf) LoadFromPath(filePath string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Conf) Watch(filePath string, reload func()) error {
|
|
||||||
watcher, err := fsnotify.NewWatcher()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("new watcher error: %s", err)
|
|
||||||
}
|
|
||||||
go func() {
|
|
||||||
var pre time.Time
|
|
||||||
defer watcher.Close()
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case e := <-watcher.Events:
|
|
||||||
if e.Has(fsnotify.Chmod) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if pre.Add(1 * time.Second).After(time.Now()) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
pre = time.Now()
|
|
||||||
log.Println("config dir changed, reloading...")
|
|
||||||
*p = *New()
|
|
||||||
err := p.LoadFromPath(filePath)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("reload config error: %s", err)
|
|
||||||
}
|
|
||||||
reload()
|
|
||||||
log.Println("reload config success")
|
|
||||||
case err := <-watcher.Errors:
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("File watcher error: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
err = watcher.Add(path.Dir(filePath))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("watch file error: %s", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
52
conf/node.go
52
conf/node.go
@ -15,28 +15,26 @@ type ApiConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ControllerConfig struct {
|
type ControllerConfig struct {
|
||||||
DisableUploadTraffic bool `yaml:"DisableUploadTraffic"`
|
ListenIP string `yaml:"ListenIP"`
|
||||||
DisableGetRule bool `yaml:"DisableGetRule"`
|
SendIP string `yaml:"SendIP"`
|
||||||
ListenIP string `yaml:"ListenIP"`
|
EnableProxyProtocol bool `yaml:"EnableProxyProtocol"`
|
||||||
SendIP string `yaml:"SendIP"`
|
XrayOptions XrayOptions `yaml:"XrayOptions"`
|
||||||
XrayOptions XrayOptions `yaml:"XrayOptions"`
|
HyOptions HyOptions `yaml:"HyOptions"`
|
||||||
HyOptions HyOptions `yaml:"HyOptions"`
|
LimitConfig LimitConfig `yaml:"LimitConfig"`
|
||||||
LimitConfig LimitConfig `yaml:"LimitConfig"`
|
CertConfig *CertConfig `yaml:"CertConfig"`
|
||||||
CertConfig *CertConfig `yaml:"CertConfig"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type XrayOptions struct {
|
type XrayOptions struct {
|
||||||
EnableProxyProtocol bool `yaml:"EnableProxyProtocol"`
|
EnableDNS bool `yaml:"EnableDNS"`
|
||||||
EnableDNS bool `yaml:"EnableDNS"`
|
DNSType string `yaml:"DNSType"`
|
||||||
DNSType string `yaml:"DNSType"`
|
EnableVless bool `yaml:"EnableVless"`
|
||||||
EnableVless bool `yaml:"EnableVless"`
|
VlessFlow string `json:"VlessFlow"`
|
||||||
EnableXtls bool `yaml:"EnableXtls"`
|
EnableUot bool `yaml:"EnableUot"`
|
||||||
EnableUot bool `yaml:"EnableUot"`
|
EnableTFO bool `yaml:"EnableTFO"`
|
||||||
EnableTFO bool `yaml:"EnableTFO"`
|
DisableIVCheck bool `yaml:"DisableIVCheck"`
|
||||||
DisableIVCheck bool `yaml:"DisableIVCheck"`
|
DisableSniffing bool `yaml:"DisableSniffing"`
|
||||||
DisableSniffing bool `yaml:"DisableSniffing"`
|
EnableFallback bool `yaml:"EnableFallback"`
|
||||||
EnableFallback bool `yaml:"EnableFallback"`
|
FallBackConfigs []FallBackConfig `yaml:"FallBackConfigs"`
|
||||||
FallBackConfigs []FallBackConfig `yaml:"FallBackConfigs"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type HyOptions struct {
|
type HyOptions struct {
|
||||||
@ -105,12 +103,12 @@ type CertConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RealityConfig struct {
|
type RealityConfig struct {
|
||||||
Dest interface{} `yaml:"Dest"`
|
Dest interface{} `yaml:"Dest" json:"Dest"`
|
||||||
Xver uint64 `yaml:"Xver"`
|
Xver uint64 `yaml:"Xver" json:"Xver"`
|
||||||
ServerNames []string `yaml:"ServerNames"`
|
ServerNames []string `yaml:"ServerNames" json:"ServerNames"`
|
||||||
PrivateKey string `yaml:"PrivateKey"`
|
PrivateKey string `yaml:"PrivateKey" json:"PrivateKey"`
|
||||||
MinClientVer string `yaml:"MinClientVer"`
|
MinClientVer string `yaml:"MinClientVer" json:"MinClientVer"`
|
||||||
MaxClientVer string `yaml:"MaxClientVer"`
|
MaxClientVer string `yaml:"MaxClientVer" json:"MaxClientVer"`
|
||||||
MaxTimeDiff uint64 `yaml:"MaxTimeDiff"`
|
MaxTimeDiff uint64 `yaml:"MaxTimeDiff" json:"MaxTimeDiff"`
|
||||||
ShortIds []string `yaml:"ShortIds"`
|
ShortIds []string `yaml:"ShortIds" json:"ShortIds"`
|
||||||
}
|
}
|
||||||
|
52
conf/watch.go
Normal file
52
conf/watch.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package conf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/fsnotify/fsnotify"
|
||||||
|
"log"
|
||||||
|
"path"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *Conf) Watch(filePath string, reload func()) error {
|
||||||
|
watcher, err := fsnotify.NewWatcher()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("new watcher error: %s", err)
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
var pre time.Time
|
||||||
|
defer watcher.Close()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case e := <-watcher.Events:
|
||||||
|
if e.Has(fsnotify.Chmod) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if pre.Add(10 * time.Second).After(time.Now()) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pre = time.Now()
|
||||||
|
go func() {
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
log.Println("config dir changed, reloading...")
|
||||||
|
*p = *New()
|
||||||
|
err := p.LoadFromPath(filePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("reload config error: %s", err)
|
||||||
|
}
|
||||||
|
reload()
|
||||||
|
log.Println("reload config success")
|
||||||
|
}()
|
||||||
|
case err := <-watcher.Errors:
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("File watcher error: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
err = watcher.Add(path.Dir(filePath))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("watch file error: %s", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -26,7 +26,7 @@ func NewCore(c *conf.CoreConfig) (Core, error) {
|
|||||||
}
|
}
|
||||||
cs = append(cs, core1)
|
cs = append(cs, core1)
|
||||||
}
|
}
|
||||||
return &Selecter{
|
return &Selector{
|
||||||
cores: cs,
|
cores: cs,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Yuzuki616/V2bX/api/panel"
|
"github.com/Yuzuki616/V2bX/api/panel"
|
||||||
"github.com/Yuzuki616/V2bX/conf"
|
"github.com/Yuzuki616/V2bX/conf"
|
||||||
"github.com/apernet/hysteria/core/cs"
|
"github.com/Yuzuki616/V2bX/limiter"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *Hy) AddNode(tag string, info *panel.NodeInfo, c *conf.ControllerConfig) error {
|
func (h *Hy) AddNode(tag string, info *panel.NodeInfo, c *conf.ControllerConfig) error {
|
||||||
@ -16,8 +16,12 @@ func (h *Hy) AddNode(tag string, info *panel.NodeInfo, c *conf.ControllerConfig)
|
|||||||
case "reality", "none", "":
|
case "reality", "none", "":
|
||||||
return errors.New("hysteria need normal tls cert")
|
return errors.New("hysteria need normal tls cert")
|
||||||
}
|
}
|
||||||
s := NewServer(tag)
|
l, err := limiter.GetLimiter(tag)
|
||||||
err := s.runServer(info, c)
|
if err != nil {
|
||||||
|
return fmt.Errorf("get limiter error: %s", err)
|
||||||
|
}
|
||||||
|
s := NewServer(tag, l)
|
||||||
|
err = s.runServer(info, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("run hy server error: %s", err)
|
return fmt.Errorf("run hy server error: %s", err)
|
||||||
}
|
}
|
||||||
@ -27,7 +31,7 @@ func (h *Hy) AddNode(tag string, info *panel.NodeInfo, c *conf.ControllerConfig)
|
|||||||
|
|
||||||
func (h *Hy) DelNode(tag string) error {
|
func (h *Hy) DelNode(tag string) error {
|
||||||
if s, e := h.servers.Load(tag); e {
|
if s, e := h.servers.Load(tag); e {
|
||||||
err := s.(*cs.Server).Close()
|
err := s.(*Server).Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Yuzuki616/V2bX/api/panel"
|
"github.com/Yuzuki616/V2bX/api/panel"
|
||||||
"github.com/Yuzuki616/V2bX/conf"
|
"github.com/Yuzuki616/V2bX/conf"
|
||||||
|
"github.com/Yuzuki616/V2bX/limiter"
|
||||||
"github.com/apernet/hysteria/core/sockopt"
|
"github.com/apernet/hysteria/core/sockopt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
@ -32,15 +33,17 @@ var serverPacketConnFuncFactoryMap = map[string]pktconns.ServerPacketConnFuncFac
|
|||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
tag string
|
tag string
|
||||||
|
l *limiter.Limiter
|
||||||
counter *UserTrafficCounter
|
counter *UserTrafficCounter
|
||||||
users sync.Map
|
users sync.Map
|
||||||
running atomic.Bool
|
running atomic.Bool
|
||||||
*cs.Server
|
*cs.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(tag string) *Server {
|
func NewServer(tag string, l *limiter.Limiter) *Server {
|
||||||
return &Server{
|
return &Server{
|
||||||
tag: tag,
|
tag: tag,
|
||||||
|
l: l,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,6 +176,9 @@ func (s *Server) runServer(node *panel.NodeInfo, c *conf.ControllerConfig) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) authByUser(addr net.Addr, auth []byte, sSend uint64, sRecv uint64) (bool, string) {
|
func (s *Server) authByUser(addr net.Addr, auth []byte, sSend uint64, sRecv uint64) (bool, string) {
|
||||||
|
if _, r := s.l.CheckLimit(string(auth), addr.String(), false); r {
|
||||||
|
return false, "device limited"
|
||||||
|
}
|
||||||
if _, ok := s.users.Load(string(auth)); ok {
|
if _, ok := s.users.Load(string(auth)); ok {
|
||||||
return true, "Done"
|
return true, "Done"
|
||||||
}
|
}
|
||||||
@ -180,6 +186,7 @@ func (s *Server) authByUser(addr net.Addr, auth []byte, sSend uint64, sRecv uint
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) connectFunc(addr net.Addr, auth []byte, sSend uint64, sRecv uint64) (bool, string) {
|
func (s *Server) connectFunc(addr net.Addr, auth []byte, sSend uint64, sRecv uint64) (bool, string) {
|
||||||
|
s.l.ConnLimiter.AddConnCount(addr.String(), string(auth), false)
|
||||||
ok, msg := s.authByUser(addr, auth, sSend, sRecv)
|
ok, msg := s.authByUser(addr, auth, sSend, sRecv)
|
||||||
if !ok {
|
if !ok {
|
||||||
logrus.WithFields(logrus.Fields{
|
logrus.WithFields(logrus.Fields{
|
||||||
@ -196,6 +203,7 @@ func (s *Server) connectFunc(addr net.Addr, auth []byte, sSend uint64, sRecv uin
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) disconnectFunc(addr net.Addr, auth []byte, err error) {
|
func (s *Server) disconnectFunc(addr net.Addr, auth []byte, err error) {
|
||||||
|
s.l.ConnLimiter.DelConnCount(addr.String(), string(auth))
|
||||||
logrus.WithFields(logrus.Fields{
|
logrus.WithFields(logrus.Fields{
|
||||||
"src": defaultIPMasker.Mask(addr.String()),
|
"src": defaultIPMasker.Mask(addr.String()),
|
||||||
"error": err,
|
"error": err,
|
||||||
|
@ -1,17 +1,23 @@
|
|||||||
package hy
|
package hy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"github.com/Yuzuki616/V2bX/api/panel"
|
"github.com/Yuzuki616/V2bX/api/panel"
|
||||||
"github.com/Yuzuki616/V2bX/conf"
|
"github.com/Yuzuki616/V2bX/conf"
|
||||||
|
"github.com/Yuzuki616/V2bX/limiter"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
"log"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestServer(t *testing.T) {
|
func TestServer(t *testing.T) {
|
||||||
logrus.SetLevel(logrus.DebugLevel)
|
logrus.SetLevel(logrus.DebugLevel)
|
||||||
s := NewServer("test")
|
limiter.Init()
|
||||||
|
l := limiter.AddLimiter("test", &conf.LimitConfig{}, nil)
|
||||||
|
s := NewServer("test", l)
|
||||||
t.Log(s.runServer(&panel.NodeInfo{
|
t.Log(s.runServer(&panel.NodeInfo{
|
||||||
Port: 11415,
|
Port: 1145,
|
||||||
UpMbps: 100,
|
UpMbps: 100,
|
||||||
DownMbps: 100,
|
DownMbps: 100,
|
||||||
HyObfs: "atresssdaaaadd",
|
HyObfs: "atresssdaaaadd",
|
||||||
@ -24,5 +30,13 @@ func TestServer(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
s.users.Store("test1111", struct{}{})
|
s.users.Store("test1111", struct{}{})
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
auth := base64.StdEncoding.EncodeToString([]byte("test1111"))
|
||||||
|
log.Println(auth)
|
||||||
|
log.Println(s.counter.getCounters(auth).UpCounter.Load())
|
||||||
|
}
|
||||||
|
}()
|
||||||
select {}
|
select {}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package hy
|
|||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
|
"github.com/Yuzuki616/V2bX/api/panel"
|
||||||
"github.com/Yuzuki616/V2bX/core"
|
"github.com/Yuzuki616/V2bX/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -23,22 +24,22 @@ func (h *Hy) GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64)
|
|||||||
s := v.(*Server)
|
s := v.(*Server)
|
||||||
auth := base64.StdEncoding.EncodeToString([]byte(uuid))
|
auth := base64.StdEncoding.EncodeToString([]byte(uuid))
|
||||||
up = s.counter.getCounters(auth).UpCounter.Load()
|
up = s.counter.getCounters(auth).UpCounter.Load()
|
||||||
down = s.counter.getCounters(uuid).DownCounter.Load()
|
down = s.counter.getCounters(auth).DownCounter.Load()
|
||||||
if reset {
|
if reset {
|
||||||
s.counter.Reset(uuid)
|
s.counter.Reset(auth)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Hy) DelUsers(users []string, tag string) error {
|
func (h *Hy) DelUsers(users []panel.UserInfo, tag string) error {
|
||||||
v, e := h.servers.Load(tag)
|
v, e := h.servers.Load(tag)
|
||||||
if !e {
|
if !e {
|
||||||
return errors.New("the node is not have")
|
return errors.New("the node is not have")
|
||||||
}
|
}
|
||||||
s := v.(*Server)
|
s := v.(*Server)
|
||||||
for i := range users {
|
for i := range users {
|
||||||
s.users.Delete(users[i])
|
s.users.Delete(users[i].Uuid)
|
||||||
s.counter.Delete(users[i])
|
s.counter.Delete(base64.StdEncoding.EncodeToString([]byte(users[i].Uuid)))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,6 @@ type Core interface {
|
|||||||
DelNode(tag string) error
|
DelNode(tag string) error
|
||||||
AddUsers(p *AddUsersParams) (added int, err error)
|
AddUsers(p *AddUsersParams) (added int, err error)
|
||||||
GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64)
|
GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64)
|
||||||
DelUsers(users []string, tag string) error
|
DelUsers(users []panel.UserInfo, tag string) error
|
||||||
Protocols() []string
|
Protocols() []string
|
||||||
}
|
}
|
||||||
|
@ -9,12 +9,12 @@ import (
|
|||||||
"github.com/hashicorp/go-multierror"
|
"github.com/hashicorp/go-multierror"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Selecter struct {
|
type Selector struct {
|
||||||
cores []Core
|
cores []Core
|
||||||
nodes sync.Map
|
nodes sync.Map
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Selecter) Start() error {
|
func (s *Selector) Start() error {
|
||||||
for i := range s.cores {
|
for i := range s.cores {
|
||||||
err := s.cores[i].Start()
|
err := s.cores[i].Start()
|
||||||
return err
|
return err
|
||||||
@ -22,7 +22,7 @@ func (s *Selecter) Start() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Selecter) Close() error {
|
func (s *Selector) Close() error {
|
||||||
var errs error
|
var errs error
|
||||||
for i := range s.cores {
|
for i := range s.cores {
|
||||||
errs = multierror.Append(errs, s.cores[i].Close())
|
errs = multierror.Append(errs, s.cores[i].Close())
|
||||||
@ -39,7 +39,7 @@ func isSupported(protocol string, protocols []string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Selecter) AddNode(tag string, info *panel.NodeInfo, config *conf.ControllerConfig) error {
|
func (s *Selector) AddNode(tag string, info *panel.NodeInfo, config *conf.ControllerConfig) error {
|
||||||
for i := range s.cores {
|
for i := range s.cores {
|
||||||
if !isSupported(info.Type, s.cores[i].Protocols()) {
|
if !isSupported(info.Type, s.cores[i].Protocols()) {
|
||||||
continue
|
continue
|
||||||
@ -53,7 +53,7 @@ func (s *Selecter) AddNode(tag string, info *panel.NodeInfo, config *conf.Contro
|
|||||||
return errors.New("the node type is not support")
|
return errors.New("the node type is not support")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Selecter) DelNode(tag string) error {
|
func (s *Selector) DelNode(tag string) error {
|
||||||
if t, e := s.nodes.Load(tag); e {
|
if t, e := s.nodes.Load(tag); e {
|
||||||
err := s.cores[t.(int)].DelNode(tag)
|
err := s.cores[t.(int)].DelNode(tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -65,7 +65,7 @@ func (s *Selecter) DelNode(tag string) error {
|
|||||||
return errors.New("the node is not have")
|
return errors.New("the node is not have")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Selecter) AddUsers(p *AddUsersParams) (added int, err error) {
|
func (s *Selector) AddUsers(p *AddUsersParams) (added int, err error) {
|
||||||
t, e := s.nodes.Load(p.Tag)
|
t, e := s.nodes.Load(p.Tag)
|
||||||
if !e {
|
if !e {
|
||||||
return 0, errors.New("the node is not have")
|
return 0, errors.New("the node is not have")
|
||||||
@ -73,7 +73,7 @@ func (s *Selecter) AddUsers(p *AddUsersParams) (added int, err error) {
|
|||||||
return s.cores[t.(int)].AddUsers(p)
|
return s.cores[t.(int)].AddUsers(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Selecter) GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64) {
|
func (s *Selector) GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64) {
|
||||||
t, e := s.nodes.Load(tag)
|
t, e := s.nodes.Load(tag)
|
||||||
if !e {
|
if !e {
|
||||||
return 0, 0
|
return 0, 0
|
||||||
@ -81,7 +81,7 @@ func (s *Selecter) GetUserTraffic(tag, uuid string, reset bool) (up int64, down
|
|||||||
return s.cores[t.(int)].GetUserTraffic(tag, uuid, reset)
|
return s.cores[t.(int)].GetUserTraffic(tag, uuid, reset)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Selecter) DelUsers(users []string, tag string) error {
|
func (s *Selector) DelUsers(users []panel.UserInfo, tag string) error {
|
||||||
t, e := s.nodes.Load(tag)
|
t, e := s.nodes.Load(tag)
|
||||||
if !e {
|
if !e {
|
||||||
return errors.New("the node is not have")
|
return errors.New("the node is not have")
|
||||||
@ -89,7 +89,7 @@ func (s *Selecter) DelUsers(users []string, tag string) error {
|
|||||||
return s.cores[t.(int)].DelUsers(users, tag)
|
return s.cores[t.(int)].DelUsers(users, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Selecter) Protocols() []string {
|
func (s *Selector) Protocols() []string {
|
||||||
protocols := make([]string, 0)
|
protocols := make([]string, 0)
|
||||||
for i := range s.cores {
|
for i := range s.cores {
|
||||||
protocols = append(protocols, s.cores[i].Protocols()...)
|
protocols = append(protocols, s.cores[i].Protocols()...)
|
@ -21,7 +21,7 @@ import (
|
|||||||
_ "github.com/xtls/xray-core/app/dns"
|
_ "github.com/xtls/xray-core/app/dns"
|
||||||
_ "github.com/xtls/xray-core/app/dns/fakedns"
|
_ "github.com/xtls/xray-core/app/dns/fakedns"
|
||||||
_ "github.com/xtls/xray-core/app/log"
|
_ "github.com/xtls/xray-core/app/log"
|
||||||
_ "github.com/xtls/xray-core/app/metrics"
|
//_ "github.com/xtls/xray-core/app/metrics"
|
||||||
_ "github.com/xtls/xray-core/app/policy"
|
_ "github.com/xtls/xray-core/app/policy"
|
||||||
_ "github.com/xtls/xray-core/app/reverse"
|
_ "github.com/xtls/xray-core/app/reverse"
|
||||||
_ "github.com/xtls/xray-core/app/router"
|
_ "github.com/xtls/xray-core/app/router"
|
||||||
|
@ -3,7 +3,7 @@ package xray
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/Yuzuki616/V2bX/api/panel"
|
||||||
"github.com/Yuzuki616/V2bX/common/builder"
|
"github.com/Yuzuki616/V2bX/common/builder"
|
||||||
vCore "github.com/Yuzuki616/V2bX/core"
|
vCore "github.com/Yuzuki616/V2bX/core"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
@ -26,16 +26,22 @@ func (c *Core) GetUserManager(tag string) (proxy.UserManager, error) {
|
|||||||
return userManager, nil
|
return userManager, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) DelUsers(users []string, tag string) error {
|
func (c *Core) DelUsers(users []panel.UserInfo, tag string) error {
|
||||||
userManager, err := c.GetUserManager(tag)
|
userManager, err := c.GetUserManager(tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("get user manager error: %s", err)
|
return fmt.Errorf("get user manager error: %s", err)
|
||||||
}
|
}
|
||||||
for _, email := range users {
|
var up, down, user string
|
||||||
err = userManager.RemoveUser(context.Background(), email)
|
for i := range users {
|
||||||
|
user = builder.BuildUserTag(tag, users[i].Uuid)
|
||||||
|
err = userManager.RemoveUser(context.Background(), user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
up = "user>>>" + user + ">>>traffic>>>uplink"
|
||||||
|
down = "user>>>" + user + ">>>traffic>>>downlink"
|
||||||
|
c.shm.UnregisterCounter(up)
|
||||||
|
c.shm.UnregisterCounter(down)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -67,11 +73,22 @@ func (c *Core) AddUsers(p *vCore.AddUsersParams) (added int, err error) {
|
|||||||
users := make([]*protocol.User, 0, len(p.UserInfo))
|
users := make([]*protocol.User, 0, len(p.UserInfo))
|
||||||
switch p.NodeInfo.Type {
|
switch p.NodeInfo.Type {
|
||||||
case "v2ray":
|
case "v2ray":
|
||||||
if p.Config.XrayOptions.EnableXtls {
|
if p.Config.XrayOptions.EnableVless ||
|
||||||
users = builder.BuildVlessUsers(p.Tag, p.UserInfo, true)
|
p.NodeInfo.ExtraConfig.EnableVless {
|
||||||
|
if p.Config.XrayOptions.VlessFlow != "" {
|
||||||
|
if p.Config.XrayOptions.VlessFlow == p.NodeInfo.ExtraConfig.VlessFlow {
|
||||||
|
users = builder.BuildVlessUsers(p.Tag, p.UserInfo, p.Config.XrayOptions.VlessFlow)
|
||||||
|
} else {
|
||||||
|
users = builder.BuildVlessUsers(p.Tag, p.UserInfo, p.NodeInfo.ExtraConfig.VlessFlow)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
users = builder.BuildVlessUsers(p.Tag, p.UserInfo, p.NodeInfo.ExtraConfig.VlessFlow)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
users = builder.BuildVmessUsers(p.Tag, p.UserInfo)
|
users = builder.BuildVmessUsers(p.Tag, p.UserInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
case "trojan":
|
case "trojan":
|
||||||
users = builder.BuildTrojanUsers(p.Tag, p.UserInfo)
|
users = builder.BuildTrojanUsers(p.Tag, p.UserInfo)
|
||||||
case "shadowsocks":
|
case "shadowsocks":
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package xray
|
package xray
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@ -10,6 +9,7 @@ import (
|
|||||||
"github.com/Yuzuki616/V2bX/core/xray/app/dispatcher"
|
"github.com/Yuzuki616/V2bX/core/xray/app/dispatcher"
|
||||||
_ "github.com/Yuzuki616/V2bX/core/xray/distro/all"
|
_ "github.com/Yuzuki616/V2bX/core/xray/distro/all"
|
||||||
"github.com/goccy/go-json"
|
"github.com/goccy/go-json"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/xtls/xray-core/app/proxyman"
|
"github.com/xtls/xray-core/app/proxyman"
|
||||||
"github.com/xtls/xray-core/app/stats"
|
"github.com/xtls/xray-core/app/stats"
|
||||||
"github.com/xtls/xray-core/common/serial"
|
"github.com/xtls/xray-core/common/serial"
|
||||||
@ -63,40 +63,40 @@ func getCore(c *conf.XrayConfig) *core.Instance {
|
|||||||
coreDnsConfig := &coreConf.DNSConfig{}
|
coreDnsConfig := &coreConf.DNSConfig{}
|
||||||
if c.DnsConfigPath != "" {
|
if c.DnsConfigPath != "" {
|
||||||
if f, err := os.Open(c.DnsConfigPath); err != nil {
|
if f, err := os.Open(c.DnsConfigPath); err != nil {
|
||||||
log.Panicf("Failed to read DNS config file at: %s", c.DnsConfigPath)
|
log.WithField("err", err).Panic("Failed to read DNS config file")
|
||||||
} else {
|
} else {
|
||||||
if err = json.NewDecoder(f).Decode(coreDnsConfig); err != nil {
|
if err = json.NewDecoder(f).Decode(coreDnsConfig); err != nil {
|
||||||
log.Panicf("Failed to unmarshal DNS config: %s", c.DnsConfigPath)
|
log.WithField("err", err).Panic("Failed to unmarshal DNS config")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dnsConfig, err := coreDnsConfig.Build()
|
dnsConfig, err := coreDnsConfig.Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panicf("Failed to understand DNS config, Please check: https://xtls.github.io/config/dns.html for help: %s", err)
|
log.WithField("err", err).Panic("Failed to understand DNS config, Please check: https://xtls.github.io/config/dns.html for help")
|
||||||
}
|
}
|
||||||
// Routing config
|
// Routing config
|
||||||
coreRouterConfig := &coreConf.RouterConfig{}
|
coreRouterConfig := &coreConf.RouterConfig{}
|
||||||
if c.RouteConfigPath != "" {
|
if c.RouteConfigPath != "" {
|
||||||
if f, err := os.Open(c.RouteConfigPath); err != nil {
|
if f, err := os.Open(c.RouteConfigPath); err != nil {
|
||||||
log.Panicf("Failed to read Routing config file at: %s", c.RouteConfigPath)
|
log.WithField("err", err).Panic("Failed to read Routing config file")
|
||||||
} else {
|
} else {
|
||||||
if err = json.NewDecoder(f).Decode(coreRouterConfig); err != nil {
|
if err = json.NewDecoder(f).Decode(coreRouterConfig); err != nil {
|
||||||
log.Panicf("Failed to unmarshal Routing config: %s", c.RouteConfigPath)
|
log.WithField("err", err).Panic("Failed to unmarshal Routing config")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
routeConfig, err := coreRouterConfig.Build()
|
routeConfig, err := coreRouterConfig.Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panicf("Failed to understand Routing config Please check: https://xtls.github.io/config/routing.html for help: %s", err)
|
log.WithField("err", err).Panic("Failed to understand Routing config Please check: https://xtls.github.io/config/routing.html")
|
||||||
}
|
}
|
||||||
// Custom Inbound config
|
// Custom Inbound config
|
||||||
var coreCustomInboundConfig []coreConf.InboundDetourConfig
|
var coreCustomInboundConfig []coreConf.InboundDetourConfig
|
||||||
if c.InboundConfigPath != "" {
|
if c.InboundConfigPath != "" {
|
||||||
if f, err := os.Open(c.InboundConfigPath); err != nil {
|
if f, err := os.Open(c.InboundConfigPath); err != nil {
|
||||||
log.Panicf("Failed to read Custom Inbound config file at: %s", c.OutboundConfigPath)
|
log.WithField("err", err).Panic("Failed to read Custom Inbound config file")
|
||||||
} else {
|
} else {
|
||||||
if err = json.NewDecoder(f).Decode(&coreCustomInboundConfig); err != nil {
|
if err = json.NewDecoder(f).Decode(&coreCustomInboundConfig); err != nil {
|
||||||
log.Panicf("Failed to unmarshal Custom Inbound config: %s", c.OutboundConfigPath)
|
log.WithField("err", err).Panic("Failed to unmarshal Custom Inbound config")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,7 +104,7 @@ func getCore(c *conf.XrayConfig) *core.Instance {
|
|||||||
for _, config := range coreCustomInboundConfig {
|
for _, config := range coreCustomInboundConfig {
|
||||||
oc, err := config.Build()
|
oc, err := config.Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panicf("Failed to understand Inbound config, Please check: https://xtls.github.io/config/inbound.html for help: %s", err)
|
log.WithField("err", err).Panic("Failed to understand Inbound config, Please check: https://xtls.github.io/config/inbound.html for help")
|
||||||
}
|
}
|
||||||
inBoundConfig = append(inBoundConfig, oc)
|
inBoundConfig = append(inBoundConfig, oc)
|
||||||
}
|
}
|
||||||
@ -112,10 +112,10 @@ func getCore(c *conf.XrayConfig) *core.Instance {
|
|||||||
var coreCustomOutboundConfig []coreConf.OutboundDetourConfig
|
var coreCustomOutboundConfig []coreConf.OutboundDetourConfig
|
||||||
if c.OutboundConfigPath != "" {
|
if c.OutboundConfigPath != "" {
|
||||||
if f, err := os.Open(c.OutboundConfigPath); err != nil {
|
if f, err := os.Open(c.OutboundConfigPath); err != nil {
|
||||||
log.Panicf("Failed to read Custom Outbound config file at: %s", c.OutboundConfigPath)
|
log.WithField("err", err).Panic("Failed to read Custom Outbound config file")
|
||||||
} else {
|
} else {
|
||||||
if err = json.NewDecoder(f).Decode(&coreCustomOutboundConfig); err != nil {
|
if err = json.NewDecoder(f).Decode(&coreCustomOutboundConfig); err != nil {
|
||||||
log.Panicf("Failed to unmarshal Custom Outbound config: %s", c.OutboundConfigPath)
|
log.WithField("err", err).Panic("Failed to unmarshal Custom Outbound config")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,7 +123,7 @@ func getCore(c *conf.XrayConfig) *core.Instance {
|
|||||||
for _, config := range coreCustomOutboundConfig {
|
for _, config := range coreCustomOutboundConfig {
|
||||||
oc, err := config.Build()
|
oc, err := config.Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panicf("Failed to understand Outbound config, Please check: https://xtls.github.io/config/outbound.html for help: %s", err)
|
log.WithField("err", err).Panic("Failed to understand Outbound config, Please check: https://xtls.github.io/config/outbound.html for help")
|
||||||
}
|
}
|
||||||
outBoundConfig = append(outBoundConfig, oc)
|
outBoundConfig = append(outBoundConfig, oc)
|
||||||
}
|
}
|
||||||
@ -149,10 +149,9 @@ func getCore(c *conf.XrayConfig) *core.Instance {
|
|||||||
}
|
}
|
||||||
server, err := core.New(config)
|
server, err := core.New(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panicf("failed to create instance: %s", err)
|
log.WithField("err", err).Panic("failed to create instance")
|
||||||
}
|
}
|
||||||
log.Printf("Core Version: %s", core.Version())
|
log.Info("Xray Core Version: ", core.Version())
|
||||||
|
|
||||||
return server
|
return server
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
CoreConfig:
|
CoreConfig:
|
||||||
Type: "xray" # Core type. if you need many cores, use " " to split
|
Type: "xray" # Core type, default support "xray" and "hy". If you need many cores, use " " to split
|
||||||
XrayConfig:
|
XrayConfig:
|
||||||
Log:
|
Log:
|
||||||
Level: warning # Log level: none, error, warning, info, debug
|
Level: warning # Log level: none, error, warning, info, debug
|
||||||
@ -31,7 +31,7 @@ Nodes:
|
|||||||
DNSType: AsIs # AsIs, UseIP, UseIPv4, UseIPv6, DNS strategy
|
DNSType: AsIs # AsIs, UseIP, UseIPv4, UseIPv6, DNS strategy
|
||||||
EnableTFO: false # Enable TCP Fast Open
|
EnableTFO: false # Enable TCP Fast Open
|
||||||
EnableVless: false # Enable Vless for V2ray Type
|
EnableVless: false # Enable Vless for V2ray Type
|
||||||
EnableXtls: false # Enable xtls-rprx-vision, only vless
|
VlessFlow: "xtls-rprx-vision" # flow for vless, "xtls-rprx-vision" or "none" or ""
|
||||||
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
|
||||||
@ -39,7 +39,7 @@ Nodes:
|
|||||||
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 disable
|
||||||
HyOptions:
|
HyOptions:
|
||||||
Resolver: "udp://1.1.1.1:53" # DNS resolver address
|
Resolver: "udp://1.1.1.1:53" # DNS resolver address
|
||||||
ResolvePreference: 64 # DNS IPv4/IPv6 preference. Available options: "64" (IPv6 first, fallback to IPv4), "46" (IPv4 first, fallback to IPv6), "6" (IPv6 only), "4" (IPv4 only)
|
ResolvePreference: 64 # DNS IPv4/IPv6 preference. Available options: "64" (IPv6 first, fallback to IPv4), "46" (IPv4 first, fallback to IPv6), "6" (IPv6 only), "4" (IPv4 only)
|
||||||
|
20
go.mod
20
go.mod
@ -3,23 +3,23 @@ module github.com/Yuzuki616/V2bX
|
|||||||
go 1.20
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/apernet/hysteria/core v1.3.4
|
github.com/apernet/hysteria/core v1.3.5
|
||||||
github.com/beevik/ntp v1.0.0
|
github.com/beevik/ntp v1.1.1
|
||||||
github.com/folbricht/routedns v0.1.21-0.20230220022436-4ae86ce30d53
|
github.com/folbricht/routedns v0.1.21-0.20230220022436-4ae86ce30d53
|
||||||
github.com/fsnotify/fsnotify v1.6.0
|
github.com/fsnotify/fsnotify v1.6.0
|
||||||
github.com/go-acme/lego/v4 v4.12.1
|
github.com/go-acme/lego/v4 v4.12.3
|
||||||
github.com/go-redis/redis/v8 v8.11.5
|
github.com/go-redis/redis/v8 v8.11.5
|
||||||
github.com/go-resty/resty/v2 v2.7.0
|
github.com/go-resty/resty/v2 v2.7.0
|
||||||
github.com/goccy/go-json v0.10.2
|
github.com/goccy/go-json v0.10.2
|
||||||
github.com/hashicorp/go-multierror v1.1.1
|
github.com/hashicorp/go-multierror v1.1.1
|
||||||
github.com/juju/ratelimit v1.0.2
|
github.com/juju/ratelimit v1.0.2
|
||||||
github.com/oschwald/geoip2-golang v1.8.0
|
github.com/oschwald/geoip2-golang v1.9.0
|
||||||
github.com/quic-go/quic-go v0.33.0
|
github.com/quic-go/quic-go v0.34.0
|
||||||
github.com/sagernet/sing-box v1.2.7
|
github.com/sagernet/sing-box v1.2.7
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
github.com/spf13/cobra v1.7.0
|
github.com/spf13/cobra v1.7.0
|
||||||
github.com/xtls/xray-core v1.8.1
|
github.com/xtls/xray-core v1.8.1
|
||||||
golang.org/x/crypto v0.9.0
|
golang.org/x/crypto v0.10.0
|
||||||
google.golang.org/protobuf v1.30.0
|
google.golang.org/protobuf v1.30.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
@ -121,7 +121,7 @@ require (
|
|||||||
github.com/nrdcg/porkbun v0.1.1 // indirect
|
github.com/nrdcg/porkbun v0.1.1 // indirect
|
||||||
github.com/onsi/ginkgo/v2 v2.9.2 // indirect
|
github.com/onsi/ginkgo/v2 v2.9.2 // indirect
|
||||||
github.com/oracle/oci-go-sdk v24.3.0+incompatible // indirect
|
github.com/oracle/oci-go-sdk v24.3.0+incompatible // indirect
|
||||||
github.com/oschwald/maxminddb-golang v1.10.0 // indirect
|
github.com/oschwald/maxminddb-golang v1.11.0 // indirect
|
||||||
github.com/ovh/go-ovh v1.1.0 // indirect
|
github.com/ovh/go-ovh v1.1.0 // indirect
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||||
github.com/pion/dtls/v2 v2.2.4 // indirect
|
github.com/pion/dtls/v2 v2.2.4 // indirect
|
||||||
@ -158,7 +158,7 @@ require (
|
|||||||
github.com/spf13/cast v1.5.0 // indirect
|
github.com/spf13/cast v1.5.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/stretchr/objx v0.5.0 // indirect
|
github.com/stretchr/objx v0.5.0 // indirect
|
||||||
github.com/stretchr/testify v1.8.3 // indirect
|
github.com/stretchr/testify v1.8.4 // indirect
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.490 // indirect
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.490 // indirect
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.490 // indirect
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.490 // indirect
|
||||||
github.com/transip/gotransip/v6 v6.17.0 // indirect
|
github.com/transip/gotransip/v6 v6.17.0 // indirect
|
||||||
@ -181,8 +181,8 @@ require (
|
|||||||
golang.org/x/mod v0.10.0 // indirect
|
golang.org/x/mod v0.10.0 // indirect
|
||||||
golang.org/x/net v0.10.0 // indirect
|
golang.org/x/net v0.10.0 // indirect
|
||||||
golang.org/x/oauth2 v0.6.0 // indirect
|
golang.org/x/oauth2 v0.6.0 // indirect
|
||||||
golang.org/x/sys v0.8.0 // indirect
|
golang.org/x/sys v0.9.0 // indirect
|
||||||
golang.org/x/text v0.9.0 // indirect
|
golang.org/x/text v0.10.0 // indirect
|
||||||
golang.org/x/time v0.3.0 // indirect
|
golang.org/x/time v0.3.0 // indirect
|
||||||
golang.org/x/tools v0.8.0 // indirect
|
golang.org/x/tools v0.8.0 // indirect
|
||||||
google.golang.org/api v0.114.0 // indirect
|
google.golang.org/api v0.114.0 // indirect
|
||||||
|
41
go.sum
41
go.sum
@ -67,8 +67,8 @@ github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/
|
|||||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||||
github.com/apernet/hysteria/core v1.3.4 h1:i5EqGIf7FZqwsOrT7PagLQeh+P5gHfLkDZWn7/pXUjo=
|
github.com/apernet/hysteria/core v1.3.5 h1:Pg7w7rcdXhkGUJoG3ALpT9waz+ZmWpIpD5QqJe8MbuI=
|
||||||
github.com/apernet/hysteria/core v1.3.4/go.mod h1:WxFihvoDBhatefn4w8Lipzy97CWjK6NF1/duT0kGUG0=
|
github.com/apernet/hysteria/core v1.3.5/go.mod h1:7jmeIvXeTaRDuXvK6suvxYq65E4erdi3nEkKy9Qusj4=
|
||||||
github.com/apernet/quic-go v0.34.1-0.20230507231629-ec008b7e8473 h1:3KFetJ/lUFn0m9xTFg+rMmz2nyHg+D2boJX0Rp4OF6c=
|
github.com/apernet/quic-go v0.34.1-0.20230507231629-ec008b7e8473 h1:3KFetJ/lUFn0m9xTFg+rMmz2nyHg+D2boJX0Rp4OF6c=
|
||||||
github.com/apernet/quic-go v0.34.1-0.20230507231629-ec008b7e8473/go.mod h1:+4CVgVppm0FNjpG3UcX8Joi/frKOH7/ciD5yGcwOO1g=
|
github.com/apernet/quic-go v0.34.1-0.20230507231629-ec008b7e8473/go.mod h1:+4CVgVppm0FNjpG3UcX8Joi/frKOH7/ciD5yGcwOO1g=
|
||||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||||
@ -76,8 +76,8 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
|
|||||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
github.com/aws/aws-sdk-go v1.39.0 h1:74BBwkEmiqBbi2CGflEh34l0YNtIibTjZsibGarkNjo=
|
github.com/aws/aws-sdk-go v1.39.0 h1:74BBwkEmiqBbi2CGflEh34l0YNtIibTjZsibGarkNjo=
|
||||||
github.com/aws/aws-sdk-go v1.39.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
github.com/aws/aws-sdk-go v1.39.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||||
github.com/beevik/ntp v1.0.0 h1:d0Lgy1xbNNqVyGfvg2Z96ItKcfyn3lzgus/oRoj9vnk=
|
github.com/beevik/ntp v1.1.1 h1:ah1SrQMwiyL8eRpb7+Erm7l4PvXnZ/Dnh/gjGZXPvp0=
|
||||||
github.com/beevik/ntp v1.0.0/go.mod h1:JN7/74B0Z4GUGO/1aUeRI2adARlfJGUeaJb0y0Wvnf4=
|
github.com/beevik/ntp v1.1.1/go.mod h1:br1ZC24XiJQWuIUdrmQT3Bf5jQXIOLaPT+MoAK9Vlk0=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
@ -176,8 +176,8 @@ github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH
|
|||||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
|
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
|
||||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||||
github.com/go-acme/lego/v4 v4.12.1 h1:Cy3FS7wADLNBqCLpz2wdfdNrThW9rZy8RCAfnUrL2uE=
|
github.com/go-acme/lego/v4 v4.12.3 h1:aWPYhBopAZXWBASPgvi1LnWGrr5YiXOsrpVaFaVJipo=
|
||||||
github.com/go-acme/lego/v4 v4.12.1/go.mod h1:UZoOlhVmUYP/N0z4tEbfUjoCNHRZNObzqWZtT76DIsc=
|
github.com/go-acme/lego/v4 v4.12.3/go.mod h1:UZoOlhVmUYP/N0z4tEbfUjoCNHRZNObzqWZtT76DIsc=
|
||||||
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
|
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
|
||||||
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
|
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
|
||||||
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
||||||
@ -519,10 +519,10 @@ github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E=
|
|||||||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||||
github.com/oracle/oci-go-sdk v24.3.0+incompatible h1:x4mcfb4agelf1O4/1/auGlZ1lr97jXRSSN5MxTgG/zU=
|
github.com/oracle/oci-go-sdk v24.3.0+incompatible h1:x4mcfb4agelf1O4/1/auGlZ1lr97jXRSSN5MxTgG/zU=
|
||||||
github.com/oracle/oci-go-sdk v24.3.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
|
github.com/oracle/oci-go-sdk v24.3.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
|
||||||
github.com/oschwald/geoip2-golang v1.8.0 h1:KfjYB8ojCEn/QLqsDU0AzrJ3R5Qa9vFlx3z6SLNcKTs=
|
github.com/oschwald/geoip2-golang v1.9.0 h1:uvD3O6fXAXs+usU+UGExshpdP13GAqp4GBrzN7IgKZc=
|
||||||
github.com/oschwald/geoip2-golang v1.8.0/go.mod h1:R7bRvYjOeaoenAp9sKRS8GX5bJWcZ0laWO5+DauEktw=
|
github.com/oschwald/geoip2-golang v1.9.0/go.mod h1:BHK6TvDyATVQhKNbQBdrj9eAvuwOMi2zSFXizL3K81Y=
|
||||||
github.com/oschwald/maxminddb-golang v1.10.0 h1:Xp1u0ZhqkSuopaKmk1WwHtjF0H9Hd9181uj2MQ5Vndg=
|
github.com/oschwald/maxminddb-golang v1.11.0 h1:aSXMqYR/EPNjGE8epgqwDay+P30hCBZIveY0WZbAWh0=
|
||||||
github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYxHV1dLIxBuyOsyYjHK0=
|
github.com/oschwald/maxminddb-golang v1.11.0/go.mod h1:YmVI+H0zh3ySFR3w+oz8PCfglAFj3PuCmui13+P9zDg=
|
||||||
github.com/ovh/go-ovh v1.1.0 h1:bHXZmw8nTgZin4Nv7JuaLs0KG5x54EQR7migYTd1zrk=
|
github.com/ovh/go-ovh v1.1.0 h1:bHXZmw8nTgZin4Nv7JuaLs0KG5x54EQR7migYTd1zrk=
|
||||||
github.com/ovh/go-ovh v1.1.0/go.mod h1:AxitLZ5HBRPyUd+Zl60Ajaag+rNTdVXWIkzfrVuTXWA=
|
github.com/ovh/go-ovh v1.1.0/go.mod h1:AxitLZ5HBRPyUd+Zl60Ajaag+rNTdVXWIkzfrVuTXWA=
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
@ -697,9 +697,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.490 h1:mmz27tVi2r70JYnm5y0Zk8w0Qzsx+vfUw3oqSyrEfP8=
|
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.490 h1:mmz27tVi2r70JYnm5y0Zk8w0Qzsx+vfUw3oqSyrEfP8=
|
||||||
@ -788,8 +787,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
|
|||||||
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
||||||
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
|
||||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
@ -857,7 +856,6 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
|
|||||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
|
||||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
@ -937,9 +935,9 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
||||||
|
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
@ -947,8 +945,8 @@ golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuX
|
|||||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
|
golang.org/x/term v0.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
@ -960,8 +958,9 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
|||||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
|
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
|
||||||
|
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
package limiter
|
package limiter
|
||||||
|
|
||||||
import "log"
|
import log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
func ClearOnlineIP() error {
|
func ClearOnlineIP() error {
|
||||||
log.Println("Limiter: Clear online ip...")
|
log.WithField("Type", "Limiter").
|
||||||
|
Debug("Clear online ip...")
|
||||||
limitLock.RLock()
|
limitLock.RLock()
|
||||||
for _, l := range limiter {
|
for _, l := range limiter {
|
||||||
l.ConnLimiter.ClearOnlineIP()
|
l.ConnLimiter.ClearOnlineIP()
|
||||||
}
|
}
|
||||||
limitLock.RUnlock()
|
limitLock.RUnlock()
|
||||||
log.Println("Limiter: Clear online ip done")
|
log.WithField("Type", "Limiter").
|
||||||
|
Debug("Clear online ip done")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package limiter
|
package limiter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/Yuzuki616/V2bX/api/panel"
|
"github.com/Yuzuki616/V2bX/api/panel"
|
||||||
|
"github.com/Yuzuki616/V2bX/common/builder"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ func (l *Limiter) AddDynamicSpeedLimit(tag string, userInfo *panel.UserInfo, lim
|
|||||||
DynamicSpeedLimit: limitNum,
|
DynamicSpeedLimit: limitNum,
|
||||||
ExpireTime: time.Now().Add(time.Duration(expire) * time.Second).Unix(),
|
ExpireTime: time.Now().Add(time.Duration(expire) * time.Second).Unix(),
|
||||||
}
|
}
|
||||||
l.UserLimitInfo.Store(fmt.Sprintf("%s|%s|%d", tag, userInfo.Uuid, userInfo.Id), userLimit)
|
l.UserLimitInfo.Store(builder.BuildUserTag(tag, userInfo.Uuid), userLimit)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,8 +7,8 @@ import (
|
|||||||
"github.com/Yuzuki616/V2bX/common/builder"
|
"github.com/Yuzuki616/V2bX/common/builder"
|
||||||
"github.com/Yuzuki616/V2bX/conf"
|
"github.com/Yuzuki616/V2bX/conf"
|
||||||
"github.com/juju/ratelimit"
|
"github.com/juju/ratelimit"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/xtls/xray-core/common/task"
|
"github.com/xtls/xray-core/common/task"
|
||||||
"log"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -24,7 +24,8 @@ func Init() {
|
|||||||
Execute: ClearOnlineIP,
|
Execute: ClearOnlineIP,
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
log.Println("Limiter: ClearOnlineIP started")
|
log.WithField("Type", "Limiter").
|
||||||
|
Debug("ClearOnlineIP started")
|
||||||
time.Sleep(time.Minute * 2)
|
time.Sleep(time.Minute * 2)
|
||||||
_ = c.Start()
|
_ = c.Start()
|
||||||
}()
|
}()
|
||||||
@ -85,10 +86,7 @@ func UpdateLimiter(tag string, added []panel.UserInfo, deleted []panel.UserInfo)
|
|||||||
return fmt.Errorf("get limit error: %s", err)
|
return fmt.Errorf("get limit error: %s", err)
|
||||||
}
|
}
|
||||||
for i := range deleted {
|
for i := range deleted {
|
||||||
l.UserLimitInfo.Delete(fmt.Sprintf("%s|%s|%d",
|
l.UserLimitInfo.Delete(builder.BuildUserTag(tag, deleted[i].Uuid))
|
||||||
tag,
|
|
||||||
deleted[i].Uuid,
|
|
||||||
deleted[i].Id))
|
|
||||||
}
|
}
|
||||||
for i := range added {
|
for i := range added {
|
||||||
if added[i].SpeedLimit != 0 {
|
if added[i].SpeedLimit != 0 {
|
||||||
@ -97,10 +95,7 @@ func UpdateLimiter(tag string, added []panel.UserInfo, deleted []panel.UserInfo)
|
|||||||
SpeedLimit: added[i].SpeedLimit,
|
SpeedLimit: added[i].SpeedLimit,
|
||||||
ExpireTime: 0,
|
ExpireTime: 0,
|
||||||
}
|
}
|
||||||
l.UserLimitInfo.Store(fmt.Sprintf("%s|%s|%d",
|
l.UserLimitInfo.Store(builder.BuildUserTag(tag, added[i].Uuid), userLimit)
|
||||||
tag,
|
|
||||||
added[i].Uuid,
|
|
||||||
added[i].Id), userLimit)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
14
node/cert.go
14
node/cert.go
@ -4,8 +4,22 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Yuzuki616/V2bX/common/file"
|
"github.com/Yuzuki616/V2bX/common/file"
|
||||||
"github.com/Yuzuki616/V2bX/node/lego"
|
"github.com/Yuzuki616/V2bX/node/lego"
|
||||||
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (c *Controller) renewCertTask() {
|
||||||
|
l, err := lego.New(c.CertConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Print("new lego error: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = l.RenewCert()
|
||||||
|
if err != nil {
|
||||||
|
log.Print("renew cert error: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Controller) requestCert() error {
|
func (c *Controller) requestCert() error {
|
||||||
if c.CertConfig.CertFile == "" || c.CertConfig.KeyFile == "" {
|
if c.CertConfig.CertFile == "" || c.CertConfig.KeyFile == "" {
|
||||||
return fmt.Errorf("cert file path or key file path not exist")
|
return fmt.Errorf("cert file path or key file path not exist")
|
||||||
|
@ -3,14 +3,13 @@ package node
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/Yuzuki616/V2bX/api/iprecoder"
|
"github.com/Yuzuki616/V2bX/api/iprecoder"
|
||||||
"github.com/Yuzuki616/V2bX/api/panel"
|
"github.com/Yuzuki616/V2bX/api/panel"
|
||||||
|
"github.com/Yuzuki616/V2bX/common/task"
|
||||||
"github.com/Yuzuki616/V2bX/conf"
|
"github.com/Yuzuki616/V2bX/conf"
|
||||||
vCore "github.com/Yuzuki616/V2bX/core"
|
vCore "github.com/Yuzuki616/V2bX/core"
|
||||||
"github.com/Yuzuki616/V2bX/limiter"
|
"github.com/Yuzuki616/V2bX/limiter"
|
||||||
"github.com/xtls/xray-core/common/task"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Controller struct {
|
type Controller struct {
|
||||||
@ -20,11 +19,11 @@ type Controller struct {
|
|||||||
Tag string
|
Tag string
|
||||||
userList []panel.UserInfo
|
userList []panel.UserInfo
|
||||||
ipRecorder iprecoder.IpRecorder
|
ipRecorder iprecoder.IpRecorder
|
||||||
nodeInfoMonitorPeriodic *task.Periodic
|
nodeInfoMonitorPeriodic *task.Task
|
||||||
userReportPeriodic *task.Periodic
|
userReportPeriodic *task.Task
|
||||||
renewCertPeriodic *task.Periodic
|
renewCertPeriodic *task.Task
|
||||||
dynamicSpeedLimitPeriodic *task.Periodic
|
dynamicSpeedLimitPeriodic *task.Task
|
||||||
onlineIpReportPeriodic *task.Periodic
|
onlineIpReportPeriodic *task.Task
|
||||||
*conf.ControllerConfig
|
*conf.ControllerConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,12 +58,10 @@ func (c *Controller) Start() error {
|
|||||||
// add limiter
|
// add limiter
|
||||||
l := limiter.AddLimiter(c.Tag, &c.LimitConfig, c.userList)
|
l := limiter.AddLimiter(c.Tag, &c.LimitConfig, c.userList)
|
||||||
// add rule limiter
|
// add rule limiter
|
||||||
if !c.DisableGetRule {
|
if err = l.UpdateRule(c.nodeInfo.Rules); err != nil {
|
||||||
if err = l.UpdateRule(c.nodeInfo.Rules); err != nil {
|
return fmt.Errorf("update rule error: %s", err)
|
||||||
return fmt.Errorf("update rule error: %s", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if c.nodeInfo.Tls {
|
if c.nodeInfo.Tls || c.nodeInfo.Type == "hysteria" {
|
||||||
err = c.requestCert()
|
err = c.requestCert()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("request cert error: %s", err)
|
return fmt.Errorf("request cert error: %s", err)
|
||||||
@ -84,7 +81,7 @@ func (c *Controller) Start() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("add users error: %s", err)
|
return fmt.Errorf("add users error: %s", err)
|
||||||
}
|
}
|
||||||
log.Printf("[%s: %d] Added %d new users", c.nodeInfo.Type, c.nodeInfo.Id, added)
|
log.WithField("tag", c.Tag).Infof("Added %d new users", added)
|
||||||
c.initTask()
|
c.initTask()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -93,38 +90,23 @@ func (c *Controller) Start() error {
|
|||||||
func (c *Controller) Close() error {
|
func (c *Controller) Close() error {
|
||||||
limiter.DeleteLimiter(c.Tag)
|
limiter.DeleteLimiter(c.Tag)
|
||||||
if c.nodeInfoMonitorPeriodic != nil {
|
if c.nodeInfoMonitorPeriodic != nil {
|
||||||
err := c.nodeInfoMonitorPeriodic.Close()
|
c.nodeInfoMonitorPeriodic.Close()
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("node info periodic close error: %s", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if c.nodeInfoMonitorPeriodic != nil {
|
if c.userReportPeriodic != nil {
|
||||||
err := c.userReportPeriodic.Close()
|
c.userReportPeriodic.Close()
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("user report periodic close error: %s", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if c.renewCertPeriodic != nil {
|
if c.renewCertPeriodic != nil {
|
||||||
err := c.renewCertPeriodic.Close()
|
c.renewCertPeriodic.Close()
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("renew cert periodic close error: %s", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if c.dynamicSpeedLimitPeriodic != nil {
|
if c.dynamicSpeedLimitPeriodic != nil {
|
||||||
err := c.dynamicSpeedLimitPeriodic.Close()
|
c.dynamicSpeedLimitPeriodic.Close()
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("dynamic speed limit periodic close error: %s", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if c.onlineIpReportPeriodic != nil {
|
if c.onlineIpReportPeriodic != nil {
|
||||||
err := c.onlineIpReportPeriodic.Close()
|
c.onlineIpReportPeriodic.Close()
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("online ip report periodic close error: %s", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) buildNodeTag() string {
|
func (c *Controller) buildNodeTag() string {
|
||||||
return fmt.Sprintf("%s_%s_%d", c.nodeInfo.Type, c.ListenIP, c.nodeInfo.Id)
|
return fmt.Sprintf("%s-%s-%d", c.apiClient.APIHost, c.nodeInfo.Type, c.nodeInfo.Id)
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,8 @@ type Lego struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func New(config *conf.CertConfig) (*Lego, error) {
|
func New(config *conf.CertConfig) (*Lego, error) {
|
||||||
user, err := NewUser(path.Join("/etc/V2bX/cert/user/",
|
user, err := NewUser(path.Join(path.Dir(config.CertFile),
|
||||||
|
"user",
|
||||||
fmt.Sprintf("user-%s.json", config.Email)),
|
fmt.Sprintf("user-%s.json", config.Email)),
|
||||||
config.Email)
|
config.Email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
264
node/task.go
264
node/task.go
@ -1,101 +1,100 @@
|
|||||||
package node
|
package node
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"github.com/Yuzuki616/V2bX/common/task"
|
||||||
"log"
|
|
||||||
"runtime"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
vCore "github.com/Yuzuki616/V2bX/core"
|
vCore "github.com/Yuzuki616/V2bX/core"
|
||||||
|
|
||||||
"github.com/Yuzuki616/V2bX/api/panel"
|
|
||||||
"github.com/Yuzuki616/V2bX/limiter"
|
"github.com/Yuzuki616/V2bX/limiter"
|
||||||
"github.com/Yuzuki616/V2bX/node/lego"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/xtls/xray-core/common/task"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Controller) initTask() {
|
func (c *Controller) initTask() {
|
||||||
// fetch node info task
|
// fetch node info task
|
||||||
c.nodeInfoMonitorPeriodic = &task.Periodic{
|
c.nodeInfoMonitorPeriodic = &task.Task{
|
||||||
Interval: c.nodeInfo.PullInterval,
|
Interval: c.nodeInfo.PullInterval,
|
||||||
Execute: c.nodeInfoMonitor,
|
Execute: c.nodeInfoMonitor,
|
||||||
}
|
}
|
||||||
// fetch user list task
|
// fetch user list task
|
||||||
c.userReportPeriodic = &task.Periodic{
|
c.userReportPeriodic = &task.Task{
|
||||||
Interval: c.nodeInfo.PushInterval,
|
Interval: c.nodeInfo.PushInterval,
|
||||||
Execute: c.reportUserTraffic,
|
Execute: c.reportUserTrafficTask,
|
||||||
}
|
}
|
||||||
log.Printf("[%s: %d] Start monitor node status", c.nodeInfo.Type, c.nodeInfo.Id)
|
log.WithField("tag", c.Tag).Info("Start monitor node status")
|
||||||
// delay to start nodeInfoMonitor
|
// delay to start nodeInfoMonitor
|
||||||
go func() {
|
_ = c.nodeInfoMonitorPeriodic.Start(false)
|
||||||
time.Sleep(c.nodeInfo.PullInterval)
|
log.WithField("tag", c.Tag).Info("Start report node status")
|
||||||
_ = c.nodeInfoMonitorPeriodic.Start()
|
_ = c.userReportPeriodic.Start(false)
|
||||||
}()
|
if c.nodeInfo.Tls {
|
||||||
log.Printf("[%s: %d] Start report node status", c.nodeInfo.Type, c.nodeInfo.Id)
|
switch c.CertConfig.CertMode {
|
||||||
// delay to start userReport
|
case "reality", "none", "":
|
||||||
go func() {
|
default:
|
||||||
time.Sleep(c.nodeInfo.PullInterval)
|
c.renewCertPeriodic = &task.Task{
|
||||||
_ = c.userReportPeriodic.Start()
|
Interval: time.Hour * 24,
|
||||||
}()
|
Execute: c.reportUserTrafficTask,
|
||||||
if c.nodeInfo.Tls && c.CertConfig.CertMode != "none" &&
|
}
|
||||||
(c.CertConfig.CertMode == "dns" || c.CertConfig.CertMode == "http") {
|
log.WithField("tag", c.Tag).Info("Start renew cert")
|
||||||
c.renewCertPeriodic = &task.Periodic{
|
// delay to start renewCert
|
||||||
Interval: time.Hour * 24,
|
_ = c.renewCertPeriodic.Start(true)
|
||||||
Execute: c.reportUserTraffic,
|
|
||||||
}
|
}
|
||||||
log.Printf("[%s: %d] Start renew cert", c.nodeInfo.Type, c.nodeInfo.Id)
|
|
||||||
// delay to start renewCert
|
|
||||||
go func() {
|
|
||||||
_ = c.renewCertPeriodic.Start()
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) nodeInfoMonitor() (err error) {
|
func (c *Controller) nodeInfoMonitor() (err error) {
|
||||||
// First fetch Node Info
|
// get node info
|
||||||
newNodeInfo, err := c.apiClient.GetNodeInfo()
|
newNodeInfo, err := c.apiClient.GetNodeInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.WithFields(log.Fields{
|
||||||
|
"tag": c.Tag,
|
||||||
|
"err": err,
|
||||||
|
}).Error("Get node info failed")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// get user info
|
||||||
|
newUserInfo, err := c.apiClient.GetUserList()
|
||||||
|
if err != nil {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"tag": c.Tag,
|
||||||
|
"err": err,
|
||||||
|
}).Error("Get user list failed")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var nodeInfoChanged = false
|
|
||||||
// If nodeInfo changed
|
|
||||||
if newNodeInfo != nil {
|
if newNodeInfo != nil {
|
||||||
|
// nodeInfo changed
|
||||||
// Remove old tag
|
// Remove old tag
|
||||||
oldTag := c.Tag
|
log.WithField("tag", c.Tag).Info("Node changed, reload")
|
||||||
err := c.server.DelNode(oldTag)
|
err = c.server.DelNode(c.Tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.WithFields(log.Fields{
|
||||||
|
"tag": c.Tag,
|
||||||
|
"err": err,
|
||||||
|
}).Error("Delete node failed")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Remove Old limiter
|
// Remove Old limiter
|
||||||
limiter.DeleteLimiter(oldTag)
|
limiter.DeleteLimiter(c.Tag)
|
||||||
// Add new tag
|
// Add new Limiter
|
||||||
c.nodeInfo = newNodeInfo
|
|
||||||
c.Tag = c.buildNodeTag()
|
c.Tag = c.buildNodeTag()
|
||||||
err = c.server.AddNode(c.Tag, newNodeInfo, c.ControllerConfig)
|
l := limiter.AddLimiter(c.Tag, &c.LimitConfig, newUserInfo)
|
||||||
if err != nil {
|
// check cert
|
||||||
log.Print(err)
|
if newNodeInfo.Tls || newNodeInfo.Type == "hysteria" {
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if newNodeInfo.Tls {
|
|
||||||
err = c.requestCert()
|
err = c.requestCert()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("request cert error: %s", err)
|
log.WithFields(log.Fields{
|
||||||
|
"tag": c.Tag,
|
||||||
|
"err": err,
|
||||||
|
}).Error("Request cert failed")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nodeInfoChanged = true
|
// add new node
|
||||||
}
|
err = c.server.AddNode(c.Tag, newNodeInfo, c.ControllerConfig)
|
||||||
// Update User
|
if err != nil {
|
||||||
newUserInfo, err := c.apiClient.GetUserList()
|
log.WithFields(log.Fields{
|
||||||
if err != nil {
|
"tag": c.Tag,
|
||||||
log.Print(err)
|
"err": err,
|
||||||
return nil
|
}).Error("Add node failed")
|
||||||
}
|
return nil
|
||||||
if nodeInfoChanged {
|
}
|
||||||
c.userList = newUserInfo
|
|
||||||
// Add new Limiter
|
|
||||||
l := limiter.AddLimiter(c.Tag, &c.LimitConfig, newUserInfo)
|
|
||||||
_, err = c.server.AddUsers(&vCore.AddUsersParams{
|
_, err = c.server.AddUsers(&vCore.AddUsersParams{
|
||||||
Tag: c.Tag,
|
Tag: c.Tag,
|
||||||
Config: c.ControllerConfig,
|
Config: c.ControllerConfig,
|
||||||
@ -103,109 +102,82 @@ func (c *Controller) nodeInfoMonitor() (err error) {
|
|||||||
NodeInfo: newNodeInfo,
|
NodeInfo: newNodeInfo,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.WithFields(log.Fields{
|
||||||
|
"tag": c.Tag,
|
||||||
|
"err": err,
|
||||||
|
}).Error("Add users failed")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
err = l.UpdateRule(newNodeInfo.Rules)
|
err = l.UpdateRule(newNodeInfo.Rules)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Update Rule error: %s", err)
|
log.WithFields(log.Fields{
|
||||||
|
"tag": c.Tag,
|
||||||
|
"err": err,
|
||||||
|
}).Error("Update Rule failed")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
// Check interval
|
// Check interval
|
||||||
if c.nodeInfoMonitorPeriodic.Interval != newNodeInfo.PullInterval &&
|
if c.nodeInfoMonitorPeriodic.Interval != newNodeInfo.PullInterval &&
|
||||||
newNodeInfo.PullInterval != 0 {
|
newNodeInfo.PullInterval != 0 {
|
||||||
c.nodeInfoMonitorPeriodic.Interval = newNodeInfo.PullInterval
|
c.nodeInfoMonitorPeriodic.Interval = newNodeInfo.PullInterval
|
||||||
_ = c.nodeInfoMonitorPeriodic.Close()
|
c.nodeInfoMonitorPeriodic.Close()
|
||||||
go func() {
|
_ = c.nodeInfoMonitorPeriodic.Start(false)
|
||||||
time.Sleep(c.nodeInfoMonitorPeriodic.Interval)
|
|
||||||
_ = c.nodeInfoMonitorPeriodic.Start()
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
if c.userReportPeriodic.Interval != newNodeInfo.PushInterval &&
|
if c.userReportPeriodic.Interval != newNodeInfo.PushInterval &&
|
||||||
newNodeInfo.PushInterval != 0 {
|
newNodeInfo.PushInterval != 0 {
|
||||||
c.userReportPeriodic.Interval = newNodeInfo.PullInterval
|
c.userReportPeriodic.Interval = newNodeInfo.PullInterval
|
||||||
_ = c.userReportPeriodic.Close()
|
c.userReportPeriodic.Close()
|
||||||
go func() {
|
_ = c.userReportPeriodic.Start(false)
|
||||||
time.Sleep(c.userReportPeriodic.Interval)
|
|
||||||
_ = c.userReportPeriodic.Start()
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
} else {
|
c.nodeInfo = newNodeInfo
|
||||||
deleted, added := compareUserList(c.userList, newUserInfo)
|
|
||||||
if len(deleted) > 0 {
|
|
||||||
deletedEmail := make([]string, len(deleted))
|
|
||||||
for i := range deleted {
|
|
||||||
deletedEmail[i] = fmt.Sprintf("%s|%s|%d",
|
|
||||||
c.Tag,
|
|
||||||
(deleted)[i].Uuid,
|
|
||||||
(deleted)[i].Id)
|
|
||||||
}
|
|
||||||
err := c.server.DelUsers(deletedEmail, c.Tag)
|
|
||||||
if err != nil {
|
|
||||||
log.Print(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(added) > 0 {
|
|
||||||
_, err := c.server.AddUsers(&vCore.AddUsersParams{
|
|
||||||
Tag: c.Tag,
|
|
||||||
Config: c.ControllerConfig,
|
|
||||||
UserInfo: added,
|
|
||||||
NodeInfo: c.nodeInfo,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Print(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(added) > 0 || len(deleted) > 0 {
|
|
||||||
// Update Limiter
|
|
||||||
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.Type, c.nodeInfo.Id,
|
|
||||||
len(deleted), len(added))
|
|
||||||
c.userList = newUserInfo
|
c.userList = newUserInfo
|
||||||
|
log.WithField("tag", c.Tag).Infof("Added %d new users", len(newUserInfo))
|
||||||
|
// exit
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Controller) reportUserTraffic() (err error) {
|
// node no changed, check users
|
||||||
// Get User traffic
|
deleted, added := compareUserList(c.userList, newUserInfo)
|
||||||
userTraffic := make([]panel.UserTraffic, 0)
|
if len(deleted) > 0 {
|
||||||
for i := range c.userList {
|
// have deleted users
|
||||||
up, down := c.server.GetUserTraffic(c.Tag, c.userList[i].Uuid, true)
|
err = c.server.DelUsers(deleted, c.Tag)
|
||||||
if up > 0 || down > 0 {
|
|
||||||
if c.LimitConfig.EnableDynamicSpeedLimit {
|
|
||||||
c.userList[i].Traffic += up + down
|
|
||||||
}
|
|
||||||
userTraffic = append(userTraffic, panel.UserTraffic{
|
|
||||||
UID: (c.userList)[i].Id,
|
|
||||||
Upload: up,
|
|
||||||
Download: down})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(userTraffic) > 0 && !c.DisableUploadTraffic {
|
|
||||||
err = c.apiClient.ReportUserTraffic(userTraffic)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Report user traffic faild: %s", err)
|
log.WithFields(log.Fields{
|
||||||
} else {
|
"tag": c.Tag,
|
||||||
log.Printf("[%s: %d] Report %d online users", c.nodeInfo.Type, c.nodeInfo.Id, len(userTraffic))
|
"err": err,
|
||||||
|
}).Error("Delete users failed")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
userTraffic = nil
|
if len(added) > 0 {
|
||||||
runtime.GC()
|
// have added users
|
||||||
|
_, err = c.server.AddUsers(&vCore.AddUsersParams{
|
||||||
|
Tag: c.Tag,
|
||||||
|
Config: c.ControllerConfig,
|
||||||
|
UserInfo: added,
|
||||||
|
NodeInfo: c.nodeInfo,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"tag": c.Tag,
|
||||||
|
"err": err,
|
||||||
|
}).Error("Add users failed")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(added) > 0 || len(deleted) > 0 {
|
||||||
|
// update Limiter
|
||||||
|
err = limiter.UpdateLimiter(c.Tag, added, deleted)
|
||||||
|
if err != nil {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"tag": c.Tag,
|
||||||
|
"err": err,
|
||||||
|
}).Error("limiter users failed")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.userList = newUserInfo
|
||||||
|
log.WithField("tag", c.Tag).
|
||||||
|
Errorf("%d user deleted, %d user added", len(deleted), len(added))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) RenewCert() {
|
|
||||||
l, err := lego.New(c.CertConfig)
|
|
||||||
if err != nil {
|
|
||||||
log.Print("new lego error: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = l.RenewCert()
|
|
||||||
if err != nil {
|
|
||||||
log.Print("renew cert error: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
33
node/user.go
33
node/user.go
@ -2,9 +2,42 @@ package node
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/Yuzuki616/V2bX/api/panel"
|
"github.com/Yuzuki616/V2bX/api/panel"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (c *Controller) reportUserTrafficTask() (err error) {
|
||||||
|
// Get User traffic
|
||||||
|
userTraffic := make([]panel.UserTraffic, 0)
|
||||||
|
for i := range c.userList {
|
||||||
|
up, down := c.server.GetUserTraffic(c.Tag, c.userList[i].Uuid, true)
|
||||||
|
if up > 0 || down > 0 {
|
||||||
|
if c.LimitConfig.EnableDynamicSpeedLimit {
|
||||||
|
c.userList[i].Traffic += up + down
|
||||||
|
}
|
||||||
|
userTraffic = append(userTraffic, panel.UserTraffic{
|
||||||
|
UID: (c.userList)[i].Id,
|
||||||
|
Upload: up,
|
||||||
|
Download: down})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(userTraffic) > 0 {
|
||||||
|
err = c.apiClient.ReportUserTraffic(userTraffic)
|
||||||
|
if err != nil {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"tag": c.Tag,
|
||||||
|
"err": err,
|
||||||
|
}).Error("Report user traffic faild")
|
||||||
|
} else {
|
||||||
|
log.WithField("tag", err).Errorf("Report %d online users", len(userTraffic))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
userTraffic = nil
|
||||||
|
runtime.GC()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func compareUserList(old, new []panel.UserInfo) (deleted, added []panel.UserInfo) {
|
func compareUserList(old, new []panel.UserInfo) (deleted, added []panel.UserInfo) {
|
||||||
tmp := map[string]struct{}{}
|
tmp := map[string]struct{}{}
|
||||||
tmp2 := map[string]struct{}{}
|
tmp2 := map[string]struct{}{}
|
||||||
|
Loading…
Reference in New Issue
Block a user