mirror of
https://github.com/clash-verge-rev/clash-verge-rev
synced 2025-05-05 05:13:44 +08:00
feat: unify runtime mode detection; support TUN and service installation in admin mode
This commit is contained in:
parent
8e99672265
commit
c53514e060
@ -20,6 +20,7 @@
|
|||||||
- 增加载入初始配置文件的错误提示,防止切换到错误的订阅配置
|
- 增加载入初始配置文件的错误提示,防止切换到错误的订阅配置
|
||||||
- 检测是否以管理员模式运行软件,如果是提示无法使用开机自启
|
- 检测是否以管理员模式运行软件,如果是提示无法使用开机自启
|
||||||
- 代理组显示节点数量
|
- 代理组显示节点数量
|
||||||
|
- 统一运行模式检测,支持管理员模式下开启TUN模式
|
||||||
|
|
||||||
#### 优化了:
|
#### 优化了:
|
||||||
- 重构了后端内核管理逻辑,更轻量化和有效的管理内核,提高了性能和稳定性
|
- 重构了后端内核管理逻辑,更轻量化和有效的管理内核,提高了性能和稳定性
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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 />
|
||||||
|
@ -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
|
||||||
|
29
src/hooks/use-system-state.ts
Normal file
29
src/hooks/use-system-state.ts
Normal 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
|
||||||
|
};
|
||||||
|
}
|
@ -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",
|
||||||
|
@ -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": "订阅更新成功",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user