refactored IP detection and added zashboard redirect URL (#3510)
* Fixed the language display size issue and updated the translation synchronously! * Fixed Russian language display issue * refactored IP detection and added zashboard redirect URL --------- Co-authored-by: Ahao <108321411+xuanyuan0408@users.noreply.github.com>
This commit is contained in:
@@ -44,11 +44,11 @@
|
||||
- 支持手动卸载服务模式,回退到 Sidecar 模式
|
||||
- 添加了土耳其语,日本语,德语,西班牙语,繁体中文的支持
|
||||
- 卸载服务的按钮
|
||||
- 添加了Zashboard的一键跳转URL
|
||||
|
||||
#### 优化了:
|
||||
- 系统代理 Bypass 设置
|
||||
- Windows 下使用 Startup 文件夹的方式实现开机自启,解决管理员模式下开机自启的各种问题
|
||||
- 增加 IP 信息请求重试机制,减少 Network Error 发生的情况
|
||||
- 切换到规则页面时自动刷新规则数据
|
||||
- 重构更新失败回退机制,使用后端完成更新失败后回退到使用 Clash 代理再次尝试更新
|
||||
- 编辑非激活订阅的时候不在触发当前订阅配置重载
|
||||
@@ -63,6 +63,7 @@
|
||||
- 优化了其他语言的翻译问题
|
||||
- Mihomo 内核默认日志等级为 warn
|
||||
- Clash Verge Rev 应用默认日志等级为 warn
|
||||
- 重构了原来的IP 信息请求重试机制,采用轮询检测,解决了 Network Error 和 超时问题
|
||||
|
||||
## v2.2.3
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ export const WebUIViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
const webUIList = verge?.web_ui_list || [
|
||||
"https://metacubex.github.io/metacubexd/#/setup?http=true&hostname=%host&port=%port&secret=%secret",
|
||||
"https://yacd.metacubex.one/?hostname=%host&port=%port&secret=%secret",
|
||||
"https://board.zash.run.place/#/setup?http=true&hostname=%host&port=%port&secret=%secret",
|
||||
];
|
||||
|
||||
const handleAdd = useLockFn(async (value: string) => {
|
||||
|
||||
@@ -319,42 +319,103 @@ export const gc = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
// Get current IP and geolocation information
|
||||
export const getIpInfo = async () => {
|
||||
// 添加重试机制
|
||||
const maxRetries = 3;
|
||||
const retryDelay = 1500;
|
||||
const timeout = 5000;
|
||||
// Get current IP and geolocation information (refactored IP detection)
|
||||
interface IpInfo {
|
||||
ip: string;
|
||||
country_code: string;
|
||||
country: string;
|
||||
region: string;
|
||||
city: string;
|
||||
organization: string;
|
||||
asn: number;
|
||||
asn_organization: string;
|
||||
longitude: number;
|
||||
latitude: number;
|
||||
timezone: string;
|
||||
}
|
||||
|
||||
let lastError;
|
||||
|
||||
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
||||
try {
|
||||
// 使用axios直接请求IP.sb的API,不通过clash代理
|
||||
const response = await axios.get("https://api.ip.sb/geoip", { timeout });
|
||||
return response.data as {
|
||||
ip: string;
|
||||
country_code: string;
|
||||
country: string;
|
||||
region: string;
|
||||
city: string;
|
||||
organization: string;
|
||||
asn: number;
|
||||
asn_organization: string;
|
||||
longitude: number;
|
||||
latitude: number;
|
||||
timezone: string;
|
||||
};
|
||||
} catch (error) {
|
||||
console.log(`获取IP信息失败,尝试 ${attempt + 1}/${maxRetries}`, error);
|
||||
lastError = error;
|
||||
// 可用的IP检测服务列表
|
||||
const IP_CHECK_SERVICES = [
|
||||
"https://api.ip.sb/geoip",
|
||||
"https://ipapi.co/json",
|
||||
"http://ip-api.com/json",
|
||||
"https://ipinfo.io/json",
|
||||
"https://ifconfig.co/json",
|
||||
];
|
||||
|
||||
// 随机打乱服务列表顺序
|
||||
function shuffleServices() {
|
||||
return [...IP_CHECK_SERVICES].sort(() => Math.random() - 0.5);
|
||||
}
|
||||
|
||||
// 获取当前IP和地理位置信息(优化版本)
|
||||
export const getIpInfo = async (): Promise<IpInfo> => {
|
||||
// 配置参数
|
||||
const maxRetries = 3;
|
||||
const serviceTimeout = 5000;
|
||||
const overallTimeout = 15000;
|
||||
|
||||
const overallTimeoutController = new AbortController();
|
||||
const overallTimeoutId = setTimeout(() => {
|
||||
overallTimeoutController.abort();
|
||||
}, overallTimeout);
|
||||
|
||||
try {
|
||||
const shuffledServices = shuffleServices();
|
||||
let lastError: Error | null = null;
|
||||
|
||||
for (const serviceUrl of shuffledServices) {
|
||||
console.log(`尝试IP检测服务: ${serviceUrl}`);
|
||||
|
||||
// 如果不是最后一次尝试,则等待后重试
|
||||
if (attempt < maxRetries - 1) {
|
||||
await new Promise(resolve => setTimeout(resolve, retryDelay));
|
||||
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
||||
let timeoutId: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
try {
|
||||
const timeoutController = new AbortController();
|
||||
timeoutId = setTimeout(() => {
|
||||
timeoutController.abort();
|
||||
}, serviceTimeout);
|
||||
|
||||
const response = await axios.get<IpInfo>(serviceUrl, {
|
||||
signal: timeoutController.signal,
|
||||
timeout: serviceTimeout,
|
||||
headers: { "User-Agent": "Mozilla/5.0" },
|
||||
});
|
||||
|
||||
if (timeoutId) clearTimeout(timeoutId);
|
||||
|
||||
if (response.data && response.data.ip) {
|
||||
console.log(`IP检测成功,使用服务: ${serviceUrl}`);
|
||||
return response.data;
|
||||
} else {
|
||||
throw new Error(`无效的响应格式 from ${serviceUrl}`);
|
||||
}
|
||||
} catch (error: any) {
|
||||
if (timeoutId) clearTimeout(timeoutId);
|
||||
|
||||
lastError = error;
|
||||
console.log(
|
||||
`尝试 ${attempt + 1}/${maxRetries} 失败 (${serviceUrl}):`,
|
||||
error.message
|
||||
);
|
||||
|
||||
if (error.name === "AbortError") {
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (attempt < maxRetries - 1) {
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw lastError;
|
||||
};
|
||||
if (lastError) {
|
||||
throw new Error(`所有IP检测服务都失败: ${lastError.message}`);
|
||||
} else {
|
||||
throw new Error('没有可用的IP检测服务');
|
||||
}
|
||||
} finally {
|
||||
clearTimeout(overallTimeoutId);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user