import { useEffect } from "react"; import { useDispatch, useSelector } from "react-redux"; import { v4 as uuidv4 } from "uuid"; import { commands, ProxyNodeInfo } from "@/bindings"; import { app } from "@tauri-apps/api"; import { createCircuit } from "@/store/circuitSlice"; import { setServiceStatus, getProxy, getVersion } from "@/store/serviceSlice"; import { setNodes, setNodesError, clearNodes } from "@/store/nodesSlice"; import { setProxiesList1 } from "@/store/web3Slice"; // import { clearCircuitState } from '@/store/circuitSlice'; import { AppDispatch, RootState } from "@/store"; interface StartupCheckResult { success: boolean; error?: string; data?: ProxyNodeInfo[]; } // 重试函数:最多重试指定次数,每次等待指定时间 async function retry( operation: () => Promise, maxAttempts: number, delayMs: number, validate: (result: T) => boolean ): Promise { let lastError: Error | undefined; for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { const result = await operation(); if (validate(result)) { return result; } lastError = new Error(`Validation failed on attempt ${attempt}`); } catch (error) { lastError = error instanceof Error ? error : new Error(String(error)); } if (attempt < maxAttempts) { await new Promise((resolve) => setTimeout(resolve, delayMs)); } } throw lastError || new Error("Operation failed after all attempts"); } // 正常来说,windows下和linux下,使用包管理器更新时安装/卸载服务是足够的,只有macOS下依赖启动检查来安装/卸载服务 // !FIXME:实现一个更好的安装/卸载服务的逻辑,当前中间只是简单的等待5秒,因为没有合适的方法判断卸载是否完成 async function checkAndInstallService(): Promise { try { // 获取当前服务版本和期望版本 const versionResult = await commands.getServiceVersion(); const expectedVersion = await app.getVersion(); // 需要安装/重装的两种情况,分别是 // 1. 服务不存在 // 2. 服务存在但版本不匹配 const serviceNotExists = versionResult.status === "error"; const versionMismatch = !serviceNotExists && versionResult.data !== expectedVersion; if (serviceNotExists) { console.log("Service not found, installing..."); const installResult = await commands.installService(); if (installResult.status === "error") { return { success: false, error: "Failed to install service", }; } } else if (versionMismatch) { console.log("Service version mismatch, uninstalling old service..."); const uninstallResult = await commands.uninstallService(); if (uninstallResult.status === "error") { return { success: false, error: "Failed to uninstall old service", }; } await new Promise((resolve) => setTimeout(resolve, 5000)); console.log("Installing new service..."); const installResult = await commands.installService(); if (installResult.status === "error") { return { success: false, error: "Failed to install service", }; } } // 如果进行了安装操作,验证安装结果 if (serviceNotExists || versionMismatch) { // 等待并验证服务安装结果 // 最多等待10秒,每秒检查一次 try { await retry( () => commands.getServiceVersion(), 10, 1000, (result) => result.status === "ok" && result.data === expectedVersion ); } catch (error) { return { success: false, error: "Service installation verification failed after retries", }; } } return { success: true }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : "Unknown error during service check", }; } } async function checkAndStartCore(): Promise { try { // 检查核心状态 let coreStatus = await commands.getNodes(); // 如果核心未运行,尝试启动 if (coreStatus.status === "error") { console.log("Starting core..."); const startResult = await commands.restartCore(); if (startResult.status === "error") { return { success: false, error: "Failed to start core", }; } // 等待并验证核心是否成功启动 // 最多等待5秒,每500ms检查一次 try { coreStatus = await retry( () => commands.getNodes(), 10, 500, (result) => result.status === "ok" ); } catch (error) { return { success: false, error: "Core start verification failed after retries", }; } } return { success: true, data: coreStatus.status === "ok" ? coreStatus.data : undefined, }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : "Unknown error during core check", }; } } export function useStartupCheck() { const dispatch: AppDispatch = useDispatch(); const { fallbackCircuit } = useSelector( (state: RootState) => state.circuitReducer ); // 检查服务和核心状态,同时更新节点信息 const checkStatus = async () => { try { const [versionResult, nodesResult] = await Promise.all([ commands.getServiceVersion(), commands.getNodes(), ]); const suitableServiceVersion = await app.getVersion(); const isServiceInstalled = versionResult.status === "ok" && versionResult.data === suitableServiceVersion; const isCoreRunning = nodesResult.status === "ok"; // 更新服务状态 dispatch( setServiceStatus({ isServiceInstalled, isCoreRunning, }) ); // 更新节点信息 // 只有当核心正在运行时才更新节点 if (isCoreRunning) { if (nodesResult.status === "ok") { const proxies:any[] = []; nodesResult.data.forEach((node,index) => { const { country_code } = node if(nodesResult.data.length-1 === index){ return } proxies.push({ country_code: country_code,ingress_country_code: nodesResult.data[index + 1].country_code }) }) // console.log(proxies,'proxiesproxiesproxies') dispatch(setProxiesList1(proxies)) dispatch(setNodes(nodesResult.data)); } else { dispatch(setNodesError("Failed to fetch nodes")); } } else { dispatch(clearNodes()); // dispatch(clearCircuitState()); // 当核心未运行时清空链路状态 } } catch (error) { console.error("Status check failed:", error); dispatch( setServiceStatus({ isServiceInstalled: false, isCoreRunning: false, }) ); dispatch(clearNodes()); } }; useEffect(() => { async function performStartupCheck() { try { // 步骤1:检查并安装服务 const serviceResult = await checkAndInstallService(); if (!serviceResult.success) { console.error("Service check failed:", serviceResult.error); await dispatch( setServiceStatus({ isServiceInstalled: false, isCoreRunning: false, }) ); await dispatch(clearNodes()); return; } // 步骤2:检查并启动核心 const coreResult = await checkAndStartCore(); if (!coreResult.success) { console.error("Core check failed:", coreResult.error); await dispatch( setServiceStatus({ isServiceInstalled: true, isCoreRunning: false, }) ); await dispatch(clearNodes()); return; } // 步骤3:检查当前核心版本 await dispatch(getVersion()); // 步骤4:检查当前是否开启了代理 await dispatch(getProxy()); // 步骤5:检查当前是否有默认链路并且保证状态是正常,否则重新创建一个默认链路 if (!fallbackCircuit || fallbackCircuit?.state === "failed") { let inbound = ""; let outbound = ""; if (coreResult && coreResult.data && coreResult.data.length > 0) { inbound = coreResult.data[0].country_code || ""; outbound = coreResult.data .filter((item) => item.exit && item.country_code !== inbound) ?.slice(-1)?.[0].country_code || ""; // 如果没有这两个那么就跳过,证明核心运行了但是节点是空的,如果只有其中一个,那么证明总共节点就一个无法创建链路 if (inbound && outbound) { await dispatch( createCircuit({ uid: uuidv4(), name: "系统默认链路", inbound: inbound, outbound: outbound, multi_hop: 3, fallback: true, rule_path: null, is_prefix: false, }) ).unwrap(); } } } // // 执行一次完整的状态检查 await checkStatus(); } catch (error) { console.error("Startup check failed:", error); dispatch( setServiceStatus({ isServiceInstalled: false, isCoreRunning: false, }) ); dispatch(clearNodes()); } } // 执行启动自检 performStartupCheck(); // 每5秒检查一次状态 const intervalId = setInterval(checkStatus, 5000); return () => clearInterval(intervalId); }, []); }