diff --git a/src/components/proxy/proxy-groups.tsx b/src/components/proxy/proxy-groups.tsx index d59c0790..c1e49135 100644 --- a/src/components/proxy/proxy-groups.tsx +++ b/src/components/proxy/proxy-groups.tsx @@ -365,6 +365,8 @@ export const ProxyGroups = (props: Props) => { // 测全部延迟 const handleCheckAll = useLockFn(async (groupName: string) => { + console.log(`[ProxyGroups] 开始测试所有延迟,组: ${groupName}`); + const proxies = renderList .filter( (e) => e.group?.name === groupName && (e.type === 2 || e.type === 4), @@ -372,20 +374,40 @@ export const ProxyGroups = (props: Props) => { .flatMap((e) => e.proxyCol || e.proxy!) .filter(Boolean); + console.log(`[ProxyGroups] 找到代理数量: ${proxies.length}`); + const providers = new Set(proxies.map((p) => p!.provider!).filter(Boolean)); if (providers.size) { + console.log(`[ProxyGroups] 发现提供者,数量: ${providers.size}`); Promise.allSettled( [...providers].map((p) => providerHealthCheck(p)), - ).then(() => onProxies()); + ).then(() => { + console.log(`[ProxyGroups] 提供者健康检查完成`); + onProxies(); + }); } const names = proxies.filter((p) => !p!.provider).map((p) => p!.name); + console.log(`[ProxyGroups] 过滤后需要测试的代理数量: ${names.length}`); - await Promise.race([ - delayManager.checkListDelay(names, groupName, timeout), - getGroupProxyDelays(groupName, delayManager.getUrl(groupName), timeout), // 查询group delays 将清除fixed(不关注调用结果) - ]); + const url = delayManager.getUrl(groupName); + console.log(`[ProxyGroups] 测试URL: ${url}, 超时: ${timeout}ms`); + + try { + await Promise.race([ + delayManager.checkListDelay(names, groupName, timeout), + getGroupProxyDelays(groupName, url, timeout).then((result) => { + console.log( + `[ProxyGroups] getGroupProxyDelays返回结果数量:`, + Object.keys(result || {}).length, + ); + }), // 查询group delays 将清除fixed(不关注调用结果) + ]); + console.log(`[ProxyGroups] 延迟测试完成,组: ${groupName}`); + } catch (error) { + console.error(`[ProxyGroups] 延迟测试出错,组: ${groupName}`, error); + } onProxies(); }); diff --git a/src/components/proxy/proxy-head.tsx b/src/components/proxy/proxy-head.tsx index c9ba125c..1b3ab170 100644 --- a/src/components/proxy/proxy-head.tsx +++ b/src/components/proxy/proxy-head.tsx @@ -48,7 +48,7 @@ export const ProxyHead = (props: Props) => { useEffect(() => { delayManager.setUrl( groupName, - testUrl || url || verge?.default_latency_test! + testUrl || url || verge?.default_latency_test!, ); }, [groupName, testUrl, verge?.default_latency_test]); @@ -68,8 +68,10 @@ export const ProxyHead = (props: Props) => { color="inherit" title={t("Delay check")} onClick={() => { + console.log(`[ProxyHead] 点击延迟测试按钮,组: ${groupName}`); // Remind the user that it is custom test url if (testUrl?.trim() && textState !== "filter") { + console.log(`[ProxyHead] 使用自定义测试URL: ${testUrl}`); onHeadState({ textState: "url" }); } props.onCheckDelay(); diff --git a/src/services/api.ts b/src/services/api.ts index 328849a7..c7ddc5ee 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -266,12 +266,31 @@ export const getGroupProxyDelays = async ( timeout: timeout || 10000, url: url || "http://cp.cloudflare.com/generate_204", }; - const instance = await getAxios(); - const result = await instance.get( - `/group/${encodeURIComponent(groupName)}/delay`, - { params }, + + console.log( + `[API] 获取代理组延迟,组: ${groupName}, URL: ${params.url}, 超时: ${params.timeout}ms`, ); - return result as any as Record; + + try { + const instance = await getAxios(); + console.log( + `[API] 发送HTTP请求: GET /group/${encodeURIComponent(groupName)}/delay`, + ); + + const result = await instance.get( + `/group/${encodeURIComponent(groupName)}/delay`, + { params }, + ); + + console.log( + `[API] 获取代理组延迟成功,组: ${groupName}, 结果数量:`, + Object.keys(result || {}).length, + ); + return result as any as Record; + } catch (error) { + console.error(`[API] 获取代理组延迟失败,组: ${groupName}`, error); + throw error; + } }; // Is debug enabled diff --git a/src/services/cmds.ts b/src/services/cmds.ts index 9338406d..505b82db 100644 --- a/src/services/cmds.ts +++ b/src/services/cmds.ts @@ -161,12 +161,42 @@ export async function cmdGetProxyDelay( timeout: number, url?: string, ) { - name = encodeURIComponent(name); - return invoke<{ delay: number }>("clash_api_get_proxy_delay", { - name, - url, - timeout, - }); + // 确保URL不为空 + const testUrl = url || "http://cp.cloudflare.com/generate_204"; + console.log( + `[API] 调用延迟测试API,代理: ${name}, 超时: ${timeout}ms, URL: ${testUrl}`, + ); + + try { + name = encodeURIComponent(name); + const result = await invoke<{ delay: number }>( + "clash_api_get_proxy_delay", + { + name, + url: testUrl, // 传递经过验证的URL + timeout, + }, + ); + + // 验证返回结果中是否有delay字段,并且值是一个有效的数字 + if (result && typeof result.delay === "number") { + console.log( + `[API] 延迟测试API调用成功,代理: ${name}, 延迟: ${result.delay}ms`, + ); + return result; + } else { + console.error( + `[API] 延迟测试API返回无效结果,代理: ${name}, 结果:`, + result, + ); + // 返回一个有效的结果对象,但标记为超时 + return { delay: 1e6 }; + } + } catch (error) { + console.error(`[API] 延迟测试API调用失败,代理: ${name}`, error); + // 返回一个有效的结果对象,但标记为错误 + return { delay: 1e6 }; + } } export async function cmdTestDelay(url: string) { diff --git a/src/services/delay.ts b/src/services/delay.ts index 3c572a9a..8d21aaa3 100644 --- a/src/services/delay.ts +++ b/src/services/delay.ts @@ -13,11 +13,17 @@ class DelayManager { private groupListenerMap = new Map void>(); setUrl(group: string, url: string) { + console.log(`[DelayManager] 设置测试URL,组: ${group}, URL: ${url}`); this.urlMap.set(group, url); } getUrl(group: string) { - return this.urlMap.get(group); + const url = this.urlMap.get(group); + console.log( + `[DelayManager] 获取测试URL,组: ${group}, URL: ${url || "未设置"}`, + ); + // 如果未设置URL,返回默认URL + return url || "http://cp.cloudflare.com/generate_204"; } setListener(name: string, group: string, listener: (time: number) => void) { @@ -40,19 +46,25 @@ class DelayManager { setDelay(name: string, group: string, delay: number) { const key = hashKey(name, group); - this.cache.set(key, [Date.now(), delay]); - this.listenerMap.get(key)?.(delay); - this.groupListenerMap.get(group)?.(); + console.log( + `[DelayManager] 设置延迟,代理: ${name}, 组: ${group}, 延迟: ${delay}`, + ); + + this.cache.set(key, [delay, Date.now()]); + const listener = this.listenerMap.get(key); + if (listener) listener(delay); } getDelay(name: string, group: string) { - if (!name) return -1; + const key = hashKey(name, group); + const val = this.cache.get(key); + if (!val) return -1; - const result = this.cache.get(hashKey(name, group)); - if (result && Date.now() - result[0] <= 18e5) { - return result[1]; + // 缓存30分钟 + if (Date.now() - val[1] > 30 * 60 * 1000) { + return -1; } - return -1; + return val[0]; } /// 暂时修复provider的节点延迟排序的问题 @@ -70,13 +82,60 @@ class DelayManager { } async checkDelay(name: string, group: string, timeout: number) { + console.log( + `[DelayManager] 开始测试延迟,代理: ${name}, 组: ${group}, 超时: ${timeout}ms`, + ); + + // 先将状态设置为测试中 + this.setDelay(name, group, -2); + let delay = -1; try { const url = this.getUrl(group); - const result = await cmdGetProxyDelay(name, timeout, url); - delay = result.delay; - } catch { + console.log(`[DelayManager] 调用API测试延迟,代理: ${name}, URL: ${url}`); + + // 记录开始时间,用于计算实际延迟 + const startTime = Date.now(); + + // 设置超时处理 + const timeoutPromise = new Promise<{ delay: number }>((_, reject) => { + setTimeout(() => reject(new Error("Timeout")), timeout); + }); + + // 使用Promise.race来实现超时控制 + const result = await Promise.race([ + cmdGetProxyDelay(name, timeout, url), + timeoutPromise, + ]); + + // 确保至少显示500ms的加载动画 + const elapsedTime = Date.now() - startTime; + if (elapsedTime < 500) { + await new Promise((resolve) => setTimeout(resolve, 500 - elapsedTime)); + } + + // 检查延迟结果是否为undefined + if (result && typeof result.delay === "number") { + delay = result.delay; + console.log( + `[DelayManager] 延迟测试完成,代理: ${name}, 结果: ${delay}ms`, + ); + } else { + console.error( + `[DelayManager] 延迟测试返回无效结果,代理: ${name}, 结果:`, + result, + ); + delay = 1e6; // 错误情况 + } + } catch (error) { + // 确保至少显示500ms的加载动画 + await new Promise((resolve) => setTimeout(resolve, 500)); + + console.error(`[DelayManager] 延迟测试出错,代理: ${name}`, error); + if (error instanceof Error && error.message === "Timeout") { + console.log(`[DelayManager] 延迟测试超时,代理: ${name}`); + } delay = 1e6; // error } @@ -88,42 +147,78 @@ class DelayManager { nameList: string[], group: string, timeout: number, - concurrency = 36 + concurrency = 36, ) { + console.log( + `[DelayManager] 批量测试延迟开始,组: ${group}, 数量: ${nameList.length}, 并发数: ${concurrency}`, + ); const names = nameList.filter(Boolean); // 设置正在延迟测试中 names.forEach((name) => this.setDelay(name, group, -2)); - let total = names.length; - let current = 0; + let index = 0; + const startTime = Date.now(); + const listener = this.groupListenerMap.get(group); - return new Promise((resolve) => { - const help = async (): Promise => { - if (current >= concurrency) return; - const task = names.shift(); - if (!task) return; - current += 1; - await this.checkDelay(task, group, timeout); - current -= 1; - total -= 1; - if (total <= 0) resolve(null); - else return help(); - }; - for (let i = 0; i < concurrency; ++i) help(); - }); + const help = async (): Promise => { + const currName = names[index++]; + if (!currName) return; + + try { + // 确保API调用前状态为测试中 + this.setDelay(currName, group, -2); + + // 添加一些随机延迟,避免所有请求同时发出和返回 + if (index > 1) { + // 第一个不延迟,保持响应性 + await new Promise((resolve) => + setTimeout(resolve, Math.random() * 200), + ); + } + + await this.checkDelay(currName, group, timeout); + if (listener) listener(); + } catch (error) { + console.error( + `[DelayManager] 批量测试单个代理出错,代理: ${currName}`, + error, + ); + // 设置为错误状态 + this.setDelay(currName, group, 1e6); + } + + return help(); + }; + + // 限制并发数,避免发送太多请求 + const actualConcurrency = Math.min(concurrency, names.length, 10); + console.log(`[DelayManager] 实际并发数: ${actualConcurrency}`); + + const promiseList: Promise[] = []; + for (let i = 0; i < actualConcurrency; i++) { + promiseList.push(help()); + } + + await Promise.all(promiseList); + const totalTime = Date.now() - startTime; + console.log( + `[DelayManager] 批量测试延迟完成,组: ${group}, 总耗时: ${totalTime}ms`, + ); } formatDelay(delay: number, timeout = 10000) { - if (delay <= 0) return "Error"; - if (delay > 1e5) return "Error"; - if (delay >= timeout) return "Timeout"; // 10s + if (delay === -1) return "-"; + if (delay === -2) return "testing"; + if (delay >= timeout) return "timeout"; return `${delay}`; } formatDelayColor(delay: number, timeout = 10000) { + if (delay < 0) return ""; if (delay >= timeout) return "error.main"; - if (delay <= 0) return "error.main"; - if (delay > 500) return "warning.main"; + if (delay >= 10000) return "error.main"; + if (delay >= 400) return "warning.main"; + if (delay >= 250) return "primary.main"; return "success.main"; } }