space.go 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. package app
  2. import (
  3. "errors"
  4. "sync/atomic"
  5. "github.com/v2ray/v2ray-core/common"
  6. )
  7. var (
  8. ErrorMissingApplication = errors.New("App: Failed to found one or more applications.")
  9. )
  10. type ID int
  11. // Context of a function call from proxy to app.
  12. type Context interface {
  13. CallerTag() string
  14. }
  15. type Caller interface {
  16. Tag() string
  17. }
  18. type Application interface {
  19. common.Releasable
  20. }
  21. type ApplicationInitializer func() error
  22. // A Space contains all apps that may be available in a V2Ray runtime.
  23. // Caller must check the availability of an app by calling HasXXX before getting its instance.
  24. type Space interface {
  25. Initialize() error
  26. InitializeApplication(ApplicationInitializer)
  27. HasApp(ID) bool
  28. GetApp(ID) Application
  29. BindApp(ID, Application)
  30. }
  31. type spaceImpl struct {
  32. cache map[ID]Application
  33. initSignal chan struct{}
  34. initErrors chan error
  35. appsToInit int32
  36. appsDone int32
  37. }
  38. func NewSpace() Space {
  39. return &spaceImpl{
  40. cache: make(map[ID]Application),
  41. initSignal: make(chan struct{}),
  42. initErrors: make(chan error, 1),
  43. }
  44. }
  45. func (this *spaceImpl) InitializeApplication(f ApplicationInitializer) {
  46. atomic.AddInt32(&(this.appsToInit), 1)
  47. go func() {
  48. <-this.initSignal
  49. err := f()
  50. if err != nil {
  51. this.initErrors <- err
  52. }
  53. count := atomic.AddInt32(&(this.appsDone), 1)
  54. if count == this.appsToInit {
  55. close(this.initErrors)
  56. }
  57. }()
  58. }
  59. func (this *spaceImpl) Initialize() error {
  60. close(this.initSignal)
  61. if err, open := <-this.initErrors; open {
  62. return err
  63. }
  64. return nil
  65. }
  66. func (this *spaceImpl) HasApp(id ID) bool {
  67. _, found := this.cache[id]
  68. return found
  69. }
  70. func (this *spaceImpl) GetApp(id ID) Application {
  71. obj, found := this.cache[id]
  72. if !found {
  73. return nil
  74. }
  75. return obj
  76. }
  77. func (this *spaceImpl) BindApp(id ID, application Application) {
  78. this.cache[id] = application
  79. }