1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-06-26 01:15:38 +00:00

add delayed and reflective auto registration

Delay is required for all init to finish, otherwise protoreflect() can return nil.
This commit is contained in:
Shelikhoo 2021-09-05 00:46:25 +01:00
parent 0250c6a4d7
commit a4c66656b1
No known key found for this signature in database
GPG Key ID: C4D5E79D22B25316

View File

@ -6,8 +6,10 @@ import (
"github.com/golang/protobuf/proto"
"github.com/v2fly/v2ray-core/v4/common/protoext"
"github.com/v2fly/v2ray-core/v4/common/serial"
"google.golang.org/protobuf/reflect/protoreflect"
protov2 "google.golang.org/protobuf/proto"
"reflect"
"strings"
"sync"
)
type implementationRegistry struct {
@ -69,10 +71,33 @@ func newImplementationRegistry() *implementationRegistry {
var globalImplementationRegistry = newImplementationRegistry()
var initialized = &sync.Once{}
type registerRequest struct {
proto interface{}
loader CustomLoader
}
var registerRequests []registerRequest
// 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 protoreflect.MessageDescriptor, loader CustomLoader) error {
msgDesc := proto
func RegisterImplementation(proto interface{}, loader CustomLoader) error {
registerRequests = append(registerRequests, registerRequest{
proto: proto,
loader: loader,
})
return nil
}
func registerImplementation(proto interface{}, loader CustomLoader) error {
protoReflect := reflect.New(reflect.TypeOf(proto).Elem())
var proto2 protov2.Message
assignMessage := func(msg protov2.Message) {
proto2 = msg
}
reflect.ValueOf(assignMessage).Call([]reflect.Value{protoReflect})
msgDesc := proto2.ProtoReflect().Descriptor()
fullName := string(msgDesc.FullName())
msgOpts, err := protoext.GetMessageOptions(msgDesc)
if err != nil {
@ -87,5 +112,10 @@ type LoadByAlias interface {
}
func LoadImplementationByAlias(interfaceType, alias string, data []byte) (proto.Message, error) {
initialized.Do(func() {
for _, v := range registerRequests {
registerImplementation(v.proto, v.loader)
}
})
return globalImplementationRegistry.LoadImplementationByAlias(interfaceType, alias, data)
}