registry.go 4.2 KB

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