registry.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package registry
  2. import (
  3. "bytes"
  4. "context"
  5. "github.com/golang/protobuf/jsonpb"
  6. "github.com/golang/protobuf/proto"
  7. "github.com/v2fly/v2ray-core/v4/common/protoext"
  8. "github.com/v2fly/v2ray-core/v4/common/protofilter"
  9. "github.com/v2fly/v2ray-core/v4/common/serial"
  10. protov2 "google.golang.org/protobuf/proto"
  11. "reflect"
  12. "strings"
  13. "sync"
  14. )
  15. type implementationRegistry struct {
  16. implSet map[string]*implementationSet
  17. }
  18. func (i *implementationRegistry) RegisterImplementation(name string, opt *protoext.MessageOpt, loader CustomLoader) {
  19. interfaceType := opt.GetType()[0]
  20. implSet, found := i.implSet[interfaceType]
  21. if !found {
  22. implSet = newImplementationSet()
  23. i.implSet[interfaceType] = implSet
  24. }
  25. implSet.RegisterImplementation(name, opt, loader)
  26. }
  27. func (i *implementationRegistry) findImplementationByAlias(interfaceType, alias string) (string, CustomLoader, error) {
  28. implSet, found := i.implSet[interfaceType]
  29. if !found {
  30. return "", nil, newError("cannot find implemention unknown interface type")
  31. }
  32. return implSet.findImplementationByAlias(alias)
  33. }
  34. func (i *implementationRegistry) LoadImplementationByAlias(ctx context.Context, interfaceType, alias string, data []byte) (proto.Message, error) {
  35. var implementationFullName string
  36. if strings.HasPrefix(alias, "#") {
  37. // skip resolution for full name
  38. implementationFullName = alias
  39. } else {
  40. registryResult, customLoader, err := i.findImplementationByAlias(interfaceType, alias)
  41. if err != nil {
  42. return nil, newError("unable to find implementation").Base(err)
  43. }
  44. if customLoader != nil {
  45. return customLoader(data, i)
  46. }
  47. implementationFullName = registryResult
  48. }
  49. implementationConfigInstance, err := serial.GetInstance(implementationFullName)
  50. if err != nil {
  51. return nil, newError("unable to create implementation config instance").Base(err)
  52. }
  53. unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: false}
  54. err = unmarshaler.Unmarshal(bytes.NewReader(data), implementationConfigInstance.(proto.Message))
  55. if err != nil {
  56. return nil, newError("unable to parse json content").Base(err)
  57. }
  58. implementationConfigInstancev2 := proto.MessageV2(implementationConfigInstance)
  59. if err := protofilter.FilterProtoConfig(ctx, implementationConfigInstancev2); err != nil {
  60. return nil, err
  61. }
  62. return implementationConfigInstance.(proto.Message), nil
  63. }
  64. func newImplementationRegistry() *implementationRegistry {
  65. return &implementationRegistry{implSet: map[string]*implementationSet{}}
  66. }
  67. var globalImplementationRegistry = newImplementationRegistry()
  68. var initialized = &sync.Once{}
  69. type registerRequest struct {
  70. proto interface{}
  71. loader CustomLoader
  72. }
  73. var registerRequests []registerRequest
  74. // RegisterImplementation register an implementation of a type of interface
  75. // loader(CustomLoader) is a private API, its interface is subject to breaking changes
  76. func RegisterImplementation(proto interface{}, loader CustomLoader) error {
  77. registerRequests = append(registerRequests, registerRequest{
  78. proto: proto,
  79. loader: loader,
  80. })
  81. return nil
  82. }
  83. func registerImplementation(proto interface{}, loader CustomLoader) error {
  84. protoReflect := reflect.New(reflect.TypeOf(proto).Elem())
  85. var proto2 protov2.Message
  86. assignMessage := func(msg protov2.Message) {
  87. proto2 = msg
  88. }
  89. reflect.ValueOf(assignMessage).Call([]reflect.Value{protoReflect})
  90. msgDesc := proto2.ProtoReflect().Descriptor()
  91. fullName := string(msgDesc.FullName())
  92. msgOpts, err := protoext.GetMessageOptions(msgDesc)
  93. if err != nil {
  94. return newError("unable to find message options").Base(err)
  95. }
  96. globalImplementationRegistry.RegisterImplementation(fullName, msgOpts, loader)
  97. return nil
  98. }
  99. type LoadByAlias interface {
  100. LoadImplementationByAlias(ctx context.Context, interfaceType, alias string, data []byte) (proto.Message, error)
  101. }
  102. func LoadImplementationByAlias(ctx context.Context, interfaceType, alias string, data []byte) (proto.Message, error) {
  103. initialized.Do(func() {
  104. for _, v := range registerRequests {
  105. registerImplementation(v.proto, v.loader)
  106. }
  107. })
  108. return globalImplementationRegistry.LoadImplementationByAlias(ctx, interfaceType, alias, data)
  109. }