github.com/sagernet/sing-box@v1.9.0-rc.20/experimental/clashapi.go (about) 1 package experimental 2 3 import ( 4 "context" 5 "os" 6 "sort" 7 8 "github.com/sagernet/sing-box/adapter" 9 C "github.com/sagernet/sing-box/constant" 10 "github.com/sagernet/sing-box/log" 11 "github.com/sagernet/sing-box/option" 12 "github.com/sagernet/sing/common" 13 ) 14 15 type ClashServerConstructor = func(ctx context.Context, router adapter.Router, logFactory log.ObservableFactory, options option.ClashAPIOptions) (adapter.ClashServer, error) 16 17 var clashServerConstructor ClashServerConstructor 18 19 func RegisterClashServerConstructor(constructor ClashServerConstructor) { 20 clashServerConstructor = constructor 21 } 22 23 func NewClashServer(ctx context.Context, router adapter.Router, logFactory log.ObservableFactory, options option.ClashAPIOptions) (adapter.ClashServer, error) { 24 if clashServerConstructor == nil { 25 return nil, os.ErrInvalid 26 } 27 return clashServerConstructor(ctx, router, logFactory, options) 28 } 29 30 func CalculateClashModeList(options option.Options) []string { 31 var clashModes []string 32 clashModes = append(clashModes, extraClashModeFromRule(common.PtrValueOrDefault(options.Route).Rules)...) 33 clashModes = append(clashModes, extraClashModeFromDNSRule(common.PtrValueOrDefault(options.DNS).Rules)...) 34 clashModes = common.FilterNotDefault(common.Uniq(clashModes)) 35 predefinedOrder := []string{ 36 "Rule", "Global", "Direct", 37 } 38 var newClashModes []string 39 for _, mode := range clashModes { 40 if !common.Contains(predefinedOrder, mode) { 41 newClashModes = append(newClashModes, mode) 42 } 43 } 44 sort.Strings(newClashModes) 45 for _, mode := range predefinedOrder { 46 if common.Contains(clashModes, mode) { 47 newClashModes = append(newClashModes, mode) 48 } 49 } 50 return newClashModes 51 } 52 53 func extraClashModeFromRule(rules []option.Rule) []string { 54 var clashMode []string 55 for _, rule := range rules { 56 switch rule.Type { 57 case C.RuleTypeDefault: 58 if rule.DefaultOptions.ClashMode != "" { 59 clashMode = append(clashMode, rule.DefaultOptions.ClashMode) 60 } 61 case C.RuleTypeLogical: 62 clashMode = append(clashMode, extraClashModeFromRule(rule.LogicalOptions.Rules)...) 63 } 64 } 65 return clashMode 66 } 67 68 func extraClashModeFromDNSRule(rules []option.DNSRule) []string { 69 var clashMode []string 70 for _, rule := range rules { 71 switch rule.Type { 72 case C.RuleTypeDefault: 73 if rule.DefaultOptions.ClashMode != "" { 74 clashMode = append(clashMode, rule.DefaultOptions.ClashMode) 75 } 76 case C.RuleTypeLogical: 77 clashMode = append(clashMode, extraClashModeFromDNSRule(rule.LogicalOptions.Rules)...) 78 } 79 } 80 return clashMode 81 }