mirror of
https://github.com/black-ant/Ant-Browser.git
synced 2026-07-14 18:48:55 +08:00
fix: measure proxy latency through browser bridge
This commit is contained in:
@@ -73,7 +73,7 @@ func (a *App) backupReloadAfterMutation() error {
|
||||
a.speedScheduler = browser.NewProxySpeedScheduler(
|
||||
a.browserMgr.ProxyDAO,
|
||||
func(proxyID string) (bool, int64, string) {
|
||||
r := proxy.SpeedTest(proxyID, a.config.Browser.Proxies, a.xrayMgr, a.singboxMgr, nil)
|
||||
r := proxy.TestRealConnectivityWithConfig(proxyID, a.config.Browser.Proxies, a.xrayMgr, a.singboxMgr, nil)
|
||||
return r.Ok, r.LatencyMs, r.Error
|
||||
},
|
||||
5*time.Minute,
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
// BrowserProxyTestSpeed 手动触发单个代理测速并持久化结果
|
||||
func (a *App) BrowserProxyTestSpeed(proxyId string) ProxyTestResult {
|
||||
proxies := a.getLatestProxies()
|
||||
result := proxy.SpeedTest(proxyId, proxies, a.xrayMgr, a.singboxMgr, a.proxySpeedTestConfig())
|
||||
result := proxy.TestRealConnectivityWithConfig(proxyId, proxies, a.xrayMgr, a.singboxMgr, a.proxySpeedTestConfig())
|
||||
if a.browserMgr.ProxyDAO != nil {
|
||||
testedAt := time.Now().Format(time.RFC3339)
|
||||
_ = a.browserMgr.ProxyDAO.UpdateSpeedResult(proxyId, result.Ok, result.LatencyMs, testedAt)
|
||||
@@ -23,13 +23,16 @@ func (a *App) BrowserProxyTestSpeed(proxyId string) ProxyTestResult {
|
||||
return ProxyTestResult{ProxyId: result.ProxyId, Ok: result.Ok, LatencyMs: result.LatencyMs, Error: result.Error}
|
||||
}
|
||||
|
||||
// BrowserProxyBatchTestSpeed 批量并发测速,concurrency 控制并发数(默认 20)
|
||||
// BrowserProxyBatchTestSpeed 批量并发测速,concurrency 控制并发数(默认 5,最高 5)。
|
||||
func (a *App) BrowserProxyBatchTestSpeed(proxyIds []string, concurrency int) []ProxyTestResult {
|
||||
if len(proxyIds) == 0 {
|
||||
return []ProxyTestResult{}
|
||||
}
|
||||
if concurrency <= 0 {
|
||||
concurrency = 20
|
||||
concurrency = 5
|
||||
}
|
||||
if concurrency > 5 {
|
||||
concurrency = 5
|
||||
}
|
||||
if concurrency > len(proxyIds) {
|
||||
concurrency = len(proxyIds)
|
||||
@@ -49,7 +52,7 @@ func (a *App) BrowserProxyBatchTestSpeed(proxyIds []string, concurrency int) []P
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for job := range jobs {
|
||||
result := proxy.SpeedTest(job.ProxyId, proxies, a.xrayMgr, a.singboxMgr, a.proxySpeedTestConfig())
|
||||
result := proxy.TestRealConnectivityWithConfig(job.ProxyId, proxies, a.xrayMgr, a.singboxMgr, a.proxySpeedTestConfig())
|
||||
if a.browserMgr.ProxyDAO != nil {
|
||||
testedAt := time.Now().Format(time.RFC3339)
|
||||
_ = a.browserMgr.ProxyDAO.UpdateSpeedResult(job.ProxyId, result.Ok, result.LatencyMs, testedAt)
|
||||
|
||||
@@ -43,7 +43,7 @@ func (a *App) TestProxyConnectivity(proxyId string, proxyConfig string) ProxyTes
|
||||
// 参考 Clash URLTest 策略:多 URL fallback + 复用桥接 + TCP ping 降级
|
||||
func (a *App) TestProxyRealConnectivity(proxyId string) ProxyTestResult {
|
||||
proxies := a.getLatestProxies()
|
||||
result := proxy.SpeedTest(proxyId, proxies, a.xrayMgr, a.singboxMgr, nil)
|
||||
result := proxy.TestRealConnectivityWithConfig(proxyId, proxies, a.xrayMgr, a.singboxMgr, nil)
|
||||
return ProxyTestResult{ProxyId: result.ProxyId, Ok: result.Ok, LatencyMs: result.LatencyMs, Error: result.Error}
|
||||
}
|
||||
|
||||
|
||||
@@ -202,7 +202,7 @@ func (a *App) startupInitSpeedScheduler() {
|
||||
a.speedScheduler = browser.NewProxySpeedScheduler(
|
||||
a.browserMgr.ProxyDAO,
|
||||
func(proxyId string) (bool, int64, string) {
|
||||
r := proxy.SpeedTest(proxyId, a.config.Browser.Proxies, a.xrayMgr, a.singboxMgr, nil)
|
||||
r := proxy.TestRealConnectivityWithConfig(proxyId, a.config.Browser.Proxies, a.xrayMgr, a.singboxMgr, nil)
|
||||
return r.Ok, r.LatencyMs, r.Error
|
||||
},
|
||||
5*time.Minute,
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"ant-chrome/backend/internal/config"
|
||||
)
|
||||
|
||||
func TestXrayRuntimeConfigUsesWarningLogLevel(t *testing.T) {
|
||||
cfg := config.DefaultConfig()
|
||||
cfg.Browser.UserDataRoot = t.TempDir()
|
||||
manager := &XrayManager{Config: cfg, AppRoot: t.TempDir()}
|
||||
|
||||
cfgPath, err := manager.buildRuntimeConfigWithRoute(
|
||||
"log-level-test",
|
||||
[]interface{}{map[string]interface{}{"protocol": "freedom", "tag": "proxy-out"}},
|
||||
[]interface{}{},
|
||||
19092,
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("buildRuntimeConfigWithRoute returned error: %v", err)
|
||||
}
|
||||
|
||||
runtimeConfig := readRuntimeConfigMap(t, cfgPath)
|
||||
logConfig := runtimeConfig["log"].(map[string]interface{})
|
||||
if got := logConfig["loglevel"]; got != "warning" {
|
||||
t.Fatalf("xray loglevel = %v, want warning", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSingBoxRuntimeConfigUsesWarnLogLevel(t *testing.T) {
|
||||
cfg := config.DefaultConfig()
|
||||
cfg.Browser.UserDataRoot = t.TempDir()
|
||||
manager := &SingBoxManager{Config: cfg, AppRoot: t.TempDir()}
|
||||
|
||||
cfgPath, err := manager.buildConfig("log-level-test", map[string]interface{}{"type": "direct", "tag": "proxy-out"}, 19093)
|
||||
if err != nil {
|
||||
t.Fatalf("buildConfig returned error: %v", err)
|
||||
}
|
||||
|
||||
runtimeConfig := readRuntimeConfigMap(t, cfgPath)
|
||||
logConfig := runtimeConfig["log"].(map[string]interface{})
|
||||
if got := logConfig["level"]; got != "warn" {
|
||||
t.Fatalf("sing-box log level = %v, want warn", got)
|
||||
}
|
||||
}
|
||||
|
||||
func readRuntimeConfigMap(t *testing.T, path string) map[string]interface{} {
|
||||
t.Helper()
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatalf("read runtime config failed: %v", err)
|
||||
}
|
||||
var runtimeConfig map[string]interface{}
|
||||
if err := json.Unmarshal(data, &runtimeConfig); err != nil {
|
||||
t.Fatalf("unmarshal runtime config failed: %v", err)
|
||||
}
|
||||
return runtimeConfig
|
||||
}
|
||||
@@ -87,7 +87,7 @@ func (m *SingBoxManager) buildConfig(key string, outbound map[string]interface{}
|
||||
|
||||
cfg := map[string]interface{}{
|
||||
"log": map[string]interface{}{
|
||||
"level": "info",
|
||||
"level": "warn",
|
||||
"output": filepath.Join(baseDir, "singbox.log"),
|
||||
"timestamp": true,
|
||||
},
|
||||
|
||||
@@ -60,6 +60,16 @@ func TestRealConnectivityWithSingBox(
|
||||
proxies []config.BrowserProxy,
|
||||
xrayMgr *XrayManager,
|
||||
singboxMgr *SingBoxManager,
|
||||
) TestResult {
|
||||
return TestRealConnectivityWithConfig(proxyId, proxies, xrayMgr, singboxMgr, nil)
|
||||
}
|
||||
|
||||
func TestRealConnectivityWithConfig(
|
||||
proxyId string,
|
||||
proxies []config.BrowserProxy,
|
||||
xrayMgr *XrayManager,
|
||||
singboxMgr *SingBoxManager,
|
||||
cfg *SpeedTestConfig,
|
||||
) TestResult {
|
||||
src := resolveProxyConfig("", proxies, proxyId)
|
||||
if src == "" {
|
||||
@@ -67,10 +77,18 @@ func TestRealConnectivityWithSingBox(
|
||||
}
|
||||
|
||||
targetURL := strings.TrimSpace(DefaultSpeedTestURL)
|
||||
timeout := 15 * time.Second
|
||||
if cfg != nil {
|
||||
if len(cfg.URLs) > 0 && strings.TrimSpace(cfg.URLs[0]) != "" {
|
||||
targetURL = strings.TrimSpace(cfg.URLs[0])
|
||||
}
|
||||
if cfg.Timeout > 0 {
|
||||
timeout = cfg.Timeout
|
||||
}
|
||||
}
|
||||
if targetURL == "" {
|
||||
return TestResult{ProxyId: proxyId, Ok: false, Error: "真实连通性测试目标 URL 为空"}
|
||||
}
|
||||
const timeout = 15 * time.Second
|
||||
|
||||
client, err := buildProxyHTTPClient(src, proxyId, proxies, xrayMgr, singboxMgr, timeout)
|
||||
if err != nil {
|
||||
|
||||
@@ -32,7 +32,7 @@ func (m *XrayManager) buildRuntimeConfigWithRoute(key string, outbounds []interf
|
||||
cfgPath := filepath.Join(baseDir, "xray-config.json")
|
||||
cfg := map[string]interface{}{
|
||||
"log": map[string]interface{}{
|
||||
"loglevel": "info",
|
||||
"loglevel": "warning",
|
||||
"error": filepath.Join(baseDir, "xray-error.log"),
|
||||
},
|
||||
"inbounds": []interface{}{
|
||||
|
||||
Reference in New Issue
Block a user