manager.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. package httpclient
  2. import (
  3. "context"
  4. "sync"
  5. "github.com/sagernet/sing-box/adapter"
  6. "github.com/sagernet/sing-box/log"
  7. "github.com/sagernet/sing-box/option"
  8. E "github.com/sagernet/sing/common/exceptions"
  9. "github.com/sagernet/sing/common/logger"
  10. )
  11. var (
  12. _ adapter.HTTPClientManager = (*Manager)(nil)
  13. _ adapter.LifecycleService = (*Manager)(nil)
  14. )
  15. type Manager struct {
  16. ctx context.Context
  17. logger log.ContextLogger
  18. access sync.Mutex
  19. defines map[string]option.HTTPClient
  20. sharedTransports map[string]*sharedManagedTransport
  21. managedTransports []*ManagedTransport
  22. defaultTag string
  23. defaultTransport *sharedManagedTransport
  24. defaultTransportFallback func() (*ManagedTransport, error)
  25. }
  26. type sharedManagedTransport struct {
  27. managed *ManagedTransport
  28. shared *sharedState
  29. }
  30. func NewManager(ctx context.Context, logger log.ContextLogger, clients []option.HTTPClient, defaultHTTPClient string) *Manager {
  31. defines := make(map[string]option.HTTPClient, len(clients))
  32. for _, client := range clients {
  33. defines[client.Tag] = client
  34. }
  35. defaultTag := defaultHTTPClient
  36. if defaultTag == "" && len(clients) > 0 {
  37. defaultTag = clients[0].Tag
  38. }
  39. return &Manager{
  40. ctx: ctx,
  41. logger: logger,
  42. defines: defines,
  43. sharedTransports: make(map[string]*sharedManagedTransport),
  44. defaultTag: defaultTag,
  45. }
  46. }
  47. func (m *Manager) Initialize(defaultTransportFallback func() (*ManagedTransport, error)) {
  48. m.defaultTransportFallback = defaultTransportFallback
  49. }
  50. func (m *Manager) Name() string {
  51. return "http-client"
  52. }
  53. func (m *Manager) Start(stage adapter.StartStage) error {
  54. if stage != adapter.StartStateStart {
  55. return nil
  56. }
  57. if m.defaultTag != "" {
  58. sharedTransport, err := m.resolveShared(m.defaultTag)
  59. if err != nil {
  60. return E.Cause(err, "resolve default http client")
  61. }
  62. m.defaultTransport = sharedTransport
  63. }
  64. return nil
  65. }
  66. func (m *Manager) DefaultTransport() adapter.HTTPTransport {
  67. m.access.Lock()
  68. defer m.access.Unlock()
  69. if m.defaultTransport == nil && m.defaultTransportFallback != nil {
  70. transport, err := m.defaultTransportFallback()
  71. if err != nil {
  72. m.logger.Error(E.Cause(err, "create default http client"))
  73. return nil
  74. }
  75. m.managedTransports = append(m.managedTransports, transport)
  76. m.defaultTransport = &sharedManagedTransport{
  77. managed: transport,
  78. shared: &sharedState{},
  79. }
  80. }
  81. if m.defaultTransport == nil {
  82. return nil
  83. }
  84. return newSharedRef(m.defaultTransport.managed, m.defaultTransport.shared)
  85. }
  86. func (m *Manager) ResolveTransport(ctx context.Context, logger logger.ContextLogger, options option.HTTPClientOptions) (adapter.HTTPTransport, error) {
  87. if options.Tag != "" {
  88. if options.ResolveOnDetour {
  89. define, loaded := m.defines[options.Tag]
  90. if !loaded {
  91. return nil, E.New("http_client not found: ", options.Tag)
  92. }
  93. resolvedOptions := define.Options()
  94. resolvedOptions.ResolveOnDetour = true
  95. transport, err := NewTransport(ctx, logger, options.Tag, resolvedOptions)
  96. if err != nil {
  97. return nil, err
  98. }
  99. m.trackTransport(transport)
  100. return transport, nil
  101. }
  102. sharedTransport, err := m.resolveShared(options.Tag)
  103. if err != nil {
  104. return nil, err
  105. }
  106. return newSharedRef(sharedTransport.managed, sharedTransport.shared), nil
  107. }
  108. transport, err := NewTransport(ctx, logger, "", options)
  109. if err != nil {
  110. return nil, err
  111. }
  112. m.trackTransport(transport)
  113. return transport, nil
  114. }
  115. func (m *Manager) trackTransport(transport *ManagedTransport) {
  116. m.access.Lock()
  117. defer m.access.Unlock()
  118. m.managedTransports = append(m.managedTransports, transport)
  119. }
  120. func (m *Manager) resolveShared(tag string) (*sharedManagedTransport, error) {
  121. m.access.Lock()
  122. defer m.access.Unlock()
  123. if sharedTransport, loaded := m.sharedTransports[tag]; loaded {
  124. return sharedTransport, nil
  125. }
  126. define, loaded := m.defines[tag]
  127. if !loaded {
  128. return nil, E.New("http_client not found: ", tag)
  129. }
  130. transport, err := NewTransport(m.ctx, m.logger, tag, define.Options())
  131. if err != nil {
  132. return nil, E.Cause(err, "create shared http_client[", tag, "]")
  133. }
  134. sharedTransport := &sharedManagedTransport{
  135. managed: transport,
  136. shared: &sharedState{},
  137. }
  138. m.sharedTransports[tag] = sharedTransport
  139. m.managedTransports = append(m.managedTransports, transport)
  140. return sharedTransport, nil
  141. }
  142. func (m *Manager) ResetNetwork() {
  143. m.access.Lock()
  144. defer m.access.Unlock()
  145. for _, transport := range m.managedTransports {
  146. transport.Reset()
  147. }
  148. }
  149. func (m *Manager) Close() error {
  150. m.access.Lock()
  151. defer m.access.Unlock()
  152. if m.managedTransports == nil {
  153. return nil
  154. }
  155. var err error
  156. for _, transport := range m.managedTransports {
  157. err = E.Append(err, transport.close(), func(err error) error {
  158. return E.Cause(err, "close http client")
  159. })
  160. }
  161. m.managedTransports = nil
  162. m.sharedTransports = nil
  163. return err
  164. }