- errcheck: 修复类型断言未检查返回值的问题 - pool.go: 添加 sync.Map 类型断言安全检查 - req_client_pool.go: 添加 sync.Map 类型断言安全检查 - concurrency_cache_benchmark_test.go: 显式忽略断言返回值 - gateway_service.go: 显式忽略 WriteString 返回值 - gofmt: 修复代码格式问题 - redis.go: 注释对齐 - api_key_repo.go: 结构体字段对齐 - concurrency_cache.go: 字段对齐 - http_upstream.go: 注释对齐 - unused: 删除未使用的代码 - user_repo.go: 删除未使用的 sql 字段 - usage_service.go: 删除未使用的 calculateStats 函数 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
65 lines
1.8 KiB
Go
65 lines
1.8 KiB
Go
package repository
|
||
|
||
import (
|
||
"fmt"
|
||
"strings"
|
||
"sync"
|
||
"time"
|
||
|
||
"github.com/imroc/req/v3"
|
||
)
|
||
|
||
// reqClientOptions 定义 req 客户端的构建参数
|
||
type reqClientOptions struct {
|
||
ProxyURL string // 代理 URL(支持 http/https/socks5)
|
||
Timeout time.Duration // 请求超时时间
|
||
Impersonate bool // 是否模拟 Chrome 浏览器指纹
|
||
}
|
||
|
||
// sharedReqClients 存储按配置参数缓存的 req 客户端实例
|
||
//
|
||
// 性能优化说明:
|
||
// 原实现在每次 OAuth 刷新时都创建新的 req.Client:
|
||
// 1. claude_oauth_service.go: 每次刷新创建新客户端
|
||
// 2. openai_oauth_service.go: 每次刷新创建新客户端
|
||
// 3. gemini_oauth_client.go: 每次刷新创建新客户端
|
||
//
|
||
// 新实现使用 sync.Map 缓存客户端:
|
||
// 1. 相同配置(代理+超时+模拟设置)复用同一客户端
|
||
// 2. 复用底层连接池,减少 TLS 握手开销
|
||
// 3. LoadOrStore 保证并发安全,避免重复创建
|
||
var sharedReqClients sync.Map
|
||
|
||
// getSharedReqClient 获取共享的 req 客户端实例
|
||
// 性能优化:相同配置复用同一客户端,避免重复创建
|
||
func getSharedReqClient(opts reqClientOptions) *req.Client {
|
||
key := buildReqClientKey(opts)
|
||
if cached, ok := sharedReqClients.Load(key); ok {
|
||
if c, ok := cached.(*req.Client); ok {
|
||
return c
|
||
}
|
||
}
|
||
|
||
client := req.C().SetTimeout(opts.Timeout)
|
||
if opts.Impersonate {
|
||
client = client.ImpersonateChrome()
|
||
}
|
||
if strings.TrimSpace(opts.ProxyURL) != "" {
|
||
client.SetProxyURL(strings.TrimSpace(opts.ProxyURL))
|
||
}
|
||
|
||
actual, _ := sharedReqClients.LoadOrStore(key, client)
|
||
if c, ok := actual.(*req.Client); ok {
|
||
return c
|
||
}
|
||
return client
|
||
}
|
||
|
||
func buildReqClientKey(opts reqClientOptions) string {
|
||
return fmt.Sprintf("%s|%s|%t",
|
||
strings.TrimSpace(opts.ProxyURL),
|
||
opts.Timeout.String(),
|
||
opts.Impersonate,
|
||
)
|
||
}
|