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