feat: Support custom delay timeout (#397)

This commit is contained in:
MystiPanda 2024-02-18 11:11:22 +08:00 committed by GitHub
parent e54d42576b
commit 8efa815eb9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 76 additions and 21 deletions

View File

@ -249,8 +249,9 @@ pub mod uwp {
pub async fn clash_api_get_proxy_delay(
name: String,
url: Option<String>,
timeout: i32,
) -> CmdResult<clash_api::DelayRes> {
match clash_api::get_proxy_delay(name, url).await {
match clash_api::get_proxy_delay(name, url, timeout).await {
Ok(res) => Ok(res),
Err(err) => Err(err.to_string()),
}

View File

@ -81,6 +81,9 @@ pub struct IVerge {
/// 默认的延迟测试连接
pub default_latency_test: Option<String>,
/// 默认的延迟测试超时时间
pub default_latency_timeout: Option<i32>,
/// 是否使用内部的脚本支持,默认为真
pub enable_builtin_enhanced: Option<bool>,
@ -222,6 +225,7 @@ impl IVerge {
patch!(auto_close_connection);
patch!(default_latency_test);
patch!(default_latency_timeout);
patch!(enable_builtin_enhanced);
patch!(proxy_layout_column);
patch!(test_list);

View File

@ -44,7 +44,11 @@ pub struct DelayRes {
/// GET /proxies/{name}/delay
/// 获取代理延迟
pub async fn get_proxy_delay(name: String, test_url: Option<String>) -> Result<DelayRes> {
pub async fn get_proxy_delay(
name: String,
test_url: Option<String>,
timeout: i32,
) -> Result<DelayRes> {
let (url, headers) = clash_client_info()?;
let url = format!("{url}/proxies/{name}/delay");
@ -57,7 +61,7 @@ pub async fn get_proxy_delay(name: String, test_url: Option<String>) -> Result<D
let builder = client
.get(&url)
.headers(headers)
.query(&[("timeout", "10000"), ("url", &test_url)]);
.query(&[("timeout", &format!("{timeout}")), ("url", &test_url)]);
let response = builder.send().await?;
Ok(response.json::<DelayRes>().await?)

View File

@ -25,6 +25,7 @@ export const ProxyGroups = (props: Props) => {
const { verge } = useVerge();
const { current, patchCurrent } = useProfiles();
const timeout = verge?.default_latency_timeout || 10000;
const virtuosoRef = useRef<VirtuosoHandle>(null);
@ -83,7 +84,7 @@ export const ProxyGroups = (props: Props) => {
}
const names = proxies.filter((p) => !p!.provider).map((p) => p!.name);
await delayManager.checkListDelay(names, groupName);
await delayManager.checkListDelay(names, groupName, timeout);
onProxies();
});

View File

@ -4,6 +4,7 @@ import { CheckCircleOutlineRounded } from "@mui/icons-material";
import { alpha, Box, ListItemButton, styled, Typography } from "@mui/material";
import { BaseLoading } from "@/components/base";
import delayManager from "@/services/delay";
import { useVerge } from "@/hooks/use-verge";
interface Props {
groupName: string;
@ -20,6 +21,8 @@ export const ProxyItemMini = (props: Props) => {
// -1/<=0 为 不显示
// -2 为 loading
const [delay, setDelay] = useState(-1);
const { verge } = useVerge();
const timeout = verge?.default_latency_timeout || 10000;
useEffect(() => {
delayManager.setListener(proxy.name, groupName, setDelay);
@ -36,7 +39,7 @@ export const ProxyItemMini = (props: Props) => {
const onDelay = useLockFn(async () => {
setDelay(-2);
setDelay(await delayManager.checkDelay(proxy.name, groupName));
setDelay(await delayManager.checkDelay(proxy.name, groupName, timeout));
});
return (
@ -139,14 +142,14 @@ export const ProxyItemMini = (props: Props) => {
e.stopPropagation();
onDelay();
}}
color={delayManager.formatDelayColor(delay)}
color={delayManager.formatDelayColor(delay, timeout)}
sx={({ palette }) =>
!proxy.provider
? { ":hover": { bgcolor: alpha(palette.primary.main, 0.15) } }
: {}
}
>
{delayManager.formatDelay(delay)}
{delayManager.formatDelay(delay, timeout)}
</Widget>
)}

View File

@ -14,6 +14,7 @@ import {
} from "@mui/material";
import { BaseLoading } from "@/components/base";
import delayManager from "@/services/delay";
import { useVerge } from "@/hooks/use-verge";
interface Props {
groupName: string;
@ -48,7 +49,8 @@ export const ProxyItem = (props: Props) => {
// -1/<=0 为 不显示
// -2 为 loading
const [delay, setDelay] = useState(-1);
const { verge } = useVerge();
const timeout = verge?.default_latency_timeout || 10000;
useEffect(() => {
delayManager.setListener(proxy.name, groupName, setDelay);
@ -64,7 +66,7 @@ export const ProxyItem = (props: Props) => {
const onDelay = useLockFn(async () => {
setDelay(-2);
setDelay(await delayManager.checkDelay(proxy.name, groupName));
setDelay(await delayManager.checkDelay(proxy.name, groupName, timeout));
});
return (
@ -149,14 +151,14 @@ export const ProxyItem = (props: Props) => {
e.stopPropagation();
onDelay();
}}
color={delayManager.formatDelayColor(delay)}
color={delayManager.formatDelayColor(delay, timeout)}
sx={({ palette }) =>
!proxy.provider
? { ":hover": { bgcolor: alpha(palette.primary.main, 0.15) } }
: {}
}
>
{delayManager.formatDelay(delay)}
{delayManager.formatDelay(delay, timeout)}
</Widget>
)}

View File

@ -25,6 +25,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
proxyLayoutColumn: 6,
defaultLatencyTest: "",
autoLogClean: 0,
defaultLatencyTimeout: 10000,
});
useImperativeHandle(ref, () => ({
@ -37,6 +38,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
proxyLayoutColumn: verge?.proxy_layout_column || 6,
defaultLatencyTest: verge?.default_latency_test || "",
autoLogClean: verge?.auto_log_clean || 0,
defaultLatencyTimeout: verge?.default_latency_timeout || 10000,
});
},
close: () => setOpen(false),
@ -50,6 +52,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
enable_builtin_enhanced: values.enableBuiltinEnhanced,
proxy_layout_column: values.proxyLayoutColumn,
default_latency_test: values.defaultLatencyTest,
default_latency_timeout: values.defaultLatencyTimeout,
auto_log_clean: values.autoLogClean as any,
});
setOpen(false);
@ -179,6 +182,27 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
}
/>
</ListItem>
<ListItem sx={{ padding: "5px 2px" }}>
<ListItemText primary={t("Default Latency Timeout")} />
<TextField
size="small"
type="number"
autoComplete="off"
autoCorrect="off"
autoCapitalize="off"
spellCheck="false"
sx={{ width: 250 }}
value={values.defaultLatencyTimeout}
placeholder="http://1.1.1.1"
onChange={(e) =>
setValues((v) => ({
...v,
defaultLatencyTimeout: parseInt(e.target.value),
}))
}
/>
</ListItem>
</List>
</BaseDialog>
);

View File

@ -152,6 +152,7 @@
"Enable Builtin Enhanced": "Enable Builtin Enhanced",
"Proxy Layout Column": "Proxy Layout Column",
"Default Latency Test": "Default Latency Test",
"Defaule Latency Timeout": "Defaule Latency Timeout",
"Auto Log Clean": "Auto Log Clean",
"Never Clean": "Never Clean",

View File

@ -152,6 +152,7 @@
"Enable Builtin Enhanced": "开启内建增强功能",
"Proxy Layout Column": "代理页布局列数",
"Default Latency Test": "默认测试链接",
"Default Latency Timeout": "测试超时时间",
"Auto Log Clean": "自动清理日志",
"Never Clean": "不清理",

View File

@ -160,9 +160,17 @@ export async function openWebUrl(url: string) {
return invoke<void>("open_web_url", { url });
}
export async function cmdGetProxyDelay(name: string, url?: string) {
export async function cmdGetProxyDelay(
name: string,
timeout: number,
url?: string
) {
name = encodeURIComponent(name);
return invoke<{ delay: number }>("clash_api_get_proxy_delay", { name, url });
return invoke<{ delay: number }>("clash_api_get_proxy_delay", {
name,
url,
timeout,
});
}
export async function cmdTestDelay(url: string) {

View File

@ -69,12 +69,12 @@ class DelayManager {
return -1;
}
async checkDelay(name: string, group: string) {
async checkDelay(name: string, group: string, timeout: number) {
let delay = -1;
try {
const url = this.getUrl(group);
const result = await cmdGetProxyDelay(name, url);
const result = await cmdGetProxyDelay(name, timeout, url);
delay = result.delay;
} catch {
delay = 1e6; // error
@ -84,7 +84,12 @@ class DelayManager {
return delay;
}
async checkListDelay(nameList: string[], group: string, concurrency = 36) {
async checkListDelay(
nameList: string[],
group: string,
timeout: number,
concurrency = 36
) {
const names = nameList.filter(Boolean);
// 设置正在延迟测试中
names.forEach((name) => this.setDelay(name, group, -2));
@ -98,7 +103,7 @@ class DelayManager {
const task = names.shift();
if (!task) return;
current += 1;
await this.checkDelay(task, group);
await this.checkDelay(task, group, timeout);
current -= 1;
total -= 1;
if (total <= 0) resolve(null);
@ -108,15 +113,15 @@ class DelayManager {
});
}
formatDelay(delay: number) {
formatDelay(delay: number, timeout = 10000) {
if (delay <= 0) return "Error";
if (delay > 1e5) return "Error";
if (delay >= 10000) return "Timeout"; // 10s
if (delay >= timeout) return "Timeout"; // 10s
return `${delay}`;
}
formatDelayColor(delay: number) {
if (delay >= 10000) return "error.main";
formatDelayColor(delay: number, timeout = 10000) {
if (delay >= timeout) return "error.main";
if (delay <= 0) return "error.main";
if (delay > 500) return "warning.main";
return "success.main";

View File

@ -219,6 +219,7 @@ interface IVergeConfig {
};
auto_close_connection?: boolean;
default_latency_test?: string;
default_latency_timeout?: number;
enable_builtin_enhanced?: boolean;
auto_log_clean?: 0 | 1 | 2 | 3;
proxy_layout_column?: number;