space.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. package app
  2. import (
  3. "context"
  4. "reflect"
  5. "v2ray.com/core/common"
  6. "v2ray.com/core/common/errors"
  7. )
  8. type Application interface {
  9. Interface() interface{}
  10. Start() error
  11. Close()
  12. }
  13. type InitializationCallback func() error
  14. func CreateAppFromConfig(ctx context.Context, config interface{}) (Application, error) {
  15. application, err := common.CreateObject(ctx, config)
  16. if err != nil {
  17. return nil, err
  18. }
  19. switch a := application.(type) {
  20. case Application:
  21. return a, nil
  22. default:
  23. return nil, errors.New("App: Not an application.")
  24. }
  25. }
  26. // A Space contains all apps that may be available in a V2Ray runtime.
  27. // Caller must check the availability of an app by calling HasXXX before getting its instance.
  28. type Space interface {
  29. GetApplication(appInterface interface{}) Application
  30. AddApplication(application Application) error
  31. Initialize() error
  32. OnInitialize(InitializationCallback)
  33. Start() error
  34. Close()
  35. }
  36. type spaceImpl struct {
  37. initialized bool
  38. cache map[reflect.Type]Application
  39. appInit []InitializationCallback
  40. }
  41. func NewSpace() Space {
  42. return &spaceImpl{
  43. cache: make(map[reflect.Type]Application),
  44. appInit: make([]InitializationCallback, 0, 32),
  45. }
  46. }
  47. func (v *spaceImpl) OnInitialize(f InitializationCallback) {
  48. if v.initialized {
  49. f()
  50. } else {
  51. v.appInit = append(v.appInit, f)
  52. }
  53. }
  54. func (v *spaceImpl) Initialize() error {
  55. for _, f := range v.appInit {
  56. if err := f(); err != nil {
  57. return err
  58. }
  59. }
  60. v.appInit = nil
  61. v.initialized = true
  62. return nil
  63. }
  64. func (v *spaceImpl) GetApplication(appInterface interface{}) Application {
  65. if v == nil {
  66. return nil
  67. }
  68. appType := reflect.TypeOf(appInterface)
  69. return v.cache[appType]
  70. }
  71. func (v *spaceImpl) AddApplication(app Application) error {
  72. if v == nil {
  73. return errors.New("App: Nil space.")
  74. }
  75. appType := reflect.TypeOf(app.Interface())
  76. v.cache[appType] = app
  77. return nil
  78. }
  79. func (s *spaceImpl) Start() error {
  80. for _, app := range s.cache {
  81. if err := app.Start(); err != nil {
  82. return err
  83. }
  84. }
  85. return nil
  86. }
  87. func (s *spaceImpl) Close() {
  88. for _, app := range s.cache {
  89. app.Close()
  90. }
  91. }
  92. type contextKey int
  93. const (
  94. spaceKey = contextKey(0)
  95. )
  96. func AddApplicationToSpace(ctx context.Context, appConfig interface{}) error {
  97. space := SpaceFromContext(ctx)
  98. if space == nil {
  99. return errors.New("App: No space in context.")
  100. }
  101. application, err := CreateAppFromConfig(ctx, appConfig)
  102. if err != nil {
  103. return err
  104. }
  105. return space.AddApplication(application)
  106. }
  107. func SpaceFromContext(ctx context.Context) Space {
  108. return ctx.Value(spaceKey).(Space)
  109. }
  110. func ContextWithSpace(ctx context.Context, space Space) context.Context {
  111. return context.WithValue(ctx, spaceKey, space)
  112. }