manager.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. package service
  2. import (
  3. "context"
  4. "os"
  5. "sync"
  6. "github.com/sagernet/sing-box/adapter"
  7. "github.com/sagernet/sing-box/common/taskmonitor"
  8. C "github.com/sagernet/sing-box/constant"
  9. "github.com/sagernet/sing-box/log"
  10. "github.com/sagernet/sing/common"
  11. E "github.com/sagernet/sing/common/exceptions"
  12. )
  13. var _ adapter.ServiceManager = (*Manager)(nil)
  14. type Manager struct {
  15. logger log.ContextLogger
  16. registry adapter.ServiceRegistry
  17. access sync.Mutex
  18. started bool
  19. stage adapter.StartStage
  20. services []adapter.Service
  21. serviceByTag map[string]adapter.Service
  22. }
  23. func NewManager(logger log.ContextLogger, registry adapter.ServiceRegistry) *Manager {
  24. return &Manager{
  25. logger: logger,
  26. registry: registry,
  27. serviceByTag: make(map[string]adapter.Service),
  28. }
  29. }
  30. func (m *Manager) Start(stage adapter.StartStage) error {
  31. m.access.Lock()
  32. if m.started && m.stage >= stage {
  33. panic("already started")
  34. }
  35. m.started = true
  36. m.stage = stage
  37. services := m.services
  38. m.access.Unlock()
  39. for _, service := range services {
  40. err := adapter.LegacyStart(service, stage)
  41. if err != nil {
  42. return E.Cause(err, stage, " service/", service.Type(), "[", service.Tag(), "]")
  43. }
  44. }
  45. return nil
  46. }
  47. func (m *Manager) Close() error {
  48. m.access.Lock()
  49. defer m.access.Unlock()
  50. if !m.started {
  51. return nil
  52. }
  53. m.started = false
  54. services := m.services
  55. m.services = nil
  56. monitor := taskmonitor.New(m.logger, C.StopTimeout)
  57. var err error
  58. for _, service := range services {
  59. monitor.Start("close service/", service.Type(), "[", service.Tag(), "]")
  60. err = E.Append(err, service.Close(), func(err error) error {
  61. return E.Cause(err, "close service/", service.Type(), "[", service.Tag(), "]")
  62. })
  63. monitor.Finish()
  64. }
  65. return nil
  66. }
  67. func (m *Manager) Services() []adapter.Service {
  68. m.access.Lock()
  69. defer m.access.Unlock()
  70. return m.services
  71. }
  72. func (m *Manager) Get(tag string) (adapter.Service, bool) {
  73. m.access.Lock()
  74. service, found := m.serviceByTag[tag]
  75. m.access.Unlock()
  76. return service, found
  77. }
  78. func (m *Manager) Remove(tag string) error {
  79. m.access.Lock()
  80. service, found := m.serviceByTag[tag]
  81. if !found {
  82. m.access.Unlock()
  83. return os.ErrInvalid
  84. }
  85. delete(m.serviceByTag, tag)
  86. index := common.Index(m.services, func(it adapter.Service) bool {
  87. return it == service
  88. })
  89. if index == -1 {
  90. panic("invalid service index")
  91. }
  92. m.services = append(m.services[:index], m.services[index+1:]...)
  93. started := m.started
  94. m.access.Unlock()
  95. if started {
  96. return service.Close()
  97. }
  98. return nil
  99. }
  100. func (m *Manager) Create(ctx context.Context, logger log.ContextLogger, tag string, serviceType string, options any) error {
  101. service, err := m.registry.Create(ctx, logger, tag, serviceType, options)
  102. if err != nil {
  103. return err
  104. }
  105. m.access.Lock()
  106. defer m.access.Unlock()
  107. if m.started {
  108. for _, stage := range adapter.ListStartStages {
  109. err = adapter.LegacyStart(service, stage)
  110. if err != nil {
  111. return E.Cause(err, stage, " service/", service.Type(), "[", service.Tag(), "]")
  112. }
  113. }
  114. }
  115. if existsService, loaded := m.serviceByTag[tag]; loaded {
  116. if m.started {
  117. err = existsService.Close()
  118. if err != nil {
  119. return E.Cause(err, "close service/", existsService.Type(), "[", existsService.Tag(), "]")
  120. }
  121. }
  122. existsIndex := common.Index(m.services, func(it adapter.Service) bool {
  123. return it == existsService
  124. })
  125. if existsIndex == -1 {
  126. panic("invalid service index")
  127. }
  128. m.services = append(m.services[:existsIndex], m.services[existsIndex+1:]...)
  129. }
  130. m.services = append(m.services, service)
  131. m.serviceByTag[tag] = service
  132. return nil
  133. }