registry.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  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/v5/common/protoext"
  12. "github.com/v2fly/v2ray-core/v5/common/protofilter"
  13. "github.com/v2fly/v2ray-core/v5/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, _ = strings.CutPrefix(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 isRestrictedModeContext(ctx) {
  65. if err := enforceRestriction(implementationConfigInstancev2); err != nil {
  66. return nil, err
  67. }
  68. }
  69. if err := protofilter.FilterProtoConfig(ctx, implementationConfigInstancev2); err != nil {
  70. return nil, err
  71. }
  72. return implementationConfigInstance.(proto.Message), nil
  73. }
  74. func newImplementationRegistry() *implementationRegistry {
  75. return &implementationRegistry{implSet: map[string]*implementationSet{}}
  76. }
  77. var globalImplementationRegistry = newImplementationRegistry()
  78. var initialized = &sync.Once{}
  79. type registerRequest struct {
  80. proto interface{}
  81. loader CustomLoader
  82. }
  83. var registerRequests []registerRequest
  84. // RegisterImplementation register an implementation of a type of interface
  85. // loader(CustomLoader) is a private API, its interface is subject to breaking changes
  86. func RegisterImplementation(proto interface{}, loader CustomLoader) error {
  87. registerRequests = append(registerRequests, registerRequest{
  88. proto: proto,
  89. loader: loader,
  90. })
  91. return nil
  92. }
  93. func registerImplementation(proto interface{}, loader CustomLoader) error {
  94. protoReflect := reflect.New(reflect.TypeOf(proto).Elem())
  95. proto2 := protoReflect.Interface().(protov2.Message)
  96. msgDesc := proto2.ProtoReflect().Descriptor()
  97. fullName := string(msgDesc.FullName())
  98. msgOpts, err := protoext.GetMessageOptions(msgDesc)
  99. if err != nil {
  100. return newError("unable to find message options").Base(err)
  101. }
  102. globalImplementationRegistry.RegisterImplementation(fullName, msgOpts, loader)
  103. return nil
  104. }
  105. type LoadByAlias interface {
  106. LoadImplementationByAlias(ctx context.Context, interfaceType, alias string, data []byte) (proto.Message, error)
  107. }
  108. func LoadImplementationByAlias(ctx context.Context, interfaceType, alias string, data []byte) (proto.Message, error) {
  109. initialized.Do(func() {
  110. for _, v := range registerRequests {
  111. registerImplementation(v.proto, v.loader)
  112. }
  113. })
  114. return globalImplementationRegistry.LoadImplementationByAlias(ctx, interfaceType, alias, data)
  115. }