mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-04-16 15:20:39 +08:00
perf: optimize IP info card
This commit is contained in:
parent
31c0910919
commit
81c56d46c1
@ -30,5 +30,6 @@
|
|||||||
- 连通性测试替换为更快的 https://1.1.1.1
|
- 连通性测试替换为更快的 https://1.1.1.1
|
||||||
- 连接、规则、日志等页面的过滤搜索组件新增了清空输入框按钮
|
- 连接、规则、日志等页面的过滤搜索组件新增了清空输入框按钮
|
||||||
- 链式代理增加明显的入口出口与数据流向标识
|
- 链式代理增加明显的入口出口与数据流向标识
|
||||||
|
- 优化 IP 信息卡
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|||||||
@ -21,11 +21,13 @@ import { useTranslation } from "react-i18next";
|
|||||||
import useSWRImmutable from "swr/immutable";
|
import useSWRImmutable from "swr/immutable";
|
||||||
|
|
||||||
import { getIpInfo } from "@/services/api";
|
import { getIpInfo } from "@/services/api";
|
||||||
|
import { SWR_EXTERNAL_API } from "@/services/config";
|
||||||
|
|
||||||
import { EnhancedCard } from "./enhanced-card";
|
import { EnhancedCard } from "./enhanced-card";
|
||||||
|
|
||||||
// 定义刷新时间(秒)
|
// 定义刷新时间(秒)
|
||||||
const IP_REFRESH_SECONDS = 300;
|
const IP_REFRESH_SECONDS = 300;
|
||||||
|
const COUNTDOWN_TICK_INTERVAL = 5_000;
|
||||||
const IP_INFO_CACHE_KEY = "cv_ip_info_cache";
|
const IP_INFO_CACHE_KEY = "cv_ip_info_cache";
|
||||||
|
|
||||||
const InfoItem = memo(({ label, value }: { label: string; value?: string }) => (
|
const InfoItem = memo(({ label, value }: { label: string; value?: string }) => (
|
||||||
@ -180,7 +182,7 @@ export const IpInfoCard = () => {
|
|||||||
console.debug(
|
console.debug(
|
||||||
"IP info card has entered the viewport, starting the countdown interval.",
|
"IP info card has entered the viewport, starting the countdown interval.",
|
||||||
);
|
);
|
||||||
timer = window.setInterval(onCountdownTick, 1000);
|
timer = window.setInterval(onCountdownTick, COUNTDOWN_TICK_INTERVAL);
|
||||||
} else {
|
} else {
|
||||||
console.debug(
|
console.debug(
|
||||||
"IP info card has not yet entered the viewport, no counting down.",
|
"IP info card has not yet entered the viewport, no counting down.",
|
||||||
@ -207,7 +209,7 @@ export const IpInfoCard = () => {
|
|||||||
console.debug("Document visible, resume the interval");
|
console.debug("Document visible, resume the interval");
|
||||||
// Resume the timer only when previous one is cleared
|
// Resume the timer only when previous one is cleared
|
||||||
if (timer == null) {
|
if (timer == null) {
|
||||||
timer = window.setInterval(onCountdownTick, 1000);
|
timer = window.setInterval(onCountdownTick, COUNTDOWN_TICK_INTERVAL);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.debug(
|
console.debug(
|
||||||
@ -420,7 +422,5 @@ export const IpInfoCard = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function useIPInfo() {
|
function useIPInfo() {
|
||||||
return useSWRImmutable(IP_INFO_CACHE_KEY, getIpInfo, {
|
return useSWRImmutable(IP_INFO_CACHE_KEY, getIpInfo, SWR_EXTERNAL_API);
|
||||||
shouldRetryOnError: true,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -137,62 +137,6 @@ const IP_CHECK_SERVICES: ServiceConfig[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// 随机性服务列表洗牌函数
|
|
||||||
function shuffleServices() {
|
|
||||||
// 过滤无效服务并确保每个元素符合ServiceConfig接口
|
|
||||||
const validServices = IP_CHECK_SERVICES.filter(
|
|
||||||
(service): service is ServiceConfig =>
|
|
||||||
service !== null &&
|
|
||||||
service !== undefined &&
|
|
||||||
typeof service.url === "string" &&
|
|
||||||
typeof service.mapping === "function", // 添加对mapping属性的检查
|
|
||||||
);
|
|
||||||
|
|
||||||
if (validServices.length === 0) {
|
|
||||||
console.error("No valid services found in IP_CHECK_SERVICES");
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用单一Fisher-Yates洗牌算法,增强随机性
|
|
||||||
const shuffled = [...validServices];
|
|
||||||
const length = shuffled.length;
|
|
||||||
|
|
||||||
// 使用多个种子进行多次洗牌
|
|
||||||
const seeds = [Math.random(), Date.now() / 1000, performance.now() / 1000];
|
|
||||||
|
|
||||||
for (const seed of seeds) {
|
|
||||||
const prng = createPrng(seed);
|
|
||||||
|
|
||||||
// Fisher-Yates洗牌算法
|
|
||||||
for (let i = length - 1; i > 0; i--) {
|
|
||||||
const j = Math.floor(prng() * (i + 1));
|
|
||||||
|
|
||||||
// 使用临时变量进行交换,避免解构赋值可能的问题
|
|
||||||
const temp = shuffled[i];
|
|
||||||
shuffled[i] = shuffled[j];
|
|
||||||
shuffled[j] = temp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return shuffled;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建一个简单的随机数生成器
|
|
||||||
function createPrng(seed: number): () => number {
|
|
||||||
// 使用xorshift32算法
|
|
||||||
let state = seed >>> 0;
|
|
||||||
|
|
||||||
// 如果种子为0,设置一个默认值
|
|
||||||
if (state === 0) state = 123456789;
|
|
||||||
|
|
||||||
return function () {
|
|
||||||
state ^= state << 13;
|
|
||||||
state ^= state >>> 17;
|
|
||||||
state ^= state << 5;
|
|
||||||
return (state >>> 0) / 4294967296;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取当前IP和地理位置信息
|
// 获取当前IP和地理位置信息
|
||||||
export const getIpInfo = async (): Promise<
|
export const getIpInfo = async (): Promise<
|
||||||
IpInfo & { lastFetchTs: number }
|
IpInfo & { lastFetchTs: number }
|
||||||
@ -201,7 +145,9 @@ export const getIpInfo = async (): Promise<
|
|||||||
const maxRetries = 2;
|
const maxRetries = 2;
|
||||||
const serviceTimeout = 5000;
|
const serviceTimeout = 5000;
|
||||||
|
|
||||||
const shuffledServices = shuffleServices();
|
const shuffledServices = IP_CHECK_SERVICES.toSorted(
|
||||||
|
() => Math.random() - 0.5,
|
||||||
|
);
|
||||||
let lastError: unknown | null = null;
|
let lastError: unknown | null = null;
|
||||||
const userAgent = await getUserAgentPromise();
|
const userAgent = await getUserAgentPromise();
|
||||||
console.debug("User-Agent for IP detection:", userAgent);
|
console.debug("User-Agent for IP detection:", userAgent);
|
||||||
@ -236,7 +182,12 @@ export const getIpInfo = async (): Promise<
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await response.json();
|
let data: any;
|
||||||
|
try {
|
||||||
|
data = await response.json();
|
||||||
|
} catch {
|
||||||
|
return bail(new Error(`无法解析 JSON 响应 from ${service.url}`));
|
||||||
|
}
|
||||||
|
|
||||||
if (data && data.ip) {
|
if (data && data.ip) {
|
||||||
debugLog(`IP检测成功,使用服务: ${service.url}`);
|
debugLog(`IP检测成功,使用服务: ${service.url}`);
|
||||||
@ -245,7 +196,7 @@ export const getIpInfo = async (): Promise<
|
|||||||
lastFetchTs: Date.now(),
|
lastFetchTs: Date.now(),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`无效的响应格式 from ${service.url}`);
|
return bail(new Error(`无效的响应格式 from ${service.url}`));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -26,3 +26,10 @@ export const SWR_MIHOMO = {
|
|||||||
errorRetryInterval: 500,
|
errorRetryInterval: 500,
|
||||||
errorRetryCount: 15,
|
errorRetryCount: 15,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const SWR_EXTERNAL_API = {
|
||||||
|
...SWR_NOT_SMART,
|
||||||
|
shouldRetryOnError: true,
|
||||||
|
errorRetryCount: 1,
|
||||||
|
errorRetryInterval: 30_000,
|
||||||
|
} as const;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user