space.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. package app
  2. import (
  3. "context"
  4. "reflect"
  5. "v2ray.com/core/common"
  6. "v2ray.com/core/common/errors"
  7. "v2ray.com/core/common/log"
  8. )
  9. type Application interface {
  10. Interface() interface{}
  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, errors.New("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. }
  33. type spaceImpl struct {
  34. initialized bool
  35. cache map[reflect.Type]Application
  36. appInit []InitializationCallback
  37. }
  38. func NewSpace() Space {
  39. return &spaceImpl{
  40. cache: make(map[reflect.Type]Application),
  41. appInit: make([]InitializationCallback, 0, 32),
  42. }
  43. }
  44. func (v *spaceImpl) OnInitialize(f InitializationCallback) {
  45. if v.initialized {
  46. if err := f(); err != nil {
  47. log.Error("Space: error after space initialization: ", err)
  48. }
  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 errors.New("App: Nil space.")
  73. }
  74. appType := reflect.TypeOf(app.Interface())
  75. v.cache[appType] = app
  76. return nil
  77. }
  78. type contextKey int
  79. const (
  80. spaceKey = contextKey(0)
  81. )
  82. func AddApplicationToSpace(ctx context.Context, appConfig interface{}) error {
  83. space := SpaceFromContext(ctx)
  84. if space == nil {
  85. return errors.New("App: No space in context.")
  86. }
  87. application, err := CreateAppFromConfig(ctx, appConfig)
  88. if err != nil {
  89. return err
  90. }
  91. return space.AddApplication(application)
  92. }
  93. func SpaceFromContext(ctx context.Context) Space {
  94. return ctx.Value(spaceKey).(Space)
  95. }
  96. func ContextWithSpace(ctx context.Context, space Space) context.Context {
  97. return context.WithValue(ctx, spaceKey, space)
  98. }