diff --git a/conf/core.go b/conf/core.go index b55bf03..547aa54 100644 --- a/conf/core.go +++ b/conf/core.go @@ -6,6 +6,7 @@ import ( type CoreConfig struct { Type string `json:"Type"` + Name string `json:"Name"` XrayConfig *XrayConfig `json:"-"` SingConfig *SingConfig `json:"-"` } diff --git a/conf/node.go b/conf/node.go index 7f4ed5f..2dce806 100644 --- a/conf/node.go +++ b/conf/node.go @@ -2,10 +2,11 @@ package conf import ( "fmt" - "github.com/InazumaV/V2bX/common/json5" - "github.com/goccy/go-json" "io" "os" + + "github.com/InazumaV/V2bX/common/json5" + "github.com/goccy/go-json" ) type NodeConfig struct { @@ -85,6 +86,7 @@ func (n *NodeConfig) UnmarshalJSON(data []byte) (err error) { type Options struct { Name string `json:"Name"` Core string `json:"Core"` + CoreName string `json:"CoreName"` ListenIP string `json:"ListenIP"` SendIP string `json:"SendIP"` LimitConfig LimitConfig `json:"LimitConfig"` diff --git a/core/core.go b/core/core.go index 618282f..9f10d17 100644 --- a/core/core.go +++ b/core/core.go @@ -2,7 +2,6 @@ package core import ( "errors" - "strings" "github.com/InazumaV/V2bX/conf" ) @@ -17,21 +16,7 @@ func NewCore(c []conf.CoreConfig) (Core, error) { } // multi core if len(c) > 1 { - var cs []Core - for _, t := range c { - f, ok := cores[strings.ToLower(t.Type)] - if !ok { - return nil, errors.New("unknown core type: " + t.Type) - } - core1, err := f(&t) - if err != nil { - return nil, err - } - cs = append(cs, core1) - } - return &Selector{ - cores: cs, - }, nil + return NewSelector(c) } // one core if f, ok := cores[c[0].Type]; ok { diff --git a/core/selector.go b/core/selector.go index fce8953..2757e34 100644 --- a/core/selector.go +++ b/core/selector.go @@ -3,6 +3,7 @@ package core import ( "errors" "fmt" + "strings" "sync" "github.com/InazumaV/V2bX/api/panel" @@ -11,10 +12,32 @@ import ( ) type Selector struct { - cores []Core + cores map[string]Core nodes sync.Map } +func NewSelector(c []conf.CoreConfig) (Core, error) { + cs := make(map[string]Core, len(c)) + for _, t := range c { + f, ok := cores[strings.ToLower(t.Type)] + if !ok { + return nil, errors.New("unknown core type: " + t.Type) + } + core1, err := f(&t) + if err != nil { + return nil, err + } + if t.Name == "" { + cs[t.Type] = core1 + } else { + cs[t.Name] = core1 + } + } + return &Selector{ + cores: cs, + }, nil +} + func (s *Selector) Start() error { for i := range s.cores { err := s.cores[i].Start() @@ -43,32 +66,47 @@ func isSupported(protocol string, protocols []string) bool { } func (s *Selector) AddNode(tag string, info *panel.NodeInfo, option *conf.Options) error { - for i, c := range s.cores { - if len(option.Core) == 0 { - if !isSupported(info.Type, c.Protocols()) { + var core Core + if len(option.CoreName) > 0 { + // use name to select core + if c, ok := s.cores[option.CoreName]; ok { + core = c + } + } else { + // use type to select core + for _, c := range s.cores { + if len(option.Core) == 0 { + if !isSupported(info.Type, c.Protocols()) { + continue + } + } else if option.Core != c.Type() { continue } - option.Core = c.Type() - err := option.UnmarshalJSON(option.RawOptions) - if err != nil { - return fmt.Errorf("unmarshal option error: %s", err) - } - } else if option.Core != c.Type() { - continue + core = c } - err := c.AddNode(tag, info, option) - if err != nil { - return err - } - s.nodes.Store(tag, i) - return nil } - return errors.New("the node type is not support") + if core == nil { + return errors.New("the node type is not support") + } + if len(option.Core) == 0 { + option.Core = core.Type() + err := option.UnmarshalJSON(option.RawOptions) + if err != nil { + return fmt.Errorf("unmarshal option error: %s", err) + } + option.RawOptions = nil + } + err := core.AddNode(tag, info, option) + if err != nil { + return err + } + s.nodes.Store(tag, core) + return nil } func (s *Selector) DelNode(tag string) error { if t, e := s.nodes.Load(tag); e { - err := s.cores[t.(int)].DelNode(tag) + err := s.cores[t.(string)].DelNode(tag) if err != nil { return err } @@ -83,7 +121,7 @@ func (s *Selector) AddUsers(p *AddUsersParams) (added int, err error) { if !e { return 0, errors.New("the node is not have") } - return s.cores[t.(int)].AddUsers(p) + return t.(Core).AddUsers(p) } func (s *Selector) GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64) { @@ -91,7 +129,7 @@ func (s *Selector) GetUserTraffic(tag, uuid string, reset bool) (up int64, down if !e { return 0, 0 } - return s.cores[t.(int)].GetUserTraffic(tag, uuid, reset) + return t.(Core).GetUserTraffic(tag, uuid, reset) } func (s *Selector) DelUsers(users []panel.UserInfo, tag string) error { @@ -99,7 +137,7 @@ func (s *Selector) DelUsers(users []panel.UserInfo, tag string) error { if !e { return errors.New("the node is not have") } - return s.cores[t.(int)].DelUsers(users, tag) + return t.(Core).DelUsers(users, tag) } func (s *Selector) Protocols() []string { @@ -112,11 +150,18 @@ func (s *Selector) Protocols() []string { func (s *Selector) Type() string { t := "Selector(" - for i := range s.cores { - if i != 0 { + var flag bool + for n, c := range s.cores { + if flag { t += " " + } else { + flag = true + } + if len(n) == 0 { + t += c.Type() + } else { + t += n } - t += s.cores[i].Type() } t += ")" return t diff --git a/example/config.json b/example/config.json index b670399..13378c5 100644 --- a/example/config.json +++ b/example/config.json @@ -4,6 +4,7 @@ // 日志等级,info, warn, error, none "Level": "error", + // 日志输出路径,默认输出到标准输出 "Output": "" }, @@ -11,6 +12,10 @@ { // Core类型 "Type": "sing", + + // Core标识名,可选,如果需要启动多个同类型内核则必填 + "Name": "sing1", + "Log": { // 同 SingBox log 部分配置 @@ -26,6 +31,14 @@ } // More }, + { + "Type": "sing", + "Name": "sing2", + "Log": { + "Level": "info", + "Timestamp": false + }, + }, { "Type": "xray", "Log": { @@ -45,26 +58,42 @@ // Node标识名,便于查看日志,不填将通过下发的节点配置自动生成 // 务必注意不要重复,否则会出现问题 "Name": "sing_node1", - // Core类型 + + // 要使用的Core的类型 + // 如果填写了CoreName可不填 + // 建议视情况填写Core和CoreName其中一个,如果均没有填写将随机选择支持的内核 "Core": "sing", + + // 要使用的Core的标识名,如果没有定义多个同类型内核可不填 + "CoreName": "sing1", + // API接口地址 "ApiHost": "http://127.0.0.1", + // API密钥,即Token "ApiKey": "test", + // 节点ID "NodeID": 33, + // 节点类型 "NodeType": "shadowsocks", + // 请求超时时间 "Timeout": 30, + // 监听IP "ListenIP": "0.0.0.0", + // 发送IP "SendIP": "0.0.0.0", + // 开启 Proxy Protocol,参见 https://github.com/haproxy/haproxy/blob/master/doc/proxy-protocol.txt "EnableProxyProtocol": false, + // 开启 TCP Fast Open "EnableTFO": true, + // 设置 Domain Strategy // 可选 prefer_ipv4 / prefer_ipv6 / ipv4_only / ipv6_only "DomainStrategy": "ipv4_only" @@ -73,8 +102,7 @@ }, { // 引用其他配置文件 - - "Include": "../example/config_node1.json" + "Include": "../example/config_node1.json", } /*, {