Files
Ant-Browser/backend/app_proxy_query.go

186 lines
5.9 KiB
Go

package backend
import (
"ant-chrome/backend/internal/browser"
"ant-chrome/backend/internal/config"
"ant-chrome/backend/internal/proxy"
"strings"
"sync"
"time"
)
func (a *App) BrowserProxyList() []BrowserProxy {
return browser.ListProxiesWithFallback(a.browserMgr.ProxyDAO, a.config.Browser.Proxies)
}
// BrowserProxyListGroups 获取所有代理分组名称
func (a *App) BrowserProxyListGroups() []string {
return browser.ListProxyGroups(a.browserMgr.ProxyDAO)
}
// BrowserProxyListByGroup 按分组名称查询代理
func (a *App) BrowserProxyListByGroup(groupName string) []BrowserProxy {
return browser.ListProxiesByGroupWithFallback(a.browserMgr.ProxyDAO, groupName, a.config.Browser.Proxies)
}
// ValidateProxyConfig 验证代理配置是否支持
func (a *App) ValidateProxyConfig(proxyConfig string, proxyId string) ProxyValidationResult {
proxies := a.getLatestProxies()
supported, errorMsg := proxy.ValidateProxyConfig(proxyConfig, proxies, proxyId)
return ProxyValidationResult{
Supported: supported,
ErrorMsg: errorMsg,
}
}
// TestProxyConnectivity 测试代理连通性
func (a *App) TestProxyConnectivity(proxyId string, proxyConfig string) ProxyTestResult {
proxies := a.getLatestProxies()
result := proxy.TestConnectivity(proxyId, proxyConfig, proxies, nil)
if result.Engine == "" {
result.Engine = "tcp"
}
return buildProxyTestResult(result)
}
// TestProxyRealConnectivity 通过真实 HTTP 请求测试代理连通性(Wails 绑定)
// 参考 Clash URLTest 策略:多 URL fallback + 复用桥接 + TCP ping 降级
func (a *App) TestProxyRealConnectivity(proxyId string) ProxyTestResult {
proxies := a.getLatestProxies()
connectorType := config.NormalizeBrowserConnectorType(a.config.Browser.DefaultConnectorType)
result := proxy.TestRealConnectivityWithRuntimeConfig(proxyId, proxies, a.xrayMgr, a.singboxMgr, a.clashMgr, connectorType, a.proxySpeedTestConfig())
return buildProxyTestResult(result)
}
// BrowserProxyWarmupBridge 只预热本地代理桥接,不执行外网测速。
func (a *App) BrowserProxyWarmupBridge(proxyId string) ProxyBridgeWarmupResult {
proxies := a.getLatestProxies()
return a.warmupProxyBridge(proxyId, "", proxies)
}
// BrowserProxyWarmupBridgeWithConfig 预热指定代理配置,proxyConfig 仅本次预热生效。
func (a *App) BrowserProxyWarmupBridgeWithConfig(proxyId string, proxyConfig string) ProxyBridgeWarmupResult {
proxies := a.getLatestProxies()
return a.warmupProxyBridge(proxyId, proxyConfig, proxies)
}
// BrowserProxyBatchWarmupBridge 批量预热代理桥接,concurrency 控制并发数(默认 5)。
func (a *App) BrowserProxyBatchWarmupBridge(proxyIds []string, concurrency int) []ProxyBridgeWarmupResult {
if len(proxyIds) == 0 {
return []ProxyBridgeWarmupResult{}
}
if concurrency <= 0 {
concurrency = 5
}
if concurrency > len(proxyIds) {
concurrency = len(proxyIds)
}
proxies := a.getLatestProxies()
results := make([]ProxyBridgeWarmupResult, len(proxyIds))
type warmupJob struct {
idx int
proxyId string
}
jobs := make(chan warmupJob, len(proxyIds))
var wg sync.WaitGroup
for worker := 0; worker < concurrency; worker++ {
wg.Add(1)
go func() {
defer wg.Done()
for job := range jobs {
results[job.idx] = a.warmupProxyBridge(job.proxyId, "", proxies)
}
}()
}
for i, proxyID := range proxyIds {
jobs <- warmupJob{idx: i, proxyId: proxyID}
}
close(jobs)
wg.Wait()
return results
}
func (a *App) warmupProxyBridge(proxyId string, proxyConfig string, proxies []BrowserProxy) ProxyBridgeWarmupResult {
startedAt := time.Now()
proxyId = strings.TrimSpace(proxyId)
result := ProxyBridgeWarmupResult{ProxyId: proxyId}
src := strings.TrimSpace(resolveProxyConfigForApp(proxyConfig, proxies, proxyId))
if src == "" {
result.Error = "代理配置为空"
return result
}
resolution, err := proxy.ResolveProxyKernel(src, proxies, proxyId, "")
result.Engine = resolution.Kernel
if err != nil {
result.Error = err.Error()
result.LatencyMs = time.Since(startedAt).Milliseconds()
return result
}
if resolution.Kernel == proxy.ProxyKernelNative {
result.Ok = true
if strings.EqualFold(src, "direct://") {
result.Engine = "direct"
}
result.LatencyMs = time.Since(startedAt).Milliseconds()
return result
}
var socksURL string
switch resolution.Kernel {
case proxy.ProxyKernelMihomo:
if a.clashMgr == nil {
result.Error = "mihomo 管理器不可用,请先下载 Mihomo 内核"
result.LatencyMs = time.Since(startedAt).Milliseconds()
return result
}
socksURL, err = a.clashMgr.EnsureNodeBridge(src, proxies, proxyId)
case proxy.ProxyKernelSingBox:
if a.singboxMgr == nil {
result.Error = "sing-box 管理器不可用"
result.LatencyMs = time.Since(startedAt).Milliseconds()
return result
}
socksURL, err = a.singboxMgr.EnsureBridge(src, proxies, proxyId)
case proxy.ProxyKernelXray:
if a.xrayMgr == nil {
result.Error = "xray 管理器不可用"
result.LatencyMs = time.Since(startedAt).Milliseconds()
return result
}
socksURL, err = a.xrayMgr.EnsureBridge(src, proxies, proxyId)
default:
result.Error = "无法选择代理内核"
result.LatencyMs = time.Since(startedAt).Milliseconds()
return result
}
result.LatencyMs = time.Since(startedAt).Milliseconds()
if err != nil {
result.Error = err.Error()
return result
}
result.Ok = true
result.SocksURL = socksURL
return result
}
func resolveProxyConfigForApp(proxyConfig string, proxies []BrowserProxy, proxyId string) string {
proxyConfig = strings.TrimSpace(proxyConfig)
proxyId = strings.TrimSpace(proxyId)
if proxyId == "" {
return proxyConfig
}
for _, item := range proxies {
if strings.EqualFold(item.ProxyId, proxyId) {
return strings.TrimSpace(item.ProxyConfig)
}
}
return proxyConfig
}
// getLatestProxies 获取最新的代理列表,优先从数据库读取
func (a *App) getLatestProxies() []BrowserProxy {
return browser.LatestProxiesWithFallback(a.browserMgr.ProxyDAO, a.config.Browser.Proxies)
}