manager.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  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. transports map[string]*Transport
  21. defaultTag string
  22. defaultTransport adapter.HTTPTransport
  23. defaultTransportFallback func() (*Transport, error)
  24. fallbackTransport *Transport
  25. }
  26. func NewManager(ctx context.Context, logger log.ContextLogger, clients []option.HTTPClient, defaultHTTPClient string) *Manager {
  27. defines := make(map[string]option.HTTPClient, len(clients))
  28. for _, client := range clients {
  29. defines[client.Tag] = client
  30. }
  31. defaultTag := defaultHTTPClient
  32. if defaultTag == "" && len(clients) > 0 {
  33. defaultTag = clients[0].Tag
  34. }
  35. return &Manager{
  36. ctx: ctx,
  37. logger: logger,
  38. defines: defines,
  39. transports: make(map[string]*Transport),
  40. defaultTag: defaultTag,
  41. }
  42. }
  43. func (m *Manager) Initialize(defaultTransportFallback func() (*Transport, error)) {
  44. m.defaultTransportFallback = defaultTransportFallback
  45. }
  46. func (m *Manager) Name() string {
  47. return "http-client"
  48. }
  49. func (m *Manager) Start(stage adapter.StartStage) error {
  50. if stage != adapter.StartStateStart {
  51. return nil
  52. }
  53. if m.defaultTag != "" {
  54. transport, err := m.resolveShared(m.defaultTag)
  55. if err != nil {
  56. return E.Cause(err, "resolve default http client")
  57. }
  58. m.defaultTransport = transport
  59. } else if m.defaultTransportFallback != nil {
  60. transport, err := m.defaultTransportFallback()
  61. if err != nil {
  62. return E.Cause(err, "create default http client")
  63. }
  64. m.defaultTransport = transport
  65. m.fallbackTransport = transport
  66. }
  67. return nil
  68. }
  69. func (m *Manager) DefaultTransport() adapter.HTTPTransport {
  70. if m.defaultTransport == nil {
  71. return nil
  72. }
  73. return &sharedTransport{m.defaultTransport}
  74. }
  75. func (m *Manager) ResolveTransport(ctx context.Context, logger logger.ContextLogger, options option.HTTPClientOptions) (adapter.HTTPTransport, error) {
  76. if options.Tag != "" {
  77. if options.ResolveOnDetour {
  78. define, loaded := m.defines[options.Tag]
  79. if !loaded {
  80. return nil, E.New("http_client not found: ", options.Tag)
  81. }
  82. resolvedOptions := define.Options()
  83. resolvedOptions.ResolveOnDetour = true
  84. return NewTransport(ctx, logger, options.Tag, resolvedOptions)
  85. }
  86. transport, err := m.resolveShared(options.Tag)
  87. if err != nil {
  88. return nil, err
  89. }
  90. return &sharedTransport{transport}, nil
  91. }
  92. return NewTransport(ctx, logger, "", options)
  93. }
  94. func (m *Manager) resolveShared(tag string) (adapter.HTTPTransport, error) {
  95. m.access.Lock()
  96. defer m.access.Unlock()
  97. if transport, loaded := m.transports[tag]; loaded {
  98. return transport, nil
  99. }
  100. define, loaded := m.defines[tag]
  101. if !loaded {
  102. return nil, E.New("http_client not found: ", tag)
  103. }
  104. transport, err := NewTransport(m.ctx, m.logger, tag, define.Options())
  105. if err != nil {
  106. return nil, E.Cause(err, "create shared http_client[", tag, "]")
  107. }
  108. m.transports[tag] = transport
  109. return transport, nil
  110. }
  111. type sharedTransport struct {
  112. adapter.HTTPTransport
  113. }
  114. func (t *sharedTransport) CloseIdleConnections() {
  115. }
  116. func (t *sharedTransport) Close() error {
  117. return nil
  118. }
  119. func (m *Manager) ResetNetwork() {
  120. m.access.Lock()
  121. defer m.access.Unlock()
  122. for _, transport := range m.transports {
  123. transport.CloseIdleConnections()
  124. }
  125. if m.fallbackTransport != nil {
  126. m.fallbackTransport.CloseIdleConnections()
  127. }
  128. }
  129. func (m *Manager) Close() error {
  130. m.access.Lock()
  131. defer m.access.Unlock()
  132. if m.transports == nil {
  133. return nil
  134. }
  135. var err error
  136. for _, transport := range m.transports {
  137. err = E.Append(err, transport.Close(), func(err error) error {
  138. return E.Cause(err, "close http client")
  139. })
  140. }
  141. if m.fallbackTransport != nil {
  142. err = E.Append(err, m.fallbackTransport.Close(), func(err error) error {
  143. return E.Cause(err, "close default http client")
  144. })
  145. }
  146. m.transports = nil
  147. return err
  148. }