Browse Source

add support for custom loader in json parser

Shelikhoo 4 years ago
parent
commit
cef6a46548
3 changed files with 50 additions and 36 deletions
  1. 2 2
      common/registry/implementation_set.go
  2. 47 7
      common/registry/registry.go
  3. 1 27
      infra/conf/v5cfg/common.go

+ 2 - 2
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

+ 47 - 7
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)
 }

+ 1 - 27
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))
 }