From d84b5456ffd2c987717539b0d94c9555b1ae62a2 Mon Sep 17 00:00:00 2001 From: wonfen Date: Wed, 16 Apr 2025 20:29:06 +0800 Subject: [PATCH] refactor: external toggle control logic & disable external-controller by default --- src-tauri/src/config/clash.rs | 23 ++++-- .../setting/mods/controller-viewer.tsx | 50 ++++++------- src/components/setting/setting-clash.tsx | 74 ++++++++++--------- 3 files changed, 78 insertions(+), 69 deletions(-) diff --git a/src-tauri/src/config/clash.rs b/src-tauri/src/config/clash.rs index e2936b96..6866cbf4 100644 --- a/src-tauri/src/config/clash.rs +++ b/src-tauri/src/config/clash.rs @@ -50,7 +50,6 @@ impl IClashTemp { map.insert("allow-lan".into(), false.into()); map.insert("ipv6".into(), true.into()); map.insert("mode".into(), "rule".into()); - map.insert("external-controller".into(), "127.0.0.1:9097".into()); #[cfg(not(target_os = "windows"))] map.insert("external-controller-unix".into(), "mihomo.sock".into()); #[cfg(target_os = "windows")] @@ -215,6 +214,10 @@ impl IClashTemp { .and_then(|value| match value.as_str() { Some(val_str) => { let val_str = val_str.trim(); + + if val_str.is_empty() { + return None; + } let val = match val_str.starts_with(':') { true => format!("127.0.0.1{val_str}"), @@ -227,11 +230,15 @@ impl IClashTemp { } None => None, }) - .unwrap_or("127.0.0.1:9097".into()) + .unwrap_or_else(|| String::new()) } pub fn guard_client_ctrl(config: &Mapping) -> String { let value = Self::guard_server_ctrl(config); + if value.is_empty() { + return value; + } + match SocketAddr::from_str(value.as_str()) { Ok(mut socket) => { if socket.ip().is_unspecified() { @@ -239,7 +246,7 @@ impl IClashTemp { } socket.to_string() } - Err(_) => "127.0.0.1:9097".into(), + Err(_) => String::new(), } } } @@ -278,12 +285,12 @@ fn test_clash_info() { assert_eq!( IClashTemp(IClashTemp::guard(Mapping::new())).get_client_info(), - get_result(7897, "127.0.0.1:9097") + get_result(7897, "") ); - assert_eq!(get_case("", ""), get_result(7897, "127.0.0.1:9097")); + assert_eq!(get_case("", ""), get_result(7897, "")); - assert_eq!(get_case(65537, ""), get_result(1, "127.0.0.1:9097")); + assert_eq!(get_case(65537, ""), get_result(1, "")); assert_eq!( get_case(8888, "127.0.0.1:8888"), @@ -292,7 +299,7 @@ fn test_clash_info() { assert_eq!( get_case(8888, " :98888 "), - get_result(8888, "127.0.0.1:9097") + get_result(8888, "") ); assert_eq!( @@ -317,7 +324,7 @@ fn test_clash_info() { assert_eq!( get_case(8888, "192.168.1.1:80800"), - get_result(8888, "127.0.0.1:9097") + get_result(8888, "") ); } diff --git a/src/components/setting/mods/controller-viewer.tsx b/src/components/setting/mods/controller-viewer.tsx index dfb50679..dea639ba 100644 --- a/src/components/setting/mods/controller-viewer.tsx +++ b/src/components/setting/mods/controller-viewer.tsx @@ -3,8 +3,9 @@ import { useLockFn } from "ahooks"; import { useTranslation } from "react-i18next"; import { List, ListItem, ListItemText, TextField, Typography, Box } from "@mui/material"; import { useClashInfo } from "@/hooks/use-clash"; -import { BaseDialog, DialogRef, Notice, Switch } from "@/components/base"; +import { BaseDialog, DialogRef, Notice } from "@/components/base"; import { useVerge } from "@/hooks/use-verge"; +import { useClash } from "@/hooks/use-clash"; export const ControllerViewer = forwardRef((props, ref) => { const { t } = useTranslation(); @@ -12,43 +13,39 @@ export const ControllerViewer = forwardRef((props, ref) => { const { clashInfo, patchInfo } = useClashInfo(); const { verge, patchVerge } = useVerge(); + const { clash } = useClash(); - const [controller, setController] = useState(clashInfo?.server || ""); - const [secret, setSecret] = useState(clashInfo?.secret || ""); + const [controller, setController] = useState(""); + const [secret, setSecret] = useState(""); - // 获取外部控制器开关状态 - const [enableController, setEnableController] = useState(() => { - const savedState = localStorage.getItem("enable_external_controller"); - if (savedState !== null) { - return savedState === "true"; - } - return verge?.enable_external_controller ?? true; - }); + const enableController = Boolean(clash?.["external-controller"] && clash?.["external-controller"] !== ""); useImperativeHandle(ref, () => ({ open: () => { setOpen(true); - setController(clashInfo?.server || ""); - setSecret(clashInfo?.secret || ""); - // 从localStorage更新开关状态 - const savedState = localStorage.getItem("enable_external_controller"); - if (savedState !== null) { - setEnableController(savedState === "true"); - } else { - setEnableController(verge?.enable_external_controller ?? true); - } + setController(clash?.["external-controller"] || ""); + setSecret(clash?.secret || ""); }, close: () => setOpen(false), })); const onSave = useLockFn(async () => { try { - // 只有在启用外部控制器时才更新配置 - if (enableController) { - await patchInfo({ "external-controller": controller, secret }); - } - Notice.success(t("External Controller Settings Saved"), 1000); setOpen(false); + const promises = []; + promises.push( + patchInfo({ + "external-controller": controller || "127.0.0.1:9097", + secret + }) + ); + + // 同步verge配置 + if (controller && controller !== "") { + promises.push(patchVerge({ enable_external_controller: true })); + } + await Promise.all(promises); + Notice.success(t("External Controller Settings Saved"), 1000); } catch (err: any) { Notice.error(err.message || err.toString(), 4000); } @@ -61,6 +58,7 @@ export const ControllerViewer = forwardRef((props, ref) => { contentSx={{ width: 400 }} okBtn={t("Save")} cancelBtn={t("Cancel")} + disableOk={!enableController} onClose={() => setOpen(false)} onCancel={() => setOpen(false)} onOk={onSave} @@ -81,7 +79,7 @@ export const ControllerViewer = forwardRef((props, ref) => { size="small" sx={{ width: 175 }} value={controller} - placeholder="Required" + placeholder="127.0.0.1:9097" onChange={(e) => setController(e.target.value)} disabled={!enableController} /> diff --git a/src/components/setting/setting-clash.tsx b/src/components/setting/setting-clash.tsx index 55cfef74..e6142275 100644 --- a/src/components/setting/setting-clash.tsx +++ b/src/components/setting/setting-clash.tsx @@ -44,6 +44,7 @@ const SettingClash = ({ onError }: Props) => { "log-level": logLevel, "unified-delay": unifiedDelay, dns, + "external-controller": externalController } = clash ?? {}; const { enable_random_port = false, verge_mixed_port } = verge ?? {}; @@ -59,15 +60,6 @@ const SettingClash = ({ onError }: Props) => { return verge?.enable_dns_settings ?? false; }); - // 添加外部控制器开关状态 - const [enableController, setEnableController] = useState(() => { - const savedState = localStorage.getItem("enable_external_controller"); - if (savedState !== null) { - return savedState === "true"; - } - return verge?.enable_external_controller ?? true; - }); - const { addListener } = useListen(); const webRef = useRef(null); @@ -118,25 +110,14 @@ const SettingClash = ({ onError }: Props) => { } }); - // 处理外部控制器开关状态变化 - const handleControllerToggle = useLockFn(async (enable: boolean) => { - try { - setEnableController(enable); - localStorage.setItem("enable_external_controller", String(enable)); - await patchVerge({ enable_external_controller: enable }); - if (!enable) { - await patchInfo({ "external-controller": "", secret: "" }); - } else { - // 如果开启,恢复默认值或之前的值 - const server = clashInfo?.server || "127.0.0.1:9097"; - await patchInfo({ "external-controller": server, secret: clashInfo?.secret || "" }); - } - } catch (err: any) { - setEnableController(!enable); - localStorage.setItem("enable_external_controller", String(!enable)); - Notice.error(err.message || err.toString()); + // 同步外部控制器配置和开关状态 + useEffect(() => { + const hasController = Boolean(externalController && externalController !== ""); + const isEnabled = Boolean(verge?.enable_external_controller); + if (hasController !== isEnabled) { + patchVerge({ enable_external_controller: hasController }); } - }); + }, [externalController, verge?.enable_external_controller]); return ( @@ -286,26 +267,49 @@ const SettingClash = ({ onError }: Props) => { /> } > - handleControllerToggle(checked)} - /> + { + onChangeVerge({ enable_external_controller: e }); + onChangeData({ + "external-controller": e ? (externalController || "127.0.0.1:9097") : "" + }); + }} + onGuard={async (e) => { + const promises = [ + patchVerge({ enable_external_controller: e }) + ]; + + if (!e) { + // 如果禁用,清空配置 + promises.push(patchClash({ "external-controller": "" })); + } else if (!externalController || externalController === "") { + promises.push(patchClash({ "external-controller": "127.0.0.1:9097" })); + } + await Promise.all(promises); + }} + > + + webRef.current?.open() : undefined} + onClick={(externalController && externalController !== "") ? () => webRef.current?.open() : undefined} label={ {t("Web UI")} } extra={ - !enableController && ( + (!externalController || externalController === "") && (