refactor: extract service installation logic to custom hook and optimize related component handling

This commit is contained in:
wonfen
2025-05-17 19:09:50 +08:00
parent 7556758284
commit e1d6c74e4f
19 changed files with 129 additions and 126 deletions

View File

@@ -11,7 +11,9 @@ import {
import { useVerge } from "@/hooks/use-verge";
import { EnhancedCard } from "./enhanced-card";
import useSWR from "swr";
import { getSystemInfo, installService, restartApp } from "@/services/cmds";
import {
getSystemInfo,
} from "@/services/cmds";
import { useNavigate } from "react-router-dom";
import { version as appVersion } from "@root/package.json";
import { useCallback, useEffect, useMemo, useState } from "react";
@@ -19,12 +21,14 @@ import { check as checkUpdate } from "@tauri-apps/plugin-updater";
import { useLockFn } from "ahooks";
import { showNotice } from "@/services/noticeService";
import { useSystemState } from "@/hooks/use-system-state";
import { useServiceInstaller } from "@/hooks/useServiceInstaller";
export const SystemInfoCard = () => {
const { t } = useTranslation();
const { verge, patchVerge } = useVerge();
const navigate = useNavigate();
const { isAdminMode, isSidecarMode, mutateRunningMode } = useSystemState();
const { installServiceAndRestartCore } = useServiceInstaller();
// 系统信息状态
const [systemState, setSystemState] = useState({
@@ -34,15 +38,13 @@ const [systemState, setSystemState] = useState({
// 初始化系统信息
useEffect(() => {
// 获取系统信息
getSystemInfo()
.then((info) => {
const lines = info.split("\n");
if (lines.length > 0) {
const sysName = lines[0].split(": ")[1] || "";
let sysVersion = lines[1].split(": ")[1] || "";
// 处理sysVersion前缀与sysName相同的情况
if (sysName && sysVersion.toLowerCase().startsWith(sysName.toLowerCase())) {
sysVersion = sysVersion.substring(sysName.length).trim();
}
@@ -120,26 +122,13 @@ useEffect(() => {
}
}, [verge, patchVerge]);
// 安装系统服务
const onInstallService = useLockFn(async () => {
try {
showNotice('info', t("Installing Service..."), 1000);
await installService();
showNotice('success', t("Service Installed Successfully"), 2000);
await mutateRunningMode();
} catch (err: any) {
showNotice('error', err.message || err.toString(), 3000);
}
});
// 点击运行模式处理,Sidecar或纯管理员模式允许安装服务
const handleRunningModeClick = useCallback(() => {
if (isSidecarMode || (isAdminMode && isSidecarMode)) {
onInstallService();
installServiceAndRestartCore();
}
}, [isSidecarMode, isAdminMode, onInstallService]);
}, [isSidecarMode, isAdminMode, installServiceAndRestartCore]);
// 检查更新
const onCheckUpdate = useLockFn(async () => {

View File

@@ -66,7 +66,7 @@ export const ClashCoreViewer = forwardRef<DialogRef>((props, ref) => {
const onRestart = useLockFn(async () => {
try {
await restartCore();
showNotice('success', t(`Clash Core Restarted`), 1000);
showNotice('success', t(`Clash Core Restarted`));
} catch (err: any) {
showNotice('error', err.message || err.toString());
}
@@ -77,7 +77,7 @@ export const ClashCoreViewer = forwardRef<DialogRef>((props, ref) => {
setUpgrading(true);
await upgradeCore();
setUpgrading(false);
showNotice('success', t(`Core Version Updated`), 1000);
showNotice('success', t(`Core Version Updated`));
} catch (err: any) {
setUpgrading(false);
showNotice('error', err.response?.data?.message || err.toString());

View File

@@ -2,7 +2,7 @@ import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
import { useTranslation } from "react-i18next";
import { BaseDialog, DialogRef } from "@/components/base";
import { getNetworkInterfacesInfo } from "@/services/cmds";
import { alpha, Box, Button, Chip, IconButton } from "@mui/material";
import { alpha, Box, Button, IconButton } from "@mui/material";
import { ContentCopyRounded } from "@mui/icons-material";
import { writeText } from "@tauri-apps/plugin-clipboard-manager";
import { showNotice } from "@/services/noticeService";

View File

@@ -30,6 +30,7 @@ import { Button, Tooltip } from "@mui/material";
import { useSystemState } from "@/hooks/use-system-state";
import { closeAllConnections } from "@/services/api";
import { showNotice } from "@/services/noticeService";
import { useServiceInstaller } from "@/hooks/useServiceInstaller";
interface Props {
onError?: (err: Error) => void;
@@ -39,35 +40,21 @@ const SettingSystem = ({ onError }: Props) => {
const { t } = useTranslation();
const { verge, mutateVerge, patchVerge } = useVerge();
const { installServiceAndRestartCore } = useServiceInstaller();
const { data: sysproxy } = useSWR("getSystemProxy", getSystemProxy);
const { data: autoproxy } = useSWR("getAutotemProxy", getAutotemProxy);
const { data: serviceOk, mutate: mutateServiceAvailable } = useSWR(
"isServiceAvailable",
isServiceAvailable
);
const { isAdminMode, isSidecarMode, mutateRunningMode } = useSystemState();
// 添加本地服务状态
const [localServiceOk, setLocalServiceOk] = useState(false);
// 更新本地服务状态
const updateLocalStatus = async () => {
try {
const serviceStatus = await isServiceAvailable();
setLocalServiceOk(serviceStatus);
mutate("isServiceAvailable", serviceStatus, false);
} catch (error) {
console.error("更新TUN状态失败:", error);
}
};
// 组件挂载时更新状态
useEffect(() => {
updateLocalStatus();
}, []);
// 判断Tun模式是否可用 - 当处于服务模式或管理员模式时可用
const isTunAvailable = localServiceOk || isAdminMode;
console.log("is tun isTunAvailable:", isTunAvailable);
// +++ isTunAvailable 现在使用 SWR 的 serviceOk
const isTunAvailable = serviceOk || isAdminMode;
const sysproxyRef = useRef<DialogRef>(null);
const tunRef = useRef<DialogRef>(null);
@@ -107,22 +94,22 @@ const SettingSystem = ({ onError }: Props) => {
}
) => {
try {
showNotice("info", t(beforeMsg));
showNotice("info", beforeMsg);
await stopCore();
showNotice("info", t(actionMsg));
showNotice("info", actionMsg);
await action();
showNotice("success", t(successMsg));
showNotice("success", successMsg);
showNotice("info", t("Restarting Core..."));
await restartCore();
await mutateRunningMode();
await updateLocalStatus();
await mutateServiceAvailable();
} catch (err: any) {
showNotice("error", err.message || err.toString());
try {
showNotice("info", t("Try running core as Sidecar..."));
await restartCore();
await mutateRunningMode();
await updateLocalStatus();
await mutateServiceAvailable();
} catch (e: any) {
showNotice("error", e?.message || e?.toString());
}
@@ -130,15 +117,6 @@ const SettingSystem = ({ onError }: Props) => {
}
);
// 安装系统服务
const onInstallService = () =>
handleServiceOperation({
beforeMsg: t("Stopping Core..."),
action: installService,
actionMsg: t("Installing Service..."),
successMsg: t("Service Installed Successfully"),
});
// 卸载系统服务
const onUninstallService = () =>
handleServiceOperation({
@@ -167,21 +145,20 @@ const SettingSystem = ({ onError }: Props) => {
<WarningRounded sx={{ color: "warning.main", mr: 1 }} />
</Tooltip>
)}
{!localServiceOk && !isAdminMode && (
{!serviceOk && !isAdminMode && (
<Tooltip title={t("Install Service")}>
<Button
variant="outlined"
color="primary"
size="small"
onClick={onInstallService}
onClick={installServiceAndRestartCore}
sx={{ mr: 1, minWidth: "32px", p: "4px" }}
>
<BuildRounded fontSize="small" />
</Button>
</Tooltip>
)}
{
localServiceOk && (
{serviceOk && (
<Tooltip title={t("Uninstall Service")}>
<Button
// variant="outlined"
@@ -215,7 +192,7 @@ const SettingSystem = ({ onError }: Props) => {
return patchVerge({ enable_tun_mode: e });
}}
>
<Switch edge="end" disabled={!isTunAvailable} />
<Switch edge="end" disabled={!isTunAvailable} />
</GuardState>
</SettingItem>
<SettingItem

View File

@@ -31,6 +31,7 @@ import {
import { useLockFn } from "ahooks";
import { closeAllConnections } from "@/services/api";
import { showNotice } from "@/services/noticeService";
import { useServiceInstaller } from "@/hooks/useServiceInstaller";
interface ProxySwitchProps {
label?: string;
@@ -45,6 +46,7 @@ const ProxyControlSwitches = ({ label, onError }: ProxySwitchProps) => {
const { t } = useTranslation();
const { verge, mutateVerge, patchVerge } = useVerge();
const theme = useTheme();
const { installServiceAndRestartCore } = useServiceInstaller();
const { data: sysproxy } = useSWR("getSystemProxy", getSystemProxy);
const { data: autoproxy } = useSWR("getAutotemProxy", getAutotemProxy);
@@ -78,50 +80,7 @@ const ProxyControlSwitches = ({ label, onError }: ProxySwitchProps) => {
};
// 安装系统服务
const onInstallService = useLockFn(async () => {
try {
showNotice('info', t("Installing Service..."));
await installService();
showNotice('success', t("Service Installed Successfully"));
showNotice('info', t("Waiting for service to be ready..."));
let serviceReady = false;
for (let i = 0; i < 5; i++) {
try {
await new Promise(resolve => setTimeout(resolve, 1000));
const isAvailable = await isServiceAvailable();
if (isAvailable) {
serviceReady = true;
break;
}
showNotice('info', t("Service not ready, retrying..."));
} catch (error) {
console.error("检查服务状态失败:", error);
}
}
showNotice('info', t("Restarting Core..."));
await restartCore();
// 重新获取运行模式
await mutateRunningMode();
// 更新服务状态
const serviceStatus = await isServiceAvailable();
mutate("isServiceAvailable", serviceStatus, false);
if (serviceReady) {
showNotice('success', t("Service is ready and core restarted"));
} else {
showNotice('info', t("Service may not be fully ready"));
}
} catch (err: any) {
showNotice('error', err.message || err.toString());
}
});
const onInstallService = installServiceAndRestartCore;
return (
<Box>
@@ -248,12 +207,6 @@ const ProxyControlSwitches = ({ label, onError }: ProxySwitchProps) => {
>
{t("Tun Mode")}
</Typography>
{/* <Typography variant="caption" color="text.secondary">
{isSidecarMode
? t("TUN requires Service Mode or Admin Mode")
: t("For special applications")
}
</Typography> */}
</Box>
</Box>