diff --git a/common/registry/implementation_set.go b/common/registry/implementation_set.go index e2958e2a4..9544e22bf 100644 --- a/common/registry/implementation_set.go +++ b/common/registry/implementation_set.go @@ -11,7 +11,7 @@ type implementationSet struct { AliasLookup map[string]*implementation } -type CustomLoader func(data []byte, dataType string) (proto.Message, error) +type CustomLoader func(data []byte, loader LoadByAlias) (proto.Message, error) type implementation struct { FullName string @@ -32,7 +32,7 @@ func (i *implementationSet) RegisterImplementation(name string, opt *protoext.Me } } -func (i *implementationSet) FindImplementationByAlias(alias string) (string, CustomLoader, error) { +func (i *implementationSet) findImplementationByAlias(alias string) (string, CustomLoader, error) { impl, found := i.AliasLookup[alias] if found { return impl.FullName, impl.Loader, nil diff --git a/common/registry/registry.go b/common/registry/registry.go index 6d721654a..a1e3c3ad0 100644 --- a/common/registry/registry.go +++ b/common/registry/registry.go @@ -1,8 +1,13 @@ package registry import ( + "bytes" + "github.com/golang/protobuf/jsonpb" + "github.com/golang/protobuf/proto" "github.com/v2fly/v2ray-core/v4/common/protoext" - "google.golang.org/protobuf/proto" + "github.com/v2fly/v2ray-core/v4/common/serial" + protov2 "google.golang.org/protobuf/proto" + "strings" ) type implementationRegistry struct { @@ -19,12 +24,43 @@ func (i *implementationRegistry) RegisterImplementation(name string, opt *protoe implSet.RegisterImplementation(name, opt, loader) } -func (i *implementationRegistry) FindImplementationByAlias(interfaceType, alias string) (string, CustomLoader, error) { +func (i *implementationRegistry) findImplementationByAlias(interfaceType, alias string) (string, CustomLoader, error) { implSet, found := i.implSet[interfaceType] if !found { return "", nil, newError("cannot find implemention unknown interface type") } - return implSet.FindImplementationByAlias(alias) + return implSet.findImplementationByAlias(alias) +} + +func (i *implementationRegistry) LoadImplementationByAlias(interfaceType, alias string, data []byte) (proto.Message, error) { + var implementationFullName string + + if strings.HasPrefix(alias, "#") { + // skip resolution for full name + implementationFullName = alias + } else { + registryResult, customLoader, err := i.findImplementationByAlias(interfaceType, alias) + if err != nil { + return nil, newError("unable to find implementation").Base(err) + } + if customLoader != nil { + return customLoader(data, i) + } + implementationFullName = registryResult + } + implementationConfigInstance, err := serial.GetInstance(implementationFullName) + if err != nil { + return nil, newError("unable to create implementation config instance").Base(err) + } + + unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: false} + err = unmarshaler.Unmarshal(bytes.NewReader(data), implementationConfigInstance.(proto.Message)) + if err != nil { + return nil, newError("unable to parse json content").Base(err) + } + + return implementationConfigInstance.(proto.Message), nil + } func newImplementationRegistry() *implementationRegistry { @@ -35,8 +71,8 @@ var globalImplementationRegistry = newImplementationRegistry() // RegisterImplementation register an implementation of a type of interface // loader(CustomLoader) is a private API, its interface is subject to breaking changes -func RegisterImplementation(proto proto.Message, loader CustomLoader) error { - msgDesc := proto.ProtoReflect().Type().Descriptor() +func RegisterImplementation(proto interface{}, loader CustomLoader) error { + msgDesc := proto.(protov2.Message).ProtoReflect().Type().Descriptor() fullName := string(msgDesc.FullName()) msgOpts, err := protoext.GetMessageOptions(msgDesc) if err != nil { @@ -46,6 +82,10 @@ func RegisterImplementation(proto proto.Message, loader CustomLoader) error { return nil } -func FindImplementationByAlias(interfaceType, alias string) (string, CustomLoader, error) { - return globalImplementationRegistry.FindImplementationByAlias(interfaceType, alias) +type LoadByAlias interface { + LoadImplementationByAlias(interfaceType, alias string, data []byte) (proto.Message, error) +} + +func LoadImplementationByAlias(interfaceType, alias string, data []byte) (proto.Message, error) { + return globalImplementationRegistry.LoadImplementationByAlias(interfaceType, alias, data) } diff --git a/infra/conf/v5cfg/common.go b/infra/conf/v5cfg/common.go index 9ba5feb08..5e7952b12 100644 --- a/infra/conf/v5cfg/common.go +++ b/infra/conf/v5cfg/common.go @@ -1,37 +1,11 @@ package v5cfg import ( - "bytes" "encoding/json" - "github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/proto" "github.com/v2fly/v2ray-core/v4/common/registry" - "github.com/v2fly/v2ray-core/v4/common/serial" - "strings" ) func loadHeterogeneousConfigFromRawJson(interfaceType, name string, rawJson json.RawMessage) (proto.Message, error) { - var implementationFullName string - if strings.HasPrefix(name, "#") { - // skip resolution for full name - implementationFullName = name - } else { - registryResult, err := registry.FindImplementationByAlias(interfaceType, name) - if err != nil { - return nil, newError("unable to find implementation").Base(err) - } - implementationFullName = registryResult - } - implementationConfigInstance, err := serial.GetInstance(implementationFullName) - if err != nil { - return nil, newError("unable to create implementation config instance").Base(err) - } - - unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: false} - err = unmarshaler.Unmarshal(bytes.NewReader([]byte(rawJson)), implementationConfigInstance.(proto.Message)) - if err != nil { - return nil, newError("unable to parse json content").Base(err) - } - - return implementationConfigInstance.(proto.Message), nil + return registry.LoadImplementationByAlias(interfaceType, name, []byte(rawJson)) }