space.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. package app
  2. import (
  3. "context"
  4. "github.com/golang/protobuf/proto"
  5. "v2ray.com/core/common/errors"
  6. "v2ray.com/core/common/log"
  7. "v2ray.com/core/common/serial"
  8. )
  9. type Application interface {
  10. }
  11. type InitializationCallback func() error
  12. type ApplicationFactory interface {
  13. Create(space Space, config interface{}) (Application, error)
  14. }
  15. type AppGetter interface {
  16. GetApp(name string) Application
  17. }
  18. var (
  19. applicationFactoryCache = make(map[string]ApplicationFactory)
  20. )
  21. func RegisterApplicationFactory(defaultConfig proto.Message, factory ApplicationFactory) error {
  22. if defaultConfig == nil {
  23. return errors.New("Space: config is nil.")
  24. }
  25. name := serial.GetMessageType(defaultConfig)
  26. if len(name) == 0 {
  27. return errors.New("Space: cannot get config type.")
  28. }
  29. applicationFactoryCache[name] = factory
  30. return nil
  31. }
  32. // A Space contains all apps that may be available in a V2Ray runtime.
  33. // Caller must check the availability of an app by calling HasXXX before getting its instance.
  34. type Space interface {
  35. AddApp(config proto.Message) error
  36. AddAppLegacy(name string, app Application)
  37. Initialize() error
  38. OnInitialize(InitializationCallback)
  39. }
  40. type spaceImpl struct {
  41. initialized bool
  42. cache map[string]Application
  43. appInit []InitializationCallback
  44. }
  45. func NewSpace() Space {
  46. return &spaceImpl{
  47. cache: make(map[string]Application),
  48. appInit: make([]InitializationCallback, 0, 32),
  49. }
  50. }
  51. func (v *spaceImpl) OnInitialize(f InitializationCallback) {
  52. if v.initialized {
  53. if err := f(); err != nil {
  54. log.Error("Space: error after space initialization: ", err)
  55. }
  56. } else {
  57. v.appInit = append(v.appInit, f)
  58. }
  59. }
  60. func (v *spaceImpl) Initialize() error {
  61. for _, f := range v.appInit {
  62. if err := f(); err != nil {
  63. return err
  64. }
  65. }
  66. v.appInit = nil
  67. v.initialized = true
  68. return nil
  69. }
  70. func (v *spaceImpl) GetApp(configType string) Application {
  71. obj, found := v.cache[configType]
  72. if !found {
  73. return nil
  74. }
  75. return obj
  76. }
  77. func (v *spaceImpl) AddApp(config proto.Message) error {
  78. configName := serial.GetMessageType(config)
  79. factory, found := applicationFactoryCache[configName]
  80. if !found {
  81. return errors.New("Space: app not registered: ", configName)
  82. }
  83. app, err := factory.Create(v, config)
  84. if err != nil {
  85. return err
  86. }
  87. v.cache[configName] = app
  88. return nil
  89. }
  90. func (v *spaceImpl) AddAppLegacy(name string, application Application) {
  91. v.cache[name] = application
  92. }
  93. type contextKey int
  94. const (
  95. spaceKey = contextKey(0)
  96. )
  97. func SpaceFromContext(ctx context.Context) Space {
  98. return ctx.Value(spaceKey).(Space)
  99. }
  100. func ContextWithSpace(ctx context.Context, space Space) context.Context {
  101. return context.WithValue(ctx, spaceKey, space)
  102. }