mirror of
https://github.com/clash-verge-rev/clash-verge-rev
synced 2025-05-05 05:13:44 +08:00
feat: enhance latency test logging and error handling
This commit is contained in:
parent
95e8fe38f2
commit
ca1f7a2b31
@ -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}`);
|
||||
|
||||
const url = delayManager.getUrl(groupName);
|
||||
console.log(`[ProxyGroups] 测试URL: ${url}, 超时: ${timeout}ms`);
|
||||
|
||||
try {
|
||||
await Promise.race([
|
||||
delayManager.checkListDelay(names, groupName, timeout),
|
||||
getGroupProxyDelays(groupName, delayManager.getUrl(groupName), timeout), // 查询group delays 将清除fixed(不关注调用结果)
|
||||
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();
|
||||
});
|
||||
|
@ -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();
|
||||
|
@ -266,12 +266,31 @@ export const getGroupProxyDelays = async (
|
||||
timeout: timeout || 10000,
|
||||
url: url || "http://cp.cloudflare.com/generate_204",
|
||||
};
|
||||
|
||||
console.log(
|
||||
`[API] 获取代理组延迟,组: ${groupName}, URL: ${params.url}, 超时: ${params.timeout}ms`,
|
||||
);
|
||||
|
||||
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<string, number>;
|
||||
} catch (error) {
|
||||
console.error(`[API] 获取代理组延迟失败,组: ${groupName}`, error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Is debug enabled
|
||||
|
@ -161,12 +161,42 @@ export async function cmdGetProxyDelay(
|
||||
timeout: number,
|
||||
url?: string,
|
||||
) {
|
||||
// 确保URL不为空
|
||||
const testUrl = url || "http://cp.cloudflare.com/generate_204";
|
||||
console.log(
|
||||
`[API] 调用延迟测试API,代理: ${name}, 超时: ${timeout}ms, URL: ${testUrl}`,
|
||||
);
|
||||
|
||||
try {
|
||||
name = encodeURIComponent(name);
|
||||
return invoke<{ delay: number }>("clash_api_get_proxy_delay", {
|
||||
const result = await invoke<{ delay: number }>(
|
||||
"clash_api_get_proxy_delay",
|
||||
{
|
||||
name,
|
||||
url,
|
||||
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) {
|
||||
|
@ -13,11 +13,17 @@ class DelayManager {
|
||||
private groupListenerMap = new Map<string, () => 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,20 +46,26 @@ 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 val[0];
|
||||
}
|
||||
|
||||
/// 暂时修复provider的节点延迟排序的问题
|
||||
getDelayFix(proxy: IProxyItem, group: string) {
|
||||
@ -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);
|
||||
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;
|
||||
} catch {
|
||||
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<void> => {
|
||||
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();
|
||||
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();
|
||||
};
|
||||
for (let i = 0; i < concurrency; ++i) help();
|
||||
});
|
||||
|
||||
// 限制并发数,避免发送太多请求
|
||||
const actualConcurrency = Math.min(concurrency, names.length, 10);
|
||||
console.log(`[DelayManager] 实际并发数: ${actualConcurrency}`);
|
||||
|
||||
const promiseList: Promise<void>[] = [];
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user