feat: auto close connection when proxy changed

This commit is contained in:
GyDi 2022-11-10 01:27:05 +08:00
parent 5f486d0f51
commit 0cfd718d8a
No known key found for this signature in database
GPG Key ID: 9C3AD40F1F99880A
9 changed files with 175 additions and 3 deletions

View File

@ -60,6 +60,12 @@ pub struct Verge {
/// hotkey map
/// format: {func},{key}
pub hotkeys: Option<Vec<String>>,
/// 切换代理时自动关闭连接
pub auto_close_connection: Option<bool>,
/// 默认的延迟测试连接
pub default_latency_test: Option<String>,
}
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
@ -122,6 +128,9 @@ impl Verge {
patch!(clash_core);
patch!(hotkeys);
patch!(auto_close_connection);
patch!(default_latency_test);
self.save_file()
}
}

View File

@ -15,8 +15,14 @@ import {
ExpandLessRounded,
ExpandMoreRounded,
} from "@mui/icons-material";
import { providerHealthCheck, updateProxy } from "@/services/api";
import {
getConnections,
providerHealthCheck,
updateProxy,
deleteConnection,
} from "@/services/api";
import { getProfiles, patchProfile } from "@/services/cmds";
import { useVergeConfig } from "@/hooks/use-verge-config";
import delayManager from "@/services/delay";
import useHeadState from "./use-head-state";
import useFilterSort from "./use-filter-sort";
@ -42,6 +48,7 @@ const ProxyGroup = ({ group }: Props) => {
);
const { data: profiles } = useSWR("getProfiles", getProfiles);
const { data: vergeConfig } = useVergeConfig();
const onChangeProxy = useLockFn(async (name: string) => {
// Todo: support another proxy group type
@ -51,6 +58,16 @@ const ProxyGroup = ({ group }: Props) => {
try {
setNow(name);
await updateProxy(group.name, name);
if (vergeConfig?.auto_close_connection) {
getConnections().then((snapshot) => {
snapshot.connections.forEach((conn) => {
if (conn.chains.includes(oldValue!)) {
deleteConnection(conn.id);
}
});
});
}
} catch {
setNow(oldValue);
return; // do not update profile

View File

@ -0,0 +1,107 @@
import { useEffect, useState } from "react";
import { useLockFn } from "ahooks";
import { useTranslation } from "react-i18next";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
List,
ListItem,
ListItemText,
Switch,
TextField,
} from "@mui/material";
import { ModalHandler } from "@/hooks/use-modal-handler";
import { useVergeConfig } from "@/hooks/use-verge-config";
import Notice from "@/components/base/base-notice";
interface Props {
handler: ModalHandler;
}
const MiscViewer = ({ handler }: Props) => {
const { t } = useTranslation();
const { data, patchVerge } = useVergeConfig();
const [open, setOpen] = useState(false);
const [values, setValues] = useState({
autoCloseConnection: false,
defaultLatencyTest: "",
});
if (handler) {
handler.current = {
open: () => setOpen(true),
close: () => setOpen(false),
};
}
useEffect(() => {
if (open) {
setValues({
autoCloseConnection: data?.auto_close_connection || false,
defaultLatencyTest: data?.default_latency_test || "",
});
}
}, [open, data]);
const onSave = useLockFn(async () => {
try {
await patchVerge({
auto_close_connection: values.autoCloseConnection,
default_latency_test: values.defaultLatencyTest,
});
setOpen(false);
} catch (err: any) {
Notice.error(err.message || err.toString());
}
});
return (
<Dialog open={open} onClose={() => setOpen(false)}>
<DialogTitle>{t("Miscellaneous")}</DialogTitle>
<DialogContent sx={{ width: 420 }}>
<List>
<ListItem sx={{ padding: "5px 2px" }}>
<ListItemText primary="Auto Close Connections" />
<Switch
edge="end"
checked={values.autoCloseConnection}
onChange={(_, c) =>
setValues((v) => ({ ...v, autoCloseConnection: c }))
}
/>
</ListItem>
<ListItem sx={{ padding: "5px 2px" }}>
<ListItemText primary="Default Latency Test" />
<TextField
size="small"
autoComplete="off"
sx={{ width: 200 }}
value={values.defaultLatencyTest}
placeholder="http://www.gstatic.com/generate_204"
onChange={(e) =>
setValues((v) => ({ ...v, defaultLatencyTest: e.target.value }))
}
/>
</ListItem>
</List>
</DialogContent>
<DialogActions>
<Button variant="outlined" onClick={() => setOpen(false)}>
{t("Cancel")}
</Button>
<Button onClick={onSave} variant="contained">
{t("Save")}
</Button>
</DialogActions>
</Dialog>
);
};
export default MiscViewer;

View File

@ -124,7 +124,7 @@ const SettingClash = ({ onError }: Props) => {
/>
</SettingItem>
<SettingItem label={t("External Controller")}>
<SettingItem label={t("External")}>
<IconButton
color="inherit"
size="small"

View File

@ -22,6 +22,7 @@ import ThemeModeSwitch from "./mods/theme-mode-switch";
import ConfigViewer from "./mods/config-viewer";
import HotkeyViewer from "./mods/hotkey-viewer";
import GuardState from "./mods/guard-state";
import MiscViewer from "./mods/misc-viewer";
import SettingTheme from "./setting-theme";
interface Props {
@ -45,11 +46,13 @@ const SettingVerge = ({ onError }: Props) => {
mutateVerge({ ...vergeConfig, ...patch }, false);
};
const miscHandler = useModalHandler();
const hotkeyHandler = useModalHandler();
return (
<SettingList title={t("Verge Setting")}>
<HotkeyViewer handler={hotkeyHandler} />
<MiscViewer handler={miscHandler} />
<SettingItem label={t("Language")}>
<GuardState
@ -103,6 +106,17 @@ const SettingVerge = ({ onError }: Props) => {
</GuardState>
</SettingItem>
<SettingItem label={t("Miscellaneous")}>
<IconButton
color="inherit"
size="small"
sx={{ my: "2px" }}
onClick={() => miscHandler.current.open()}
>
<ArrowForward />
</IconButton>
</SettingItem>
<SettingItem label={t("Theme Setting")}>
<IconButton
color="inherit"

View File

@ -0,0 +1,16 @@
import useSWR from "swr";
import { getVergeConfig, patchVergeConfig } from "@/services/cmds";
export const useVergeConfig = () => {
const { data, mutate } = useSWR("getVergeConfig", getVergeConfig);
const patchVerge = async (value: Partial<CmdType.VergeConfig>) => {
await patchVergeConfig(value);
mutate();
};
return {
data,
patchVerge,
};
};

View File

@ -60,7 +60,7 @@
"IPv6": "IPv6",
"Log Level": "日志等级",
"Mixed Port": "端口设置",
"External Controller": "外部控制",
"External": "外部控制",
"Clash Core": "Clash 内核",
"Tun Mode": "Tun 模式",
"Service Mode": "服务模式",
@ -74,6 +74,7 @@
"Current System Proxy": "当前系统代理",
"Theme Mode": "主题模式",
"Theme Blur": "背景模糊",
"Miscellaneous": "杂项设置",
"Theme Setting": "主题设置",
"Hotkey Setting": "热键设置",
"Traffic Graph": "流量图显",

View File

@ -176,6 +176,12 @@ export async function providerHealthCheck(name: string) {
);
}
export async function getConnections() {
const instance = await getAxios();
const result = await instance.get("/connections");
return result as any as ApiType.Connections;
}
// Close specific connection
export async function deleteConnection(id: string) {
const instance = await getAxios();

View File

@ -165,6 +165,8 @@ declare namespace CmdType {
font_family?: string;
css_injection?: string;
};
auto_close_connection?: boolean;
default_latency_test?: string;
}
type ClashConfigValue = any;