feat: better service status and TUN mode usable checks in Setting Page

This commit is contained in:
Tunglies
2025-05-12 19:04:08 +08:00
parent d587ed09a5
commit 5b6c9be99f
14 changed files with 127 additions and 88 deletions

View File

@@ -20,6 +20,7 @@ import {
getAutotemProxy,
installService,
getAutoLaunchStatus,
restartCore,
} from "@/services/cmds";
import { useLockFn } from "ahooks";
import { Button, Tooltip } from "@mui/material";
@@ -41,25 +42,18 @@ const SettingSystem = ({ onError }: Props) => {
const { data: autoLaunchEnabled } = useSWR(
"getAutoLaunchStatus",
getAutoLaunchStatus,
{ revalidateOnFocus: false }
{ revalidateOnFocus: false },
);
const { isAdminMode, isSidecarMode, mutateRunningMode } = useSystemState();
const { isAdminMode, isSidecarMode, mutateRunningMode, isServiceOk } =
useSystemState();
console.log("Is service running:", isServiceOk);
// 判断Tun模式是否可用 - 当处于服务模式或管理员模式时可用
const isTunAvailable = !isSidecarMode || isAdminMode;
const isTunAvailable = isServiceOk || (isSidecarMode && !isAdminMode);
// 当实际自启动状态与配置不同步时更新配置
useEffect(() => {
if (
autoLaunchEnabled !== undefined &&
verge &&
verge.enable_auto_launch !== autoLaunchEnabled
) {
// 静默更新配置不触发UI刷新
mutateVerge({ ...verge, enable_auto_launch: autoLaunchEnabled }, false);
}
}, [autoLaunchEnabled]);
console.log("is tun isTunAvailable:", isTunAvailable);
const sysproxyRef = useRef<DialogRef>(null);
const tunRef = useRef<DialogRef>(null);
@@ -87,13 +81,16 @@ const SettingSystem = ({ onError }: Props) => {
// 安装系统服务
const onInstallService = useLockFn(async () => {
try {
showNotice('info', t("Installing Service..."), 1000);
showNotice("info", t("Installing Service..."), 1000);
await installService();
showNotice('success', t("Service Installed Successfully"), 2000);
showNotice("success", t("Service Installed Successfully"), 2000);
await restartCore();
showNotice("info", t("Restarting Core"), 1000);
console.log("restartCore");
// 重新获取运行模式
await mutateRunningMode();
} catch (err: any) {
showNotice('error', err.message || err.toString(), 3000);
showNotice("error", err.message || err.toString(), 3000);
}
});
@@ -111,12 +108,12 @@ const SettingSystem = ({ onError }: Props) => {
icon={SettingsRounded}
onClick={() => tunRef.current?.open()}
/>
{isSidecarMode && !isAdminMode && (
{!isServiceOk && !isAdminMode && (
<Tooltip title={t("TUN requires Service Mode")}>
<WarningRounded sx={{ color: "warning.main", mr: 1 }} />
</Tooltip>
)}
{isSidecarMode && !isAdminMode && (
{!isServiceOk && !isAdminMode && (
<Tooltip title={t("Install Service")}>
<Button
variant="outlined"
@@ -138,20 +135,20 @@ const SettingSystem = ({ onError }: Props) => {
onCatch={onError}
onFormat={onSwitchFormat}
onChange={(e) => {
// 当在sidecar模式下且非管理员模式时禁用切换
if (isSidecarMode && !isAdminMode) return;
// 非 Service 状态禁止切换
if (!isServiceOk) return;
onChangeData({ enable_tun_mode: e });
}}
onGuard={(e) => {
// 当在sidecar模式下且非管理员模式时禁用切换
if (isSidecarMode && !isAdminMode) {
showNotice('error', t("TUN requires Service Mode"), 2000);
// 非 Service 状态禁止切换
if (!isServiceOk) {
showNotice("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 && !isAdminMode} />
<Switch edge="end" disabled={isServiceOk} />
</GuardState>
</SettingItem>
<SettingItem
@@ -195,11 +192,13 @@ const SettingSystem = ({ onError }: Props) => {
</GuardState>
</SettingItem>
<SettingItem
<SettingItem
label={t("Auto Launch")}
extra={
isAdminMode && (
<Tooltip title={t("Administrator mode may not support auto launch")}>
<Tooltip
title={t("Administrator mode may not support auto launch")}
>
<WarningRounded sx={{ color: "warning.main", mr: 1 }} />
</Tooltip>
)
@@ -216,9 +215,13 @@ const SettingSystem = ({ onError }: Props) => {
}}
onGuard={async (e) => {
if (isAdminMode) {
showNotice('info', t("Administrator mode may not support auto launch"), 2000);
showNotice(
"info",
t("Administrator mode may not support auto launch"),
2000,
);
}
try {
// 在应用更改之前先触发UI更新让用户立即看到反馈
onChangeData({ enable_auto_launch: e });

View File

@@ -1,29 +1,42 @@
import useSWR from "swr";
import { getRunningMode, isAdmin } from "@/services/cmds";
import { getRunningMode, isAdmin, isServiceAvailable } from "@/services/cmds";
/**
* 自定义 hook 用于获取系统运行状态
* 包括运行模式管理员状态
* 包括运行模式管理员状态、系统服务是否可用
*/
export function useSystemState() {
// 获取运行模式
const { data: runningMode = "Sidecar", mutate: mutateRunningMode } =
useSWR("getRunningMode", getRunningMode, {
const { data: runningMode = "Sidecar", mutate: mutateRunningMode } = useSWR(
"getRunningMode",
getRunningMode,
{
suspense: false,
revalidateOnFocus: false
});
revalidateOnFocus: false,
},
);
// 获取管理员状态
const { data: isAdminMode = false } =
useSWR("isAdmin", isAdmin, {
const { data: isAdminMode = false } = useSWR("isAdmin", isAdmin, {
suspense: false,
revalidateOnFocus: false,
});
// 获取系统服务状态
const { data: isServiceOk = false } = useSWR(
"isServiceAvailable",
isServiceAvailable,
{
suspense: false,
revalidateOnFocus: false
});
revalidateOnFocus: false,
},
);
return {
runningMode,
isAdminMode,
isSidecarMode: runningMode === "Sidecar",
mutateRunningMode
mutateRunningMode,
isServiceOk,
};
}
}

View File

@@ -145,19 +145,19 @@ export async function getAppDir() {
export async function openAppDir() {
return invoke<void>("open_app_dir").catch((err) =>
showNotice('error', err?.message || err.toString()),
showNotice("error", err?.message || err.toString()),
);
}
export async function openCoreDir() {
return invoke<void>("open_core_dir").catch((err) =>
showNotice('error', err?.message || err.toString()),
showNotice("error", err?.message || err.toString()),
);
}
export async function openLogsDir() {
return invoke<void>("open_logs_dir").catch((err) =>
showNotice('error', err?.message || err.toString()),
showNotice("error", err?.message || err.toString()),
);
}
@@ -165,7 +165,7 @@ export const openWebUrl = async (url: string) => {
try {
await invoke("open_web_url", { url });
} catch (err: any) {
showNotice('error', err.toString());
showNotice("error", err.toString());
}
};
@@ -218,7 +218,7 @@ export async function cmdTestDelay(url: string) {
export async function invoke_uwp_tool() {
return invoke<void>("invoke_uwp_tool").catch((err) =>
showNotice('error', err?.message || err.toString(), 1500),
showNotice("error", err?.message || err.toString(), 1500),
);
}
@@ -347,6 +347,15 @@ export const repairService = async () => {
return invoke<void>("repair_service");
};
// 系统服务是否可用
export const isServiceAvailable = async () => {
try {
return await invoke<boolean>("is_service_available");
} catch (error) {
console.error("Service check failed:", error);
return false;
}
};
export const entry_lightweight_mode = async () => {
return invoke<void>("entry_lightweight_mode");
};