clashapi.go 2.4 KB

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