|
|
@@ -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)
|
|
|
}
|