Support network proxies

This commit is contained in:
Ben Sarmiento
2024-01-11 04:15:40 +01:00
parent dfa3ef99b0
commit b2e02c7e1f
5 changed files with 66 additions and 34 deletions

View File

@@ -10,6 +10,12 @@ port: 9999
# username: yowmamasita # username: yowmamasita
# password: 1234 # password: 1234
# You can proxy all zurg requests like this:
# proxy: "http://[username:password@]host:port"
# proxy: "https://[username:password@]host:port"
# proxy: "socks4://[username@]host:port"
# proxy: "socks5://[username:password@]host:port"
# How many requests in parallel should we send to Real-Debrid API? # How many requests in parallel should we send to Real-Debrid API?
concurrent_workers: 20 concurrent_workers: 20

1
go.mod
View File

@@ -20,6 +20,7 @@ require (
github.com/go-chi/chi/v5 v5.0.11 // indirect github.com/go-chi/chi/v5 v5.0.11 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
golang.org/x/net v0.20.0 // indirect
) )
require ( require (

2
go.sum
View File

@@ -42,6 +42,8 @@ go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=

View File

@@ -13,6 +13,7 @@ type ConfigInterface interface {
GetPort() string GetPort() string
GetUsername() string GetUsername() string
GetPassword() string GetPassword() string
GetProxy() string
GetDirectories() []string GetDirectories() []string
MeetsConditions(directory, torrentName string, torrentSize int64, torrentIDs, fileNames []string, fileSizes []int64) bool MeetsConditions(directory, torrentName string, torrentSize int64, torrentIDs, fileNames []string, fileSizes []int64) bool
GetOnLibraryUpdate() string GetOnLibraryUpdate() string
@@ -39,6 +40,7 @@ type ZurgConfig struct {
Port string `yaml:"port" json:"port"` Port string `yaml:"port" json:"port"`
Username string `yaml:"username" json:"username"` Username string `yaml:"username" json:"username"`
Password string `yaml:"password" json:"password"` Password string `yaml:"password" json:"password"`
Proxy string `yaml:"proxy" json:"proxy"`
NumOfWorkers int `yaml:"concurrent_workers" json:"concurrent_workers"` NumOfWorkers int `yaml:"concurrent_workers" json:"concurrent_workers"`
RefreshEverySeconds int `yaml:"check_for_changes_every_secs" json:"check_for_changes_every_secs"` RefreshEverySeconds int `yaml:"check_for_changes_every_secs" json:"check_for_changes_every_secs"`
@@ -92,6 +94,10 @@ func (z *ZurgConfig) GetPassword() string {
return z.Password return z.Password
} }
func (z *ZurgConfig) GetProxy() string {
return z.Proxy
}
func (z *ZurgConfig) GetNumOfWorkers() int { func (z *ZurgConfig) GetNumOfWorkers() int {
if z.NumOfWorkers == 0 { if z.NumOfWorkers == 0 {
return 50 return 50

View File

@@ -9,12 +9,14 @@ import (
"math/rand" "math/rand"
"net" "net"
"net/http" "net/http"
"net/url"
"strings" "strings"
"time" "time"
"github.com/debridmediamanager/zurg/internal/config" "github.com/debridmediamanager/zurg/internal/config"
"github.com/debridmediamanager/zurg/pkg/hosts" "github.com/debridmediamanager/zurg/pkg/hosts"
"github.com/debridmediamanager/zurg/pkg/logutil" "github.com/debridmediamanager/zurg/pkg/logutil"
"golang.org/x/net/proxy"
cmap "github.com/orcaman/concurrent-map/v2" cmap "github.com/orcaman/concurrent-map/v2"
) )
@@ -110,23 +112,35 @@ func NewHTTPClient(token string, maxRetries int, timeoutSecs int, ensureIPv6Host
log: log, log: log,
} }
if !cfg.ShouldForceIPv6() { var dialer proxy.Dialer = &net.Dialer{}
return &client if proxyURLString := cfg.GetProxy(); proxyURLString != "" {
proxyURL, err := url.Parse(proxyURLString)
if err != nil {
log.Errorf("Failed to parse proxy URL: %v", err)
return nil
}
proxyDialer, err := proxy.FromURL(proxyURL, dialer)
if err != nil {
log.Errorf("Failed to create proxy dialer: %v", err)
return nil
}
dialer = proxyDialer
} }
// set ipv6 hosts if cfg.ShouldForceIPv6() {
ipv6List, err := hosts.FetchHosts(hosts.IPV6) ipv6List, err := hosts.FetchHosts(hosts.IPV6)
if err != nil { if err != nil {
log.Warnf("Failed to fetch IPv6 hosts: %v", err) log.Warnf("Failed to fetch IPv6 hosts: %v", err)
} // Decide if you want to return nil here or continue without IPv6
} else {
client.ipv6Hosts = ipv6List client.ipv6Hosts = ipv6List
log.Debugf("Fetched %d IPv6 hosts", len(ipv6List)) log.Debugf("Fetched %d IPv6 hosts", len(ipv6List))
}
// set ipv6 transport client.client.Transport = &http.Transport{
dialer := &net.Dialer{} DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
dialContext := func(ctx context.Context, network, address string) (net.Conn, error) {
if ipv6Address, ok := client.ipv6.Get(address); ok { if ipv6Address, ok := client.ipv6.Get(address); ok {
return dialer.DialContext(ctx, network, ipv6Address) return dialer.Dial(network, ipv6Address)
} }
host, port, err := net.SplitHostPort(address) host, port, err := net.SplitHostPort(address)
if err != nil { if err != nil {
@@ -138,18 +152,21 @@ func NewHTTPClient(token string, maxRetries int, timeoutSecs int, ensureIPv6Host
} }
for _, ip := range ips { for _, ip := range ips {
if ip.IP.To4() == nil { // IPv6 address found if ip.IP.To4() == nil { // IPv6 address found
ip6Host := ip.IP.String() ipv6Address := net.JoinHostPort(ip.IP.String(), port)
ipv6Address := net.JoinHostPort(ip6Host, port)
client.ipv6.Set(address, ipv6Address) client.ipv6.Set(address, ipv6Address)
return dialer.DialContext(ctx, network, ipv6Address) return dialer.Dial(network, ipv6Address)
} }
} }
return dialer.DialContext(ctx, network, address) return dialer.Dial(network, address)
},
}
} else {
client.client.Transport = &http.Transport{
DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
return dialer.Dial(network, address)
},
} }
transport := &http.Transport{
DialContext: dialContext,
} }
client.client.Transport = transport
return &client return &client
} }