| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859 |
- package network
-
- import (
- "context"
- "fmt"
- "math/rand/v2"
- "net/url"
-
- "github.com/9seconds/mtg/v2/essentials"
- )
-
- type loadBalancedSocks5Dialer struct {
- dialers []Dialer
- }
-
- func (l loadBalancedSocks5Dialer) Dial(network, address string) (essentials.Conn, error) {
- return l.DialContext(context.Background(), network, address)
- }
-
- func (l loadBalancedSocks5Dialer) DialContext(ctx context.Context, network, address string) (essentials.Conn, error) {
- length := len(l.dialers)
- start := rand.IntN(length)
- moved := false
-
- for i := start; i != start || !moved; i = (i + 1) % length {
- moved = true
-
- if conn, err := l.dialers[i].DialContext(ctx, network, address); err == nil {
- return conn, nil
- }
- }
-
- return nil, ErrCannotDialWithAllProxies
- }
-
- // NewLoadBalancedSocks5Dialer builds a new load balancing SOCKS5 dialer.
- //
- // The main difference from one which is made by NewSocks5Dialer is that we
- // actually have a list of these proxies. When dial is requested, any proxy is
- // picked and used. If proxy fails for some reason, we try another one.
- //
- // So, it is mostly useful if you have some routes with proxies which are not
- // always online or having buggy network.
- func NewLoadBalancedSocks5Dialer(baseDialer Dialer, proxyURLs []*url.URL) (Dialer, error) {
- dialers := make([]Dialer, 0, len(proxyURLs))
-
- for _, u := range proxyURLs {
- dialer, err := NewSocks5Dialer(newProxyDialer(baseDialer, u), u)
- if err != nil {
- return nil, fmt.Errorf("cannot build dialer for %s: %w", u.String(), err)
- }
-
- dialers = append(dialers, dialer)
- }
-
- return loadBalancedSocks5Dialer{
- dialers: dialers,
- }, nil
- }
|