space.go 2.6 KB

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