github.com/sagernet/sing-box@v1.9.0-rc.20/route/rule_set.go (about) 1 package route 2 3 import ( 4 "context" 5 "net" 6 "net/http" 7 "sync" 8 9 "github.com/sagernet/sing-box/adapter" 10 C "github.com/sagernet/sing-box/constant" 11 "github.com/sagernet/sing-box/option" 12 E "github.com/sagernet/sing/common/exceptions" 13 "github.com/sagernet/sing/common/logger" 14 M "github.com/sagernet/sing/common/metadata" 15 N "github.com/sagernet/sing/common/network" 16 ) 17 18 func NewRuleSet(ctx context.Context, router adapter.Router, logger logger.ContextLogger, options option.RuleSet) (adapter.RuleSet, error) { 19 switch options.Type { 20 case C.RuleSetTypeLocal: 21 return NewLocalRuleSet(router, options) 22 case C.RuleSetTypeRemote: 23 return NewRemoteRuleSet(ctx, router, logger, options), nil 24 default: 25 return nil, E.New("unknown rule set type: ", options.Type) 26 } 27 } 28 29 var _ adapter.RuleSetStartContext = (*RuleSetStartContext)(nil) 30 31 type RuleSetStartContext struct { 32 access sync.Mutex 33 httpClientCache map[string]*http.Client 34 } 35 36 func NewRuleSetStartContext() *RuleSetStartContext { 37 return &RuleSetStartContext{ 38 httpClientCache: make(map[string]*http.Client), 39 } 40 } 41 42 func (c *RuleSetStartContext) HTTPClient(detour string, dialer N.Dialer) *http.Client { 43 c.access.Lock() 44 defer c.access.Unlock() 45 if httpClient, loaded := c.httpClientCache[detour]; loaded { 46 return httpClient 47 } 48 httpClient := &http.Client{ 49 Transport: &http.Transport{ 50 ForceAttemptHTTP2: true, 51 TLSHandshakeTimeout: C.TCPTimeout, 52 DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { 53 return dialer.DialContext(ctx, network, M.ParseSocksaddr(addr)) 54 }, 55 }, 56 } 57 c.httpClientCache[detour] = httpClient 58 return httpClient 59 } 60 61 func (c *RuleSetStartContext) Close() { 62 c.access.Lock() 63 defer c.access.Unlock() 64 for _, client := range c.httpClientCache { 65 client.CloseIdleConnections() 66 } 67 }