From aea36939a3003fac6c3532d972f020e9f9d5d981 Mon Sep 17 00:00:00 2001 From: user123456 Date: Tue, 17 Jun 2025 18:18:17 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=94=AF=E6=8C=81=E8=B5=B0?= =?UTF-8?q?=E4=BB=A3=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config.go | 3 ++ src/config.toml | 8 +++++- src/docker.go | 7 +++-- src/http_client.go | 70 ++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 77 insertions(+), 11 deletions(-) diff --git a/src/config.go b/src/config.go index 0d20aa9..0204365 100644 --- a/src/config.go +++ b/src/config.go @@ -42,6 +42,7 @@ type AppConfig struct { Proxy struct { WhiteList []string `toml:"whiteList"` // 代理白名单(仓库级别) BlackList []string `toml:"blackList"` // 代理黑名单(仓库级别) + Socks5 string `toml:"socks5"` // SOCKS5代理地址: socks5://[user:pass@]host:port } `toml:"proxy"` Download struct { @@ -97,9 +98,11 @@ func DefaultConfig() *AppConfig { Proxy: struct { WhiteList []string `toml:"whiteList"` BlackList []string `toml:"blackList"` + Socks5 string `toml:"socks5"` }{ WhiteList: []string{}, BlackList: []string{}, + Socks5: "", // 默认不使用代理 }, Download: struct { MaxImages int `toml:"maxImages"` diff --git a/src/config.toml b/src/config.toml index a716d59..ad85bd2 100644 --- a/src/config.toml +++ b/src/config.toml @@ -37,7 +37,13 @@ blackList = [ "baduser/malicious-repo", "*/malicious-repo", "baduser/*" -] +] + +# SOCKS5代理配置,支持有用户名/密码认证和无认证模式 +# 无认证: socks5://127.0.0.1:1080 +# 有认证: socks5://username:password@127.0.0.1:1080 +# 留空不使用代理 +socks5 = "" [download] # 批量下载离线镜像数量限制 diff --git a/src/docker.go b/src/docker.go index 4b4ebf1..f4813bd 100644 --- a/src/docker.go +++ b/src/docker.go @@ -72,6 +72,7 @@ func initDockerProxy() { options := []remote.Option{ remote.WithAuth(authn.Anonymous), remote.WithUserAgent("hubproxy/go-containerregistry"), + remote.WithTransport(GetGlobalHTTPClient().Transport), } dockerProxy = &DockerProxy{ @@ -407,9 +408,10 @@ func proxyDockerAuthOriginal(c *gin.Context) { authURL += "?" + c.Request.URL.RawQuery } - // 创建HTTP客户端 + // 创建HTTP客户端,复用全局传输配置(包含代理设置) client := &http.Client{ - Timeout: 30 * time.Second, + Timeout: 30 * time.Second, + Transport: GetGlobalHTTPClient().Transport, } // 创建请求 @@ -664,6 +666,7 @@ func createUpstreamOptions(mapping RegistryMapping) []remote.Option { options := []remote.Option{ remote.WithAuth(authn.Anonymous), remote.WithUserAgent("hubproxy/go-containerregistry"), + remote.WithTransport(GetGlobalHTTPClient().Transport), } // 根据Registry类型添加特定的认证选项(方便后续扩展) diff --git a/src/http_client.go b/src/http_client.go index a336521..24d509b 100644 --- a/src/http_client.go +++ b/src/http_client.go @@ -1,9 +1,14 @@ package main import ( + "context" + "log" "net" "net/http" + "net/url" "time" + + "golang.org/x/net/proxy" ) var ( @@ -15,13 +20,65 @@ var ( // initHTTPClients 初始化HTTP客户端 func initHTTPClients() { + cfg := GetConfig() + + // 创建DialContext函数,支持SOCKS5代理 + createDialContext := func(timeout time.Duration) func(ctx context.Context, network, addr string) (net.Conn, error) { + if cfg.Proxy.Socks5 == "" { + // 没有配置代理,使用直连 + dialer := &net.Dialer{ + Timeout: timeout, + KeepAlive: 30 * time.Second, + } + return dialer.DialContext + } + + // 解析SOCKS5代理URL + proxyURL, err := url.Parse(cfg.Proxy.Socks5) + if err != nil { + log.Printf("SOCKS5代理配置错误,使用直连: %v", err) + dialer := &net.Dialer{ + Timeout: timeout, + KeepAlive: 30 * time.Second, + } + return dialer.DialContext + } + + // 创建基础dialer + baseDialer := &net.Dialer{ + Timeout: timeout, + KeepAlive: 30 * time.Second, + } + + // 创建SOCKS5代理dialer + var auth *proxy.Auth + if proxyURL.User != nil { + if password, ok := proxyURL.User.Password(); ok { + auth = &proxy.Auth{ + User: proxyURL.User.Username(), + Password: password, + } + } + } + + socks5Dialer, err := proxy.SOCKS5("tcp", proxyURL.Host, auth, baseDialer) + if err != nil { + log.Printf("创建SOCKS5代理失败,使用直连: %v", err) + return baseDialer.DialContext + } + + log.Printf("使用SOCKS5代理: %s", proxyURL.Host) + + // 返回带上下文的dial函数 + return func(ctx context.Context, network, addr string) (net.Conn, error) { + return socks5Dialer.Dial(network, addr) + } + } + // 代理客户端配置 - 适用于大文件传输 globalHTTPClient = &http.Client{ Transport: &http.Transport{ - DialContext: (&net.Dialer{ - Timeout: 30 * time.Second, - KeepAlive: 30 * time.Second, - }).DialContext, + DialContext: createDialContext(30 * time.Second), MaxIdleConns: 1000, MaxIdleConnsPerHost: 1000, IdleConnTimeout: 90 * time.Second, @@ -35,10 +92,7 @@ func initHTTPClients() { searchHTTPClient = &http.Client{ Timeout: 10 * time.Second, Transport: &http.Transport{ - DialContext: (&net.Dialer{ - Timeout: 5 * time.Second, - KeepAlive: 30 * time.Second, - }).DialContext, + DialContext: createDialContext(5 * time.Second), MaxIdleConns: 100, MaxIdleConnsPerHost: 10, IdleConnTimeout: 90 * time.Second,