space.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. package app
  2. import (
  3. "context"
  4. "reflect"
  5. "v2ray.com/core/common"
  6. "v2ray.com/core/common/event"
  7. )
  8. // Application is a component that runs in Space.
  9. type Application interface {
  10. Interface() interface{}
  11. Start() error
  12. Close()
  13. }
  14. // CreateAppFromConfig creates an Application based on its config. Application must have been registered.
  15. func CreateAppFromConfig(ctx context.Context, config interface{}) (Application, error) {
  16. application, err := common.CreateObject(ctx, config)
  17. if err != nil {
  18. return nil, err
  19. }
  20. switch a := application.(type) {
  21. case Application:
  22. return a, nil
  23. default:
  24. return nil, newError("not an application")
  25. }
  26. }
  27. // A Space contains all apps that may be available in a V2Ray runtime.
  28. type Space interface {
  29. event.Registry
  30. GetApplication(appInterface interface{}) Application
  31. AddApplication(application Application) error
  32. Initialize() error
  33. Start() error
  34. Close()
  35. }
  36. const (
  37. // SpaceInitializing is an event to be fired when Space is being initialized.
  38. SpaceInitializing event.Event = iota
  39. )
  40. type spaceImpl struct {
  41. event.Listener
  42. cache map[reflect.Type]Application
  43. initialized bool
  44. }
  45. // NewSpace creates a new Space.
  46. func NewSpace() Space {
  47. return &spaceImpl{
  48. cache: make(map[reflect.Type]Application),
  49. }
  50. }
  51. func (s *spaceImpl) On(e event.Event, h event.Handler) {
  52. if e == SpaceInitializing && s.initialized {
  53. _ = h(nil) // Ignore error
  54. return
  55. }
  56. s.Listener.On(e, h)
  57. }
  58. func (s *spaceImpl) Initialize() error {
  59. if s.initialized {
  60. return nil
  61. }
  62. s.initialized = true
  63. return s.Fire(SpaceInitializing, nil)
  64. }
  65. func (s *spaceImpl) GetApplication(appInterface interface{}) Application {
  66. if s == nil {
  67. return nil
  68. }
  69. appType := reflect.TypeOf(appInterface)
  70. return s.cache[appType]
  71. }
  72. func (s *spaceImpl) AddApplication(app Application) error {
  73. if s == nil {
  74. return newError("nil space").AtError()
  75. }
  76. appType := reflect.TypeOf(app.Interface())
  77. s.cache[appType] = app
  78. return nil
  79. }
  80. func (s *spaceImpl) Start() error {
  81. for _, app := range s.cache {
  82. if err := app.Start(); err != nil {
  83. return err
  84. }
  85. }
  86. return nil
  87. }
  88. func (s *spaceImpl) Close() {
  89. for _, app := range s.cache {
  90. app.Close()
  91. }
  92. }
  93. type contextKey int
  94. const (
  95. spaceKey = contextKey(0)
  96. )
  97. func AddApplicationToSpace(ctx context.Context, appConfig interface{}) error {
  98. space := SpaceFromContext(ctx)
  99. if space == nil {
  100. return newError("no space in context").AtError()
  101. }
  102. application, err := CreateAppFromConfig(ctx, appConfig)
  103. if err != nil {
  104. return err
  105. }
  106. return space.AddApplication(application)
  107. }
  108. func SpaceFromContext(ctx context.Context) Space {
  109. return ctx.Value(spaceKey).(Space)
  110. }
  111. func ContextWithSpace(ctx context.Context, space Space) context.Context {
  112. return context.WithValue(ctx, spaceKey, space)
  113. }