package serverObj import ( "errors" "fmt" "net/url" "strings" "github.com/v2rayA/v2rayA/common" "github.com/v2rayA/v2rayA/conf" "github.com/v2rayA/v2rayA/kernel/coreObj" "github.com/v2rayA/v2rayA/kernel/v2ray/where" ) var ErrInvalidParameter = fmt.Errorf("malformed server link") type ServerObj interface { Configuration(info PriorInfo) (c Configuration, err error) ExportToURL() string NeedPluginPort() bool ProtoToShow() string GetProtocol() string GetHostname() string GetPort() int GetName() string SetName(name string) } type Configuration struct { CoreOutbound coreObj.OutboundObject ExtraOutbounds []coreObj.OutboundObject PluginChain string // The first is a server plugin, and the others are client plugins. Split by ",". UDPSupport bool PluginManagerServerLink string } type PriorInfo struct { Variant where.Variant CoreVersion string Tag string PluginPort int Backend string // effective backend: "v2ray" or "" (daeuniverse/system default) } // BackendGetter is implemented by server types that support backend selection. type BackendGetter interface { GetBackend() string } func (info *PriorInfo) PluginObj() coreObj.OutboundObject { return coreObj.OutboundObject{ Tag: info.Tag, Protocol: "socks", Settings: coreObj.Settings{ Servers: []coreObj.Server{ { Address: "127.0.0.1", Port: info.PluginPort, }, }}, } } type FromLinkCreator func(link string) (ServerObj, error) type EmptyCreator func() (ServerObj, error) var fromLinkCreators = make(map[string]FromLinkCreator) var emptyCreators = make(map[string]EmptyCreator) func FromLinkRegister(name string, creator FromLinkCreator) { fromLinkCreators[name] = creator } func EmptyRegister(name string, creator EmptyCreator) { emptyCreators[name] = creator } func New(name string) (ServerObj, error) { if creator, ok := emptyCreators[name]; ok { return creator() } else if pm := conf.GetEnvironmentConfig().PluginManager; pm != "" { // we do not support to override build-in protocols creator := emptyCreators[PluginManagerScheme] return creator() } else { return nil, fmt.Errorf("%q links are not supported; supported schemes: vmess, vless, ss, trojan, trojan-go, socks5, http, https, http-proxy, https-proxy, hysteria2, hy2, tuic, juicity, anytls, wireguard", name) } } func NewFromLink(name string, link string) (ServerObj, error) { if name == "ssr" || name == "shadowsocksr" { return nil, common.Coded("LINK_UNSUPPORTED_SCHEME", fmt.Errorf("%s", ssrUnsupported), map[string]interface{}{"scheme": name}) } if creator, ok := fromLinkCreators[name]; ok { obj, err := creator(link) var coded *common.CodedError if errors.As(err, &coded) { return nil, err } if err != nil { return nil, common.Coded("LINK_MALFORMED", err, map[string]interface{}{ "protocol": name, "detail": strings.TrimPrefix(err.Error(), ErrInvalidParameter.Error()+": "), }) } return obj, nil } else if pm := conf.GetEnvironmentConfig().PluginManager; pm != "" { // we do not support to override build-in protocols creator := fromLinkCreators[PluginManagerScheme] return creator(link) } else { return nil, common.Coded("LINK_UNSUPPORTED_SCHEME", fmt.Errorf("%q links are not supported; supported schemes: vmess, vless, ss, trojan, trojan-go, socks5, http, https, http-proxy, https-proxy, hysteria2, hy2, tuic, juicity, anytls, wireguard", name), map[string]interface{}{"scheme": name}) } } func setValue(values *url.Values, key string, value string) { if value == "" { return } values.Set(key, value) }