From c53514e060474ecbfcfd2f026842323826b00046 Mon Sep 17 00:00:00 2001 From: wonfen Date: Mon, 31 Mar 2025 08:16:14 +0800 Subject: [PATCH] feat: unify runtime mode detection; support TUN and service installation in admin mode --- UPDATELOG.md | 1 + src-tauri/src/cmd/system.rs | 8 +-- src/components/home/proxy-tun-card.tsx | 16 ++--- src/components/home/system-info-card.tsx | 78 +++++++++++++++-------- src/components/setting/setting-system.tsx | 36 ++++------- src/hooks/use-system-state.ts | 29 +++++++++ src/locales/en.json | 1 + src/locales/zh.json | 1 + 8 files changed, 109 insertions(+), 61 deletions(-) create mode 100644 src/hooks/use-system-state.ts diff --git a/UPDATELOG.md b/UPDATELOG.md index 43559f12..63e3c80a 100644 --- a/UPDATELOG.md +++ b/UPDATELOG.md @@ -20,6 +20,7 @@ - 增加载入初始配置文件的错误提示,防止切换到错误的订阅配置 - 检测是否以管理员模式运行软件,如果是提示无法使用开机自启 - 代理组显示节点数量 + - 统一运行模式检测,支持管理员模式下开启TUN模式 #### 优化了: - 重构了后端内核管理逻辑,更轻量化和有效的管理内核,提高了性能和稳定性 diff --git a/src-tauri/src/cmd/system.rs b/src-tauri/src/cmd/system.rs index 6b7453fc..a109180c 100644 --- a/src-tauri/src/cmd/system.rs +++ b/src-tauri/src/cmd/system.rs @@ -64,12 +64,12 @@ pub fn get_app_uptime() -> CmdResult { #[cfg(target_os = "windows")] pub fn is_admin() -> CmdResult { use deelevate::{PrivilegeLevel, Token}; - + let result = Token::with_current_process() .and_then(|token| token.privilege_level()) .map(|level| level != PrivilegeLevel::NotPrivileged) .unwrap_or(false); - + Ok(result) } @@ -81,12 +81,12 @@ pub fn is_admin() -> CmdResult { { Ok(unsafe { libc::geteuid() } == 0) } - + #[cfg(target_os = "linux")] { Ok(unsafe { libc::geteuid() } == 0) } - + #[cfg(not(any(target_os = "macos", target_os = "linux")))] { Ok(false) diff --git a/src/components/home/proxy-tun-card.tsx b/src/components/home/proxy-tun-card.tsx index 89300106..720812d2 100644 --- a/src/components/home/proxy-tun-card.tsx +++ b/src/components/home/proxy-tun-card.tsx @@ -19,7 +19,7 @@ import { SvgIconComponent, } from "@mui/icons-material"; import { useVerge } from "@/hooks/use-verge"; -import { useAppData } from "@/providers/app-data-provider"; +import { useSystemState } from "@/hooks/use-system-state"; const LOCAL_STORAGE_TAB_KEY = "clash-verge-proxy-active-tab"; @@ -140,14 +140,14 @@ export const ProxyTunCard: FC = () => { ); // 获取代理状态信息 - const { sysproxy, runningMode } = useAppData(); const { verge } = useVerge(); + const { isSidecarMode, isAdminMode } = useSystemState(); // 从verge配置中获取开关状态 const { enable_system_proxy, enable_tun_mode } = verge ?? {}; - - // 是否以sidecar模式运行 - const isSidecarMode = runningMode === "Sidecar"; + + // 判断Tun模式是否可用 - 当处于服务模式或管理员模式时可用 + const isTunAvailable = !isSidecarMode || isAdminMode; // 处理错误 const handleError = (err: Error) => { @@ -171,7 +171,7 @@ export const ProxyTunCard: FC = () => { }; } else { return { - text: isSidecarMode + text: !isTunAvailable ? t("TUN Mode Service Required") : enable_tun_mode ? t("TUN Mode Enabled") @@ -179,7 +179,7 @@ export const ProxyTunCard: FC = () => { tooltip: t("TUN Mode Intercept Info"), }; } - }, [activeTab, enable_system_proxy, enable_tun_mode, isSidecarMode, t]); + }, [activeTab, enable_system_proxy, enable_tun_mode, isTunAvailable, t]); return ( @@ -206,7 +206,7 @@ export const ProxyTunCard: FC = () => { onClick={() => handleTabChange("tun")} icon={TroubleshootRounded} label={t("Tun Mode")} - hasIndicator={enable_tun_mode && !isSidecarMode} + hasIndicator={enable_tun_mode && isTunAvailable} /> diff --git a/src/components/home/system-info-card.tsx b/src/components/home/system-info-card.tsx index 86f0ef67..b0aa6fbf 100644 --- a/src/components/home/system-info-card.tsx +++ b/src/components/home/system-info-card.tsx @@ -1,21 +1,30 @@ import { useTranslation } from "react-i18next"; import { Typography, Stack, Divider, Chip, IconButton, Tooltip } from "@mui/material"; -import { InfoOutlined, SettingsOutlined, WarningOutlined } from "@mui/icons-material"; +import { + InfoOutlined, + SettingsOutlined, + WarningOutlined, + AdminPanelSettingsOutlined, + DnsOutlined, + ExtensionOutlined +} from "@mui/icons-material"; import { useVerge } from "@/hooks/use-verge"; import { EnhancedCard } from "./enhanced-card"; import useSWR from "swr"; -import { getRunningMode, getSystemInfo, installService, isAdmin } from "@/services/cmds"; +import { getSystemInfo, installService } from "@/services/cmds"; import { useNavigate } from "react-router-dom"; import { version as appVersion } from "@root/package.json"; import { useCallback, useEffect, useMemo, useState } from "react"; import { check as checkUpdate } from "@tauri-apps/plugin-updater"; import { useLockFn } from "ahooks"; import { Notice } from "@/components/base"; +import { useSystemState } from "@/hooks/use-system-state"; export const SystemInfoCard = () => { const { t } = useTranslation(); const { verge, patchVerge } = useVerge(); const navigate = useNavigate(); + const { isAdminMode, isSidecarMode, mutateRunningMode } = useSystemState(); // 系统信息状态 const [systemState, setSystemState] = useState({ @@ -23,23 +32,6 @@ export const SystemInfoCard = () => { lastCheckUpdate: "-", }); - // 获取运行模式 - const { data: runningMode = "Sidecar", mutate: mutateRunningMode } = useSWR( - "getRunningMode", - getRunningMode, - { suspense: false, revalidateOnFocus: false }, - ); - - // 获取管理员状态 - const { data: isAdminMode = false } = useSWR( - "isAdmin", - isAdmin, - { suspense: false, revalidateOnFocus: false }, - ); - - // 是否以sidecar模式运行 - const isSidecarMode = runningMode === "Sidecar"; - // 初始化系统信息 useEffect(() => { // 获取系统信息 @@ -136,10 +128,10 @@ export const SystemInfoCard = () => { // 点击运行模式处理 const handleRunningModeClick = useCallback(() => { - if (isSidecarMode) { + if (isSidecarMode || isAdminMode) { onInstallService(); } - }, [isSidecarMode, onInstallService]); + }, [isSidecarMode, isAdminMode, onInstallService]); // 检查更新 const onCheckUpdate = useLockFn(async () => { @@ -165,15 +157,44 @@ export const SystemInfoCard = () => { // 运行模式样式 const runningModeStyle = useMemo( () => ({ - cursor: isSidecarMode ? "pointer" : "default", - textDecoration: isSidecarMode ? "underline" : "none", + cursor: (isSidecarMode || isAdminMode) ? "pointer" : "default", + textDecoration: (isSidecarMode || isAdminMode) ? "underline" : "none", + display: "flex", + alignItems: "center", + gap: 0.5, "&:hover": { - opacity: isSidecarMode ? 0.7 : 1, + opacity: (isSidecarMode || isAdminMode) ? 0.7 : 1, }, }), - [isSidecarMode], + [isSidecarMode, isAdminMode], ); + // 获取模式图标和文本 + const getModeIcon = () => { + if (isAdminMode) { + return ( + + ); + } else if (isSidecarMode) { + return ( + + ); + } else { + return ( + + ); + } + }; + // 只有当verge存在时才渲染内容 if (!verge) return null; @@ -220,7 +241,7 @@ export const SystemInfoCard = () => { - + {t("Running Mode")} @@ -230,7 +251,10 @@ export const SystemInfoCard = () => { onClick={handleRunningModeClick} sx={runningModeStyle} > - {isSidecarMode ? t("Sidecar Mode") : t("Service Mode")} + {getModeIcon()} + {isAdminMode + ? t("Administrator Mode") + : isSidecarMode ? t("Sidecar Mode") : t("Service Mode")} diff --git a/src/components/setting/setting-system.tsx b/src/components/setting/setting-system.tsx index 5f431599..ef5ee59a 100644 --- a/src/components/setting/setting-system.tsx +++ b/src/components/setting/setting-system.tsx @@ -18,13 +18,12 @@ import { TooltipIcon } from "@/components/base/base-tooltip-icon"; import { getSystemProxy, getAutotemProxy, - getRunningMode, installService, getAutoLaunchStatus, - isAdmin, } from "@/services/cmds"; import { useLockFn } from "ahooks"; -import { Box, Button, Tooltip } from "@mui/material"; +import { Button, Tooltip } from "@mui/material"; +import { useSystemState } from "@/hooks/use-system-state"; interface Props { onError?: (err: Error) => void; @@ -37,20 +36,16 @@ const SettingSystem = ({ onError }: Props) => { const { data: sysproxy } = useSWR("getSystemProxy", getSystemProxy); const { data: autoproxy } = useSWR("getAutotemProxy", getAutotemProxy); - const { data: runningMode, mutate: mutateRunningMode } = useSWR( - "getRunningMode", - getRunningMode, - ); const { data: autoLaunchEnabled } = useSWR( "getAutoLaunchStatus", getAutoLaunchStatus, { revalidateOnFocus: false } ); - const { data: isAdminMode = false } = useSWR( - "isAdmin", - isAdmin, - { revalidateOnFocus: false } - ); + + const { isAdminMode, isSidecarMode, mutateRunningMode } = useSystemState(); + + // 判断Tun模式是否可用 - 当处于服务模式或管理员模式时可用 + const isTunAvailable = !isSidecarMode || isAdminMode; // 当实际自启动状态与配置不同步时更新配置 useEffect(() => { @@ -64,9 +59,6 @@ const SettingSystem = ({ onError }: Props) => { } }, [autoLaunchEnabled]); - // 是否以sidecar模式运行 - const isSidecarMode = runningMode === "Sidecar"; - const sysproxyRef = useRef(null); const tunRef = useRef(null); @@ -117,12 +109,12 @@ const SettingSystem = ({ onError }: Props) => { icon={SettingsRounded} onClick={() => tunRef.current?.open()} /> - {isSidecarMode && ( + {isSidecarMode && !isAdminMode && ( )} - {isSidecarMode && ( + {isSidecarMode && !isAdminMode && (