feat: unify runtime mode detection; support TUN and service installation in admin mode

This commit is contained in:
wonfen 2025-03-31 08:16:14 +08:00
parent 8e99672265
commit c53514e060
8 changed files with 109 additions and 61 deletions

View File

@ -20,6 +20,7 @@
- 增加载入初始配置文件的错误提示,防止切换到错误的订阅配置 - 增加载入初始配置文件的错误提示,防止切换到错误的订阅配置
- 检测是否以管理员模式运行软件,如果是提示无法使用开机自启 - 检测是否以管理员模式运行软件,如果是提示无法使用开机自启
- 代理组显示节点数量 - 代理组显示节点数量
- 统一运行模式检测支持管理员模式下开启TUN模式
#### 优化了: #### 优化了:
- 重构了后端内核管理逻辑,更轻量化和有效的管理内核,提高了性能和稳定性 - 重构了后端内核管理逻辑,更轻量化和有效的管理内核,提高了性能和稳定性

View File

@ -19,7 +19,7 @@ import {
SvgIconComponent, SvgIconComponent,
} from "@mui/icons-material"; } from "@mui/icons-material";
import { useVerge } from "@/hooks/use-verge"; 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"; 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 { verge } = useVerge();
const { isSidecarMode, isAdminMode } = useSystemState();
// 从verge配置中获取开关状态 // 从verge配置中获取开关状态
const { enable_system_proxy, enable_tun_mode } = verge ?? {}; const { enable_system_proxy, enable_tun_mode } = verge ?? {};
// 是否以sidecar模式运行 // 判断Tun模式是否可用 - 当处于服务模式或管理员模式时可用
const isSidecarMode = runningMode === "Sidecar"; const isTunAvailable = !isSidecarMode || isAdminMode;
// 处理错误 // 处理错误
const handleError = (err: Error) => { const handleError = (err: Error) => {
@ -171,7 +171,7 @@ export const ProxyTunCard: FC = () => {
}; };
} else { } else {
return { return {
text: isSidecarMode text: !isTunAvailable
? t("TUN Mode Service Required") ? t("TUN Mode Service Required")
: enable_tun_mode : enable_tun_mode
? t("TUN Mode Enabled") ? t("TUN Mode Enabled")
@ -179,7 +179,7 @@ export const ProxyTunCard: FC = () => {
tooltip: t("TUN Mode Intercept Info"), 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 ( return (
<Box sx={{ display: "flex", flexDirection: "column", width: "100%" }}> <Box sx={{ display: "flex", flexDirection: "column", width: "100%" }}>
@ -206,7 +206,7 @@ export const ProxyTunCard: FC = () => {
onClick={() => handleTabChange("tun")} onClick={() => handleTabChange("tun")}
icon={TroubleshootRounded} icon={TroubleshootRounded}
label={t("Tun Mode")} label={t("Tun Mode")}
hasIndicator={enable_tun_mode && !isSidecarMode} hasIndicator={enable_tun_mode && isTunAvailable}
/> />
</Stack> </Stack>

View File

@ -1,21 +1,30 @@
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Typography, Stack, Divider, Chip, IconButton, Tooltip } from "@mui/material"; 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 { useVerge } from "@/hooks/use-verge";
import { EnhancedCard } from "./enhanced-card"; import { EnhancedCard } from "./enhanced-card";
import useSWR from "swr"; 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 { useNavigate } from "react-router-dom";
import { version as appVersion } from "@root/package.json"; import { version as appVersion } from "@root/package.json";
import { useCallback, useEffect, useMemo, useState } from "react"; import { useCallback, useEffect, useMemo, useState } from "react";
import { check as checkUpdate } from "@tauri-apps/plugin-updater"; import { check as checkUpdate } from "@tauri-apps/plugin-updater";
import { useLockFn } from "ahooks"; import { useLockFn } from "ahooks";
import { Notice } from "@/components/base"; import { Notice } from "@/components/base";
import { useSystemState } from "@/hooks/use-system-state";
export const SystemInfoCard = () => { export const SystemInfoCard = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { verge, patchVerge } = useVerge(); const { verge, patchVerge } = useVerge();
const navigate = useNavigate(); const navigate = useNavigate();
const { isAdminMode, isSidecarMode, mutateRunningMode } = useSystemState();
// 系统信息状态 // 系统信息状态
const [systemState, setSystemState] = useState({ const [systemState, setSystemState] = useState({
@ -23,23 +32,6 @@ export const SystemInfoCard = () => {
lastCheckUpdate: "-", 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(() => { useEffect(() => {
// 获取系统信息 // 获取系统信息
@ -136,10 +128,10 @@ export const SystemInfoCard = () => {
// 点击运行模式处理 // 点击运行模式处理
const handleRunningModeClick = useCallback(() => { const handleRunningModeClick = useCallback(() => {
if (isSidecarMode) { if (isSidecarMode || isAdminMode) {
onInstallService(); onInstallService();
} }
}, [isSidecarMode, onInstallService]); }, [isSidecarMode, isAdminMode, onInstallService]);
// 检查更新 // 检查更新
const onCheckUpdate = useLockFn(async () => { const onCheckUpdate = useLockFn(async () => {
@ -165,15 +157,44 @@ export const SystemInfoCard = () => {
// 运行模式样式 // 运行模式样式
const runningModeStyle = useMemo( const runningModeStyle = useMemo(
() => ({ () => ({
cursor: isSidecarMode ? "pointer" : "default", cursor: (isSidecarMode || isAdminMode) ? "pointer" : "default",
textDecoration: isSidecarMode ? "underline" : "none", textDecoration: (isSidecarMode || isAdminMode) ? "underline" : "none",
display: "flex",
alignItems: "center",
gap: 0.5,
"&:hover": { "&:hover": {
opacity: isSidecarMode ? 0.7 : 1, opacity: (isSidecarMode || isAdminMode) ? 0.7 : 1,
}, },
}), }),
[isSidecarMode], [isSidecarMode, isAdminMode],
); );
// 获取模式图标和文本
const getModeIcon = () => {
if (isAdminMode) {
return (
<AdminPanelSettingsOutlined
sx={{ color: "primary.main", fontSize: 16 }}
titleAccess={t("Administrator Mode")}
/>
);
} else if (isSidecarMode) {
return (
<ExtensionOutlined
sx={{ color: "info.main", fontSize: 16 }}
titleAccess={t("Sidecar Mode")}
/>
);
} else {
return (
<DnsOutlined
sx={{ color: "success.main", fontSize: 16 }}
titleAccess={t("Service Mode")}
/>
);
}
};
// 只有当verge存在时才渲染内容 // 只有当verge存在时才渲染内容
if (!verge) return null; if (!verge) return null;
@ -220,7 +241,7 @@ export const SystemInfoCard = () => {
</Stack> </Stack>
</Stack> </Stack>
<Divider /> <Divider />
<Stack direction="row" justifyContent="space-between"> <Stack direction="row" justifyContent="space-between" alignItems="center">
<Typography variant="body2" color="text.secondary"> <Typography variant="body2" color="text.secondary">
{t("Running Mode")} {t("Running Mode")}
</Typography> </Typography>
@ -230,7 +251,10 @@ export const SystemInfoCard = () => {
onClick={handleRunningModeClick} onClick={handleRunningModeClick}
sx={runningModeStyle} sx={runningModeStyle}
> >
{isSidecarMode ? t("Sidecar Mode") : t("Service Mode")} {getModeIcon()}
{isAdminMode
? t("Administrator Mode")
: isSidecarMode ? t("Sidecar Mode") : t("Service Mode")}
</Typography> </Typography>
</Stack> </Stack>
<Divider /> <Divider />

View File

@ -18,13 +18,12 @@ import { TooltipIcon } from "@/components/base/base-tooltip-icon";
import { import {
getSystemProxy, getSystemProxy,
getAutotemProxy, getAutotemProxy,
getRunningMode,
installService, installService,
getAutoLaunchStatus, getAutoLaunchStatus,
isAdmin,
} from "@/services/cmds"; } from "@/services/cmds";
import { useLockFn } from "ahooks"; 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 { interface Props {
onError?: (err: Error) => void; onError?: (err: Error) => void;
@ -37,20 +36,16 @@ const SettingSystem = ({ onError }: Props) => {
const { data: sysproxy } = useSWR("getSystemProxy", getSystemProxy); const { data: sysproxy } = useSWR("getSystemProxy", getSystemProxy);
const { data: autoproxy } = useSWR("getAutotemProxy", getAutotemProxy); const { data: autoproxy } = useSWR("getAutotemProxy", getAutotemProxy);
const { data: runningMode, mutate: mutateRunningMode } = useSWR(
"getRunningMode",
getRunningMode,
);
const { data: autoLaunchEnabled } = useSWR( const { data: autoLaunchEnabled } = useSWR(
"getAutoLaunchStatus", "getAutoLaunchStatus",
getAutoLaunchStatus, getAutoLaunchStatus,
{ revalidateOnFocus: false } { revalidateOnFocus: false }
); );
const { data: isAdminMode = false } = useSWR(
"isAdmin", const { isAdminMode, isSidecarMode, mutateRunningMode } = useSystemState();
isAdmin,
{ revalidateOnFocus: false } // 判断Tun模式是否可用 - 当处于服务模式或管理员模式时可用
); const isTunAvailable = !isSidecarMode || isAdminMode;
// 当实际自启动状态与配置不同步时更新配置 // 当实际自启动状态与配置不同步时更新配置
useEffect(() => { useEffect(() => {
@ -64,9 +59,6 @@ const SettingSystem = ({ onError }: Props) => {
} }
}, [autoLaunchEnabled]); }, [autoLaunchEnabled]);
// 是否以sidecar模式运行
const isSidecarMode = runningMode === "Sidecar";
const sysproxyRef = useRef<DialogRef>(null); const sysproxyRef = useRef<DialogRef>(null);
const tunRef = useRef<DialogRef>(null); const tunRef = useRef<DialogRef>(null);
@ -117,12 +109,12 @@ const SettingSystem = ({ onError }: Props) => {
icon={SettingsRounded} icon={SettingsRounded}
onClick={() => tunRef.current?.open()} onClick={() => tunRef.current?.open()}
/> />
{isSidecarMode && ( {isSidecarMode && !isAdminMode && (
<Tooltip title={t("TUN requires Service Mode")}> <Tooltip title={t("TUN requires Service Mode")}>
<WarningRounded sx={{ color: "warning.main", mr: 1 }} /> <WarningRounded sx={{ color: "warning.main", mr: 1 }} />
</Tooltip> </Tooltip>
)} )}
{isSidecarMode && ( {isSidecarMode && !isAdminMode && (
<Tooltip title={t("Install Service")}> <Tooltip title={t("Install Service")}>
<Button <Button
variant="outlined" variant="outlined"
@ -144,20 +136,20 @@ const SettingSystem = ({ onError }: Props) => {
onCatch={onError} onCatch={onError}
onFormat={onSwitchFormat} onFormat={onSwitchFormat}
onChange={(e) => { onChange={(e) => {
// 当在sidecar模式下禁用切换 // 当在sidecar模式下且非管理员模式时禁用切换
if (isSidecarMode) return; if (isSidecarMode && !isAdminMode) return;
onChangeData({ enable_tun_mode: e }); onChangeData({ enable_tun_mode: e });
}} }}
onGuard={(e) => { onGuard={(e) => {
// 当在sidecar模式下禁用切换 // 当在sidecar模式下且非管理员模式时禁用切换
if (isSidecarMode) { if (isSidecarMode && !isAdminMode) {
Notice.error(t("TUN requires Service Mode"), 2000); Notice.error(t("TUN requires Service Mode"), 2000);
return Promise.reject(new Error(t("TUN requires Service Mode"))); return Promise.reject(new Error(t("TUN requires Service Mode")));
} }
return patchVerge({ enable_tun_mode: e }); return patchVerge({ enable_tun_mode: e });
}} }}
> >
<Switch edge="end" disabled={isSidecarMode} /> <Switch edge="end" disabled={isSidecarMode && !isAdminMode} />
</GuardState> </GuardState>
</SettingItem> </SettingItem>
<SettingItem <SettingItem

View File

@ -0,0 +1,29 @@
import useSWR from "swr";
import { getRunningMode, isAdmin } from "@/services/cmds";
/**
* hook
*
*/
export function useSystemState() {
// 获取运行模式
const { data: runningMode = "Sidecar", mutate: mutateRunningMode } =
useSWR("getRunningMode", getRunningMode, {
suspense: false,
revalidateOnFocus: false
});
// 获取管理员状态
const { data: isAdminMode = false } =
useSWR("isAdmin", isAdmin, {
suspense: false,
revalidateOnFocus: false
});
return {
runningMode,
isAdminMode,
isSidecarMode: runningMode === "Sidecar",
mutateRunningMode
};
}

View File

@ -554,6 +554,7 @@
"OS Info": "OS Info", "OS Info": "OS Info",
"Running Mode": "Running Mode", "Running Mode": "Running Mode",
"Sidecar Mode": "User Mode", "Sidecar Mode": "User Mode",
"Administrator Mode": "Administrator Mode",
"Last Check Update": "Last Check Update", "Last Check Update": "Last Check Update",
"Click to import subscription": "Click to import subscription", "Click to import subscription": "Click to import subscription",
"Update subscription successfully": "Update subscription successfully", "Update subscription successfully": "Update subscription successfully",

View File

@ -554,6 +554,7 @@
"OS Info": "操作系统信息", "OS Info": "操作系统信息",
"Running Mode": "运行模式", "Running Mode": "运行模式",
"Sidecar Mode": "用户模式", "Sidecar Mode": "用户模式",
"Administrator Mode": "管理员模式",
"Last Check Update": "最后检查更新", "Last Check Update": "最后检查更新",
"Click to import subscription": "点击导入订阅", "Click to import subscription": "点击导入订阅",
"Update subscription successfully": "订阅更新成功", "Update subscription successfully": "订阅更新成功",