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  }