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,
} 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 (
<Box sx={{ display: "flex", flexDirection: "column", width: "100%" }}>
@ -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}
/>
</Stack>

View File

@ -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 (
<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存在时才渲染内容
if (!verge) return null;
@ -220,7 +241,7 @@ export const SystemInfoCard = () => {
</Stack>
</Stack>
<Divider />
<Stack direction="row" justifyContent="space-between">
<Stack direction="row" justifyContent="space-between" alignItems="center">
<Typography variant="body2" color="text.secondary">
{t("Running Mode")}
</Typography>
@ -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")}
</Typography>
</Stack>
<Divider />

View File

@ -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<DialogRef>(null);
const tunRef = useRef<DialogRef>(null);
@ -117,12 +109,12 @@ const SettingSystem = ({ onError }: Props) => {
icon={SettingsRounded}
onClick={() => tunRef.current?.open()}
/>
{isSidecarMode && (
{isSidecarMode && !isAdminMode && (
<Tooltip title={t("TUN requires Service Mode")}>
<WarningRounded sx={{ color: "warning.main", mr: 1 }} />
</Tooltip>
)}
{isSidecarMode && (
{isSidecarMode && !isAdminMode && (
<Tooltip title={t("Install Service")}>
<Button
variant="outlined"
@ -144,20 +136,20 @@ const SettingSystem = ({ onError }: Props) => {
onCatch={onError}
onFormat={onSwitchFormat}
onChange={(e) => {
// 当在sidecar模式下禁用切换
if (isSidecarMode) return;
// 当在sidecar模式下且非管理员模式时禁用切换
if (isSidecarMode && !isAdminMode) return;
onChangeData({ enable_tun_mode: e });
}}
onGuard={(e) => {
// 当在sidecar模式下禁用切换
if (isSidecarMode) {
// 当在sidecar模式下且非管理员模式时禁用切换
if (isSidecarMode && !isAdminMode) {
Notice.error(t("TUN requires Service Mode"), 2000);
return Promise.reject(new Error(t("TUN requires Service Mode")));
}
return patchVerge({ enable_tun_mode: e });
}}
>
<Switch edge="end" disabled={isSidecarMode} />
<Switch edge="end" disabled={isSidecarMode && !isAdminMode} />
</GuardState>
</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",
"Running Mode": "Running Mode",
"Sidecar Mode": "User Mode",
"Administrator Mode": "Administrator Mode",
"Last Check Update": "Last Check Update",
"Click to import subscription": "Click to import subscription",
"Update subscription successfully": "Update subscription successfully",

View File

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