Reapply SingboxForPanel integration on upstream stable

This commit is contained in:
CN-JS-HuiBai
2026-04-16 10:29:41 +08:00
parent d5adb54bc6
commit 66c252d6ef
29 changed files with 5280 additions and 41 deletions

View File

@@ -0,0 +1,112 @@
package xboard
import (
"context"
"fmt"
"github.com/sagernet/sing-box/adapter"
boxService "github.com/sagernet/sing-box/adapter/service"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
)
type multiNodeService struct {
boxService.Adapter
services []adapter.Service
}
func newMultiNodeService(ctx context.Context, logger log.ContextLogger, tag string, options option.XBoardServiceOptions) (adapter.Service, error) {
expanded := expandNodeOptions(options)
services := make([]adapter.Service, 0, len(expanded))
for i, node := range expanded {
nodeTag := expandedNodeTag(tag, i, options.Nodes[i], node)
service, err := newSingleService(ctx, logger, nodeTag, node)
if err != nil {
return nil, fmt.Errorf("create xboard node service %s: %w", nodeTag, err)
}
services = append(services, service)
}
return &multiNodeService{
Adapter: boxService.NewAdapter(C.TypeXBoard, tag),
services: services,
}, nil
}
func expandNodeOptions(base option.XBoardServiceOptions) []option.XBoardServiceOptions {
if len(base.Nodes) == 0 {
return []option.XBoardServiceOptions{base}
}
result := make([]option.XBoardServiceOptions, 0, len(base.Nodes))
for _, node := range base.Nodes {
child := base
child.Nodes = nil
if node.PanelURL != "" {
child.PanelURL = node.PanelURL
}
if node.ConfigPanelURL != "" {
child.ConfigPanelURL = node.ConfigPanelURL
}
if node.UserPanelURL != "" {
child.UserPanelURL = node.UserPanelURL
}
if node.Key != "" {
child.Key = node.Key
}
if node.NodeID != 0 {
child.NodeID = node.NodeID
}
if node.ConfigNodeID != 0 {
child.ConfigNodeID = node.ConfigNodeID
}
if node.UserNodeID != 0 {
child.UserNodeID = node.UserNodeID
}
if node.NodeType != "" {
child.NodeType = node.NodeType
}
if node.SyncInterval != 0 {
child.SyncInterval = node.SyncInterval
}
if node.ReportInterval != 0 {
child.ReportInterval = node.ReportInterval
}
result = append(result, child)
}
return result
}
func expandedNodeTag(baseTag string, index int, entry option.XBoardNodeOptions, node option.XBoardServiceOptions) string {
nodeTag := ""
if entry.Tag != "" {
nodeTag = entry.Tag
}
if nodeTag == "" && node.NodeID != 0 {
nodeTag = fmt.Sprintf("%d", node.NodeID)
}
if nodeTag == "" {
nodeTag = fmt.Sprintf("%d", index+1)
}
if baseTag == "" {
return "xboard-" + nodeTag
}
return fmt.Sprintf("%s-%s", baseTag, nodeTag)
}
func (s *multiNodeService) Start(stage adapter.StartStage) error {
for _, service := range s.services {
if err := service.Start(stage); err != nil {
return err
}
}
return nil
}
func (s *multiNodeService) Close() error {
for i := len(s.services) - 1; i >= 0; i-- {
if err := s.services[i].Close(); err != nil {
return err
}
}
return nil
}