mirror of
https://github.com/clash-verge-rev/clash-verge-rev
synced 2025-05-04 21:17:32 +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模式
|
||||
|
||||
#### 优化了:
|
||||
- 重构了后端内核管理逻辑,更轻量化和有效的管理内核,提高了性能和稳定性
|
||||
|
@ -64,12 +64,12 @@ pub fn get_app_uptime() -> CmdResult<i64> {
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn is_admin() -> CmdResult<bool> {
|
||||
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<bool> {
|
||||
{
|
||||
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)
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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 />
|
||||
|
@ -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
|
||||
|
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",
|
||||
"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",
|
||||
|
@ -554,6 +554,7 @@
|
||||
"OS Info": "操作系统信息",
|
||||
"Running Mode": "运行模式",
|
||||
"Sidecar Mode": "用户模式",
|
||||
"Administrator Mode": "管理员模式",
|
||||
"Last Check Update": "最后检查更新",
|
||||
"Click to import subscription": "点击导入订阅",
|
||||
"Update subscription successfully": "订阅更新成功",
|
||||
|
Loading…
x
Reference in New Issue
Block a user