manager.go 4.1 KB

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