mirror of
https://github.com/v2fly/v2ray-core.git
synced 2025-06-02 22:03:39 -04:00
add support for custom loader in json parser
This commit is contained in:
parent
7e9f4acd9b
commit
cef6a46548
@ -11,7 +11,7 @@ type implementationSet struct {
|
|||||||
AliasLookup map[string]*implementation
|
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 {
|
type implementation struct {
|
||||||
FullName string
|
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]
|
impl, found := i.AliasLookup[alias]
|
||||||
if found {
|
if found {
|
||||||
return impl.FullName, impl.Loader, nil
|
return impl.FullName, impl.Loader, nil
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
package registry
|
package registry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"github.com/golang/protobuf/jsonpb"
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
"github.com/v2fly/v2ray-core/v4/common/protoext"
|
"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 {
|
type implementationRegistry struct {
|
||||||
@ -19,12 +24,43 @@ func (i *implementationRegistry) RegisterImplementation(name string, opt *protoe
|
|||||||
implSet.RegisterImplementation(name, opt, loader)
|
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]
|
implSet, found := i.implSet[interfaceType]
|
||||||
if !found {
|
if !found {
|
||||||
return "", nil, newError("cannot find implemention unknown interface type")
|
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 {
|
func newImplementationRegistry() *implementationRegistry {
|
||||||
@ -35,8 +71,8 @@ var globalImplementationRegistry = newImplementationRegistry()
|
|||||||
|
|
||||||
// RegisterImplementation register an implementation of a type of interface
|
// RegisterImplementation register an implementation of a type of interface
|
||||||
// loader(CustomLoader) is a private API, its interface is subject to breaking changes
|
// loader(CustomLoader) is a private API, its interface is subject to breaking changes
|
||||||
func RegisterImplementation(proto proto.Message, loader CustomLoader) error {
|
func RegisterImplementation(proto interface{}, loader CustomLoader) error {
|
||||||
msgDesc := proto.ProtoReflect().Type().Descriptor()
|
msgDesc := proto.(protov2.Message).ProtoReflect().Type().Descriptor()
|
||||||
fullName := string(msgDesc.FullName())
|
fullName := string(msgDesc.FullName())
|
||||||
msgOpts, err := protoext.GetMessageOptions(msgDesc)
|
msgOpts, err := protoext.GetMessageOptions(msgDesc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -46,6 +82,10 @@ func RegisterImplementation(proto proto.Message, loader CustomLoader) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func FindImplementationByAlias(interfaceType, alias string) (string, CustomLoader, error) {
|
type LoadByAlias interface {
|
||||||
return globalImplementationRegistry.FindImplementationByAlias(interfaceType, alias)
|
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,37 +1,11 @@
|
|||||||
package v5cfg
|
package v5cfg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/golang/protobuf/jsonpb"
|
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
"github.com/v2fly/v2ray-core/v4/common/registry"
|
"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) {
|
func loadHeterogeneousConfigFromRawJson(interfaceType, name string, rawJson json.RawMessage) (proto.Message, error) {
|
||||||
var implementationFullName string
|
return registry.LoadImplementationByAlias(interfaceType, name, []byte(rawJson))
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user