lazy.go 1.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. package dialer
  2. import (
  3. "context"
  4. "net"
  5. "sync"
  6. "github.com/sagernet/sing-box/adapter"
  7. "github.com/sagernet/sing-box/config"
  8. E "github.com/sagernet/sing/common/exceptions"
  9. M "github.com/sagernet/sing/common/metadata"
  10. N "github.com/sagernet/sing/common/network"
  11. )
  12. type LazyDialer struct {
  13. router adapter.Router
  14. options config.DialerOptions
  15. dialer N.Dialer
  16. initOnce sync.Once
  17. initErr error
  18. }
  19. func NewDialer(router adapter.Router, options config.DialerOptions) N.Dialer {
  20. return &LazyDialer{
  21. router: router,
  22. options: options,
  23. }
  24. }
  25. func (d *LazyDialer) Dialer() (N.Dialer, error) {
  26. d.initOnce.Do(func() {
  27. if d.options.Detour != "" {
  28. var loaded bool
  29. d.dialer, loaded = d.router.Outbound(d.options.Detour)
  30. if !loaded {
  31. d.initErr = E.New("outbound detour not found: ", d.options.Detour)
  32. }
  33. } else {
  34. d.dialer = newDialer(d.options)
  35. }
  36. })
  37. return d.dialer, d.initErr
  38. }
  39. func (d *LazyDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
  40. dialer, err := d.Dialer()
  41. if err != nil {
  42. return nil, err
  43. }
  44. return dialer.DialContext(ctx, network, destination)
  45. }
  46. func (d *LazyDialer) ListenPacket(ctx context.Context) (net.PacketConn, error) {
  47. dialer, err := d.Dialer()
  48. if err != nil {
  49. return nil, err
  50. }
  51. return dialer.ListenPacket(ctx)
  52. }