registry.go 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. package registry
  2. import (
  3. "bytes"
  4. "github.com/golang/protobuf/jsonpb"
  5. "github.com/golang/protobuf/proto"
  6. "github.com/v2fly/v2ray-core/v4/common/protoext"
  7. "github.com/v2fly/v2ray-core/v4/common/serial"
  8. "google.golang.org/protobuf/reflect/protoreflect"
  9. "strings"
  10. )
  11. type implementationRegistry struct {
  12. implSet map[string]*implementationSet
  13. }
  14. func (i *implementationRegistry) RegisterImplementation(name string, opt *protoext.MessageOpt, loader CustomLoader) {
  15. interfaceType := opt.GetType()[0]
  16. implSet, found := i.implSet[interfaceType]
  17. if !found {
  18. implSet = newImplementationSet()
  19. i.implSet[interfaceType] = implSet
  20. }
  21. implSet.RegisterImplementation(name, opt, loader)
  22. }
  23. func (i *implementationRegistry) findImplementationByAlias(interfaceType, alias string) (string, CustomLoader, error) {
  24. implSet, found := i.implSet[interfaceType]
  25. if !found {
  26. return "", nil, newError("cannot find implemention unknown interface type")
  27. }
  28. return implSet.findImplementationByAlias(alias)
  29. }
  30. func (i *implementationRegistry) LoadImplementationByAlias(interfaceType, alias string, data []byte) (proto.Message, error) {
  31. var implementationFullName string
  32. if strings.HasPrefix(alias, "#") {
  33. // skip resolution for full name
  34. implementationFullName = alias
  35. } else {
  36. registryResult, customLoader, err := i.findImplementationByAlias(interfaceType, alias)
  37. if err != nil {
  38. return nil, newError("unable to find implementation").Base(err)
  39. }
  40. if customLoader != nil {
  41. return customLoader(data, i)
  42. }
  43. implementationFullName = registryResult
  44. }
  45. implementationConfigInstance, err := serial.GetInstance(implementationFullName)
  46. if err != nil {
  47. return nil, newError("unable to create implementation config instance").Base(err)
  48. }
  49. unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: false}
  50. err = unmarshaler.Unmarshal(bytes.NewReader(data), implementationConfigInstance.(proto.Message))
  51. if err != nil {
  52. return nil, newError("unable to parse json content").Base(err)
  53. }
  54. return implementationConfigInstance.(proto.Message), nil
  55. }
  56. func newImplementationRegistry() *implementationRegistry {
  57. return &implementationRegistry{implSet: map[string]*implementationSet{}}
  58. }
  59. var globalImplementationRegistry = newImplementationRegistry()
  60. // RegisterImplementation register an implementation of a type of interface
  61. // loader(CustomLoader) is a private API, its interface is subject to breaking changes
  62. func RegisterImplementation(proto protoreflect.MessageDescriptor, loader CustomLoader) error {
  63. msgDesc := proto
  64. fullName := string(msgDesc.FullName())
  65. msgOpts, err := protoext.GetMessageOptions(msgDesc)
  66. if err != nil {
  67. return newError("unable to find message options").Base(err)
  68. }
  69. globalImplementationRegistry.RegisterImplementation(fullName, msgOpts, loader)
  70. return nil
  71. }
  72. type LoadByAlias interface {
  73. LoadImplementationByAlias(interfaceType, alias string, data []byte) (proto.Message, error)
  74. }
  75. func LoadImplementationByAlias(interfaceType, alias string, data []byte) (proto.Message, error) {
  76. return globalImplementationRegistry.LoadImplementationByAlias(interfaceType, alias, data)
  77. }