新增对象存储/账单/保留IP模块,删桶并发提速与成本增强
CI / test (push) Successful in 33s

This commit is contained in:
2026-07-21 12:11:05 +08:00
parent 9cfde8b702
commit f40f2a20e8
44 changed files with 7788 additions and 54 deletions
+39 -11
View File
@@ -5,6 +5,7 @@ import (
"net"
"net/http"
"net/url"
"sync"
"time"
"golang.org/x/net/proxy"
@@ -31,6 +32,20 @@ const (
proxyTLSHandshakeTimeout = 10 * time.Second
)
// 连接池参数:PerHost 须 > 批量删除并发数(service 层 16)——并发拨号竞速时
// Transport 会投机新建连接,池上限过紧会让这些连接用一次即被丢弃(churn);
// IdleConnTimeout 显式关闭空闲连接(零值=永不关,只能等远端 ~65s 断开,连接会堆积)。
const (
proxyMaxIdleConns = 128
proxyMaxIdleConnsPerHost = 32
proxyIdleConnTimeout = 90 * time.Second
)
// proxyClients 按代理配置复用 http.Client。SDK client 每次操作新建,
// 若 Transport 也随之新建则连接零复用:每个请求都要付完整的
// TCP+SOCKS/CONNECT+TLS 握手(经代理 3+ 个 RTT),批量操作被拖到分钟级。
var proxyClients sync.Map // ProxySpec(值) → *http.Client
// applyProxy 在 SDK client 构造后统一挂出站代理;未关联代理时不动默认配置。
// 所有 New*ClientWithConfigurationProvider 调用点构造成功后都必须经过这里。
func applyProxy(base *common.BaseClient, cred Credentials) {
@@ -39,16 +54,21 @@ func applyProxy(base *common.BaseClient, cred Credentials) {
}
}
// proxyHTTPClient 按代理配置构造 http.Client;nil 或非法配置返回 nil(走直连)。
// proxyHTTPClient 按代理配置取共享 http.Client;nil 或非法配置返回 nil(走直连)。
// 同配置复用同一实例(连接池随之复用);调用方只可包装、不得改写其字段。
func proxyHTTPClient(p *ProxySpec) *http.Client {
if p == nil || p.Host == "" || p.Port <= 0 {
return nil
}
if v, ok := proxyClients.Load(*p); ok {
return v.(*http.Client)
}
tr := transportFor(p)
if tr == nil {
return nil
}
return &http.Client{Transport: tr, Timeout: proxyClientTimeout}
v, _ := proxyClients.LoadOrStore(*p, &http.Client{Transport: tr, Timeout: proxyClientTimeout})
return v.(*http.Client)
}
// HTTPClientFor 供面板自身请求(如代理出口地理探测)复用与租户 SDK
@@ -57,6 +77,16 @@ func HTTPClientFor(p *ProxySpec) *http.Client {
return proxyHTTPClient(p)
}
// pooledTransport 连接池参数统一的 Transport 骨架;阶段超时见常量注释。
func pooledTransport() *http.Transport {
return &http.Transport{
TLSHandshakeTimeout: proxyTLSHandshakeTimeout,
MaxIdleConns: proxyMaxIdleConns,
MaxIdleConnsPerHost: proxyMaxIdleConnsPerHost,
IdleConnTimeout: proxyIdleConnTimeout,
}
}
// transportFor 构造代理 Transport:http / https 走 CONNECT,socks5 走拨号器。
func transportFor(p *ProxySpec) *http.Transport {
addr := fmt.Sprintf("%s:%d", p.Host, p.Port)
@@ -66,11 +96,10 @@ func transportFor(p *ProxySpec) *http.Transport {
if p.Username != "" {
u.User = url.UserPassword(p.Username, p.Password)
}
return &http.Transport{
Proxy: http.ProxyURL(u),
DialContext: dialer.DialContext,
TLSHandshakeTimeout: proxyTLSHandshakeTimeout,
}
tr := pooledTransport()
tr.Proxy = http.ProxyURL(u)
tr.DialContext = dialer.DialContext
return tr
}
var auth *proxy.Auth
if p.Username != "" {
@@ -84,8 +113,7 @@ func transportFor(p *ProxySpec) *http.Transport {
if !ok {
return nil
}
return &http.Transport{
DialContext: cd.DialContext,
TLSHandshakeTimeout: proxyTLSHandshakeTimeout,
}
tr := pooledTransport()
tr.DialContext = cd.DialContext
return tr
}