From 0cfd718d8a178b17cd97f33c77bcd01c00772b76 Mon Sep 17 00:00:00 2001 From: GyDi Date: Thu, 10 Nov 2022 01:27:05 +0800 Subject: [PATCH] feat: auto close connection when proxy changed --- src-tauri/src/data/verge.rs | 9 ++ src/components/proxy/proxy-group.tsx | 19 +++- src/components/setting/mods/misc-viewer.tsx | 107 ++++++++++++++++++++ src/components/setting/setting-clash.tsx | 2 +- src/components/setting/setting-verge.tsx | 14 +++ src/hooks/use-verge-config.ts | 16 +++ src/locales/zh.json | 3 +- src/services/api.ts | 6 ++ src/services/types.d.ts | 2 + 9 files changed, 175 insertions(+), 3 deletions(-) create mode 100644 src/components/setting/mods/misc-viewer.tsx create mode 100644 src/hooks/use-verge-config.ts diff --git a/src-tauri/src/data/verge.rs b/src-tauri/src/data/verge.rs index 90aa5b7..9a5519e 100644 --- a/src-tauri/src/data/verge.rs +++ b/src-tauri/src/data/verge.rs @@ -60,6 +60,12 @@ pub struct Verge { /// hotkey map /// format: {func},{key} pub hotkeys: Option>, + + /// 切换代理时自动关闭连接 + pub auto_close_connection: Option, + + /// 默认的延迟测试连接 + pub default_latency_test: Option, } #[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() } } diff --git a/src/components/proxy/proxy-group.tsx b/src/components/proxy/proxy-group.tsx index 95d8adb..d25e395 100644 --- a/src/components/proxy/proxy-group.tsx +++ b/src/components/proxy/proxy-group.tsx @@ -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 diff --git a/src/components/setting/mods/misc-viewer.tsx b/src/components/setting/mods/misc-viewer.tsx new file mode 100644 index 0000000..5ab3abf --- /dev/null +++ b/src/components/setting/mods/misc-viewer.tsx @@ -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 ( + setOpen(false)}> + {t("Miscellaneous")} + + + + + + + setValues((v) => ({ ...v, autoCloseConnection: c })) + } + /> + + + + + + setValues((v) => ({ ...v, defaultLatencyTest: e.target.value })) + } + /> + + + + + + + + + + ); +}; + +export default MiscViewer; diff --git a/src/components/setting/setting-clash.tsx b/src/components/setting/setting-clash.tsx index 8ddad18..fdc7a38 100644 --- a/src/components/setting/setting-clash.tsx +++ b/src/components/setting/setting-clash.tsx @@ -124,7 +124,7 @@ const SettingClash = ({ onError }: Props) => { /> - + { mutateVerge({ ...vergeConfig, ...patch }, false); }; + const miscHandler = useModalHandler(); const hotkeyHandler = useModalHandler(); return ( + { + + miscHandler.current.open()} + > + + + + { + const { data, mutate } = useSWR("getVergeConfig", getVergeConfig); + + const patchVerge = async (value: Partial) => { + await patchVergeConfig(value); + mutate(); + }; + + return { + data, + patchVerge, + }; +}; diff --git a/src/locales/zh.json b/src/locales/zh.json index a1fac5e..eb9d627 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -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": "流量图显", diff --git a/src/services/api.ts b/src/services/api.ts index 65594d5..625f96e 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -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(); diff --git a/src/services/types.d.ts b/src/services/types.d.ts index 804d343..e84a281 100644 --- a/src/services/types.d.ts +++ b/src/services/types.d.ts @@ -165,6 +165,8 @@ declare namespace CmdType { font_family?: string; css_injection?: string; }; + auto_close_connection?: boolean; + default_latency_test?: string; } type ClashConfigValue = any;