selector.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. package outboundgroup
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "github.com/metacubex/mihomo/adapter/outbound"
  7. "github.com/metacubex/mihomo/component/dialer"
  8. C "github.com/metacubex/mihomo/constant"
  9. "github.com/metacubex/mihomo/constant/provider"
  10. )
  11. type Selector struct {
  12. *GroupBase
  13. disableUDP bool
  14. selected string
  15. Hidden bool
  16. Icon string
  17. }
  18. // DialContext implements C.ProxyAdapter
  19. func (s *Selector) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
  20. c, err := s.selectedProxy(true).DialContext(ctx, metadata, s.Base.DialOptions(opts...)...)
  21. if err == nil {
  22. c.AppendToChains(s)
  23. }
  24. return c, err
  25. }
  26. // ListenPacketContext implements C.ProxyAdapter
  27. func (s *Selector) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
  28. pc, err := s.selectedProxy(true).ListenPacketContext(ctx, metadata, s.Base.DialOptions(opts...)...)
  29. if err == nil {
  30. pc.AppendToChains(s)
  31. }
  32. return pc, err
  33. }
  34. // SupportUDP implements C.ProxyAdapter
  35. func (s *Selector) SupportUDP() bool {
  36. if s.disableUDP {
  37. return false
  38. }
  39. return s.selectedProxy(false).SupportUDP()
  40. }
  41. // IsL3Protocol implements C.ProxyAdapter
  42. func (s *Selector) IsL3Protocol(metadata *C.Metadata) bool {
  43. return s.selectedProxy(false).IsL3Protocol(metadata)
  44. }
  45. // MarshalJSON implements C.ProxyAdapter
  46. func (s *Selector) MarshalJSON() ([]byte, error) {
  47. all := []string{}
  48. for _, proxy := range s.GetProxies(false) {
  49. all = append(all, proxy.Name())
  50. }
  51. return json.Marshal(map[string]any{
  52. "type": s.Type().String(),
  53. "now": s.Now(),
  54. "all": all,
  55. "hidden": s.Hidden,
  56. "icon": s.Icon,
  57. })
  58. }
  59. func (s *Selector) Now() string {
  60. return s.selectedProxy(false).Name()
  61. }
  62. func (s *Selector) Set(name string) error {
  63. for _, proxy := range s.GetProxies(false) {
  64. if proxy.Name() == name {
  65. s.selected = name
  66. return nil
  67. }
  68. }
  69. return errors.New("proxy not exist")
  70. }
  71. func (s *Selector) ForceSet(name string) {
  72. s.selected = name
  73. }
  74. // Unwrap implements C.ProxyAdapter
  75. func (s *Selector) Unwrap(metadata *C.Metadata, touch bool) C.Proxy {
  76. return s.selectedProxy(touch)
  77. }
  78. func (s *Selector) selectedProxy(touch bool) C.Proxy {
  79. proxies := s.GetProxies(touch)
  80. for _, proxy := range proxies {
  81. if proxy.Name() == s.selected {
  82. return proxy
  83. }
  84. }
  85. return proxies[0]
  86. }
  87. func NewSelector(option *GroupCommonOption, providers []provider.ProxyProvider) *Selector {
  88. return &Selector{
  89. GroupBase: NewGroupBase(GroupBaseOption{
  90. outbound.BaseOption{
  91. Name: option.Name,
  92. Type: C.Selector,
  93. Interface: option.Interface,
  94. RoutingMark: option.RoutingMark,
  95. },
  96. option.Filter,
  97. option.ExcludeFilter,
  98. option.ExcludeType,
  99. option.TestTimeout,
  100. option.MaxFailedTimes,
  101. providers,
  102. }),
  103. selected: "COMPATIBLE",
  104. disableUDP: option.DisableUDP,
  105. Hidden: option.Hidden,
  106. Icon: option.Icon,
  107. }
  108. }