package clash import ( "context" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing/common" E "github.com/sagernet/sing/common/exceptions" "gopkg.in/yaml.v3" ) type ClashConfig struct { Proxies []ClashProxy `yaml:"proxies"` } type _ClashProxy struct { Name string `yaml:"name"` Type string `yaml:"type"` Options Proxy `yaml:"-"` SingType string `yaml:"-"` } type ClashProxy _ClashProxy type Proxy interface { Build() any } func (c *ClashProxy) UnmarshalYAML(value *yaml.Node) error { err := value.Decode((*_ClashProxy)(c)) if err != nil { return err } var options Proxy switch c.Type { case "ss": c.SingType = C.TypeShadowsocks options = &ShadowSocksOption{} case "tuic": c.SingType = C.TypeTUIC options = &TuicOption{} case "vmess": c.SingType = C.TypeVMess options = &VmessOption{} case "vless": c.SingType = C.TypeVLESS options = &VlessOption{} case "socks5": c.SingType = C.TypeSOCKS options = &Socks5Option{} case "http": c.SingType = C.TypeHTTP options = &HttpOption{} case "trojan": c.SingType = C.TypeTrojan options = &TrojanOption{} case "hysteria": c.SingType = C.TypeHysteria options = &HysteriaOption{} case "hysteria2": c.SingType = C.TypeHysteria2 options = &Hysteria2Option{} case "ssh": c.SingType = C.TypeSSH options = &SSHOption{} case "anytls": c.SingType = C.TypeAnyTLS options = &AnyTLSOption{} default: return nil } err = value.Decode(options) if err != nil { return err } c.Options = options return nil } func (c *ClashProxy) Build() option.Outbound { outbound := option.Outbound{ Tag: c.Name, Type: c.SingType, } if c.Options != nil { outbound.Options = c.Options.Build() } return outbound } func ParseClashSubscription(_ context.Context, content string) ([]option.Outbound, error) { config := &ClashConfig{} err := yaml.Unmarshal([]byte(content), &config) if err != nil { return nil, E.Cause(err, "parse clash config") } outbounds := common.FilterIsInstance(config.Proxies, func(proxy ClashProxy) (option.Outbound, bool) { if proxy.SingType == "" { return option.Outbound{}, false } return proxy.Build(), true }) return outbounds, nil }