1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-06-21 15:05:23 +00:00

add support for custom loader in json parser

This commit is contained in:
Shelikhoo 2021-09-04 19:22:41 +01:00
parent 7e9f4acd9b
commit cef6a46548
No known key found for this signature in database
GPG Key ID: C4D5E79D22B25316
3 changed files with 50 additions and 36 deletions

View File

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

View File

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

View File

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