From 1e562e7dd51a850533017c5ce0deb5390a8a1b69 Mon Sep 17 00:00:00 2001 From: Shelikhoo Date: Sat, 4 Sep 2021 15:21:58 +0100 Subject: [PATCH] added implementation registry --- common/registry/errors.generated.go | 9 +++++ common/registry/implementation_set.go | 39 +++++++++++++++++++++ common/registry/registry.go | 49 +++++++++++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 common/registry/errors.generated.go create mode 100644 common/registry/implementation_set.go create mode 100644 common/registry/registry.go diff --git a/common/registry/errors.generated.go b/common/registry/errors.generated.go new file mode 100644 index 000000000..58e743d6e --- /dev/null +++ b/common/registry/errors.generated.go @@ -0,0 +1,9 @@ +package registry + +import "github.com/v2fly/v2ray-core/v4/common/errors" + +type errPathObjHolder struct{} + +func newError(values ...interface{}) *errors.Error { + return errors.New(values...).WithPathObj(errPathObjHolder{}) +} diff --git a/common/registry/implementation_set.go b/common/registry/implementation_set.go new file mode 100644 index 000000000..7b509620d --- /dev/null +++ b/common/registry/implementation_set.go @@ -0,0 +1,39 @@ +package registry + +import "github.com/v2fly/v2ray-core/v4/common/protoext" + +//go:generate go run github.com/v2fly/v2ray-core/v4/common/errors/errorgen + +type implementationSet struct { + AliasLookup map[string]*implementation +} + +type implementation struct { + FullName string + Alias []string +} + +func (i *implementationSet) RegisterImplementation(name string, opt *protoext.MessageOpt) { + alias := opt.GetShortName() + + impl := &implementation{ + FullName: name, + Alias: alias, + } + + for _, aliasName := range alias { + i.AliasLookup[aliasName] = impl + } +} + +func (i *implementationSet) FindImplementationByAlias(alias string) (string, error) { + impl, found := i.AliasLookup[alias] + if found { + return impl.FullName, nil + } + return "", newError("cannot find implementation by alias") +} + +func newImplementationSet() *implementationSet { + return &implementationSet{AliasLookup: map[string]*implementation{}} +} diff --git a/common/registry/registry.go b/common/registry/registry.go new file mode 100644 index 000000000..28ffa9038 --- /dev/null +++ b/common/registry/registry.go @@ -0,0 +1,49 @@ +package registry + +import ( + "github.com/v2fly/v2ray-core/v4/common/protoext" + "google.golang.org/protobuf/proto" +) + +type implementationRegistry struct { + implSet map[string]*implementationSet +} + +func (i *implementationRegistry) RegisterImplementation(name string, opt *protoext.MessageOpt) { + interfaceType := opt.GetType()[0] + implSet, found := i.implSet[interfaceType] + if !found { + implSet = newImplementationSet() + i.implSet[interfaceType] = implSet + } + implSet.RegisterImplementation(name, opt) +} + +func (i *implementationRegistry) FindImplementationByAlias(interfaceType, alias string) (string, error) { + implSet, found := i.implSet[interfaceType] + if !found { + return "", newError("cannot find implemention unknown interface type") + } + return implSet.FindImplementationByAlias(alias) +} + +func newImplementationRegistry() *implementationRegistry { + return &implementationRegistry{implSet: map[string]*implementationSet{}} +} + +var globalImplementationRegistry = newImplementationRegistry() + +func RegisterImplementation(proto proto.Message) error { + msgDesc := proto.ProtoReflect().Type().Descriptor() + fullName := string(msgDesc.FullName()) + msgOpts, err := protoext.GetMessageOptions(msgDesc) + if err != nil { + return newError("unable to find message options").Base(err) + } + globalImplementationRegistry.RegisterImplementation(fullName, msgOpts) + return nil +} + +func FindImplementationByAlias(interfaceType, alias string) (string, error) { + return globalImplementationRegistry.FindImplementationByAlias(interfaceType, alias) +}