From 7afeb39275eb27aa6455cb3ff518d1fa05d6428b Mon Sep 17 00:00:00 2001 From: Minoricew <154642983+Minoricew@users.noreply.github.com> Date: Mon, 17 Nov 2025 00:36:23 +0800 Subject: [PATCH] =?UTF-8?q?[=E2=9A=A1=EF=B8=8F=20BREAKING=20/=20Feat]=20Bu?= =?UTF-8?q?mp=20version=20to=20v0.2.0-RC1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - [+] 完成了下载 & 安装 Aikari 的步骤 - [*] 修复了部分状态管理错误, 但没修全 --- README.md | 14 +- package.json | 2 +- .../init/main/ipcModules/aikariIpcHandler.js | 115 ++++++-- src/aura/ui/composables/rawCmdExec/fs.js | 32 +-- .../behaviourCtrl/aikariStatus.js | 248 ++++++++++++------ src/core/hook.js | 2 +- src/core/preload.js | 2 +- 7 files changed, 288 insertions(+), 127 deletions(-) diff --git a/README.md b/README.md index db213e4..5a9d5a7 100755 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@

HugoAura

下一代希沃管家注入式修改方案

- 首页 · 关于 · 文档 · 反馈 · 社区 + 首页 · 关于 (WIP) · 文档 (WIP) · 反馈 · 社区

@@ -14,18 +14,6 @@ > [!IMPORTANT] > 已经过测试的希沃管家版本: v1.5.5.3878 -> [!CAUTION] -> 由于作者高三学业繁忙, 项目正处于缓慢更新阶段。 -> -> 作者将尽可能抽出时间维护项目, 但新功能的实现速度将大幅降低。 - -> [!WARNING] -> 我们正在使用 C++ 重构 PLS, 新的子项目代号为 [Aikari](https://github.com/HugoAura/HugoAura-Aikari)。其将集成 MQTT 消息中转、HugoAura 自动更新、特权操作辅助等功能。 -> -> 在 Aikari 的首个 Alpha 版本发布前, HugoAura 主项目与 [PLS](https://github.com/HugoAura/HugoAura-PLS) 的新功能更新频率将减弱。 -> -> 您依然可以提出 Feature Request 或 Bug Report。开发者将在能力 / 时间限度内尽可能处理。 - ![Repobeats](https://repobeats.axiom.co/api/embed/69b5be5daacef624b8f5e4b8966a0b5898439a22.svg "Repobeats analytics image") ## ✨ 概览 diff --git a/package.json b/package.json index 6a74fcf..c30d1b8 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "HugoAura", - "version": "0.1.1-beta-patch-1", + "version": "0.2.0-rc1", "description": "Aura for SeewoHugo", "main": "app.asar/main.js", "dependencies": {}, diff --git a/src/aura/init/main/ipcModules/aikariIpcHandler.js b/src/aura/init/main/ipcModules/aikariIpcHandler.js index cb016b3..01ffa29 100644 --- a/src/aura/init/main/ipcModules/aikariIpcHandler.js +++ b/src/aura/init/main/ipcModules/aikariIpcHandler.js @@ -68,7 +68,7 @@ const functions = { * @param {(arg: DownloadTask) => any} callbackFn * @param {string} binPath */ - handleAikariDownload: async (channel, callbackFn, binPath) => { + handleAikariDlAndInstall: async (channel, callbackFn, binPath) => { // TODO: Channel selection const apiInfo = global.__HUGO_AURA_API__; @@ -167,7 +167,8 @@ const functions = { status: "failed", dlUrl: null, savePath: null, - message: "未能获取 Aikari 版本信息, 所有 API 域名均无法连接", + message: + "未能获取 Aikari 版本信息, 所有 API 域名均无法连接, 建议前往 GitHub 下载安装包并自行安装", }); return false; } @@ -187,25 +188,85 @@ const functions = { status: "failed", dlUrl: null, savePath: null, - message: `处理器架构识别失败, 检测到的架构: ${deviceArch}`, + message: `不支持的处理器架构, 检测到的架构: "${deviceArch}"`, }); return false; } - fsComposables.downloadFile( - aikariVersionInfo.data.downloadUrl[deviceArch], - binPath, - (...args) => { - if (args[0].status === "done") { - if (global.__HUGO_AURA__.aikariStats) { - global.__HUGO_AURA__.aikariStats.installed = true; - global.__HUGO_AURA__.aikariStats.status = "dead"; + const downloadFilePromise = new Promise((resolve) => { + fsComposables.downloadFile( + aikariVersionInfo.data.downloadUrl[deviceArch], + binPath, + (...args) => { + if (args[0].status === "done") { + resolve(true); + } else if (args[0].status === "failed") { + resolve(false); } - } - callbackFn(...args); + callbackFn(...args); + } + ); + }); + + const dlResult = await downloadFilePromise; + + if (dlResult) { + callbackFn({ + id: "INSTALL_STAGE", + progress: 5, + status: "waiting", + dlUrl: null, + savePath: null, + message: "准备运行 Aikari 安装程序...", + }); + + const runInstPromise = new Promise((resolve) => { + exec( + `"${binPath}" /VERYSILENT /SUPPRESSMSGBOXES /LOG="${binPath}\\..\\Aikari-Install.log"`, + (err, stdout, stderr) => { + if (err) { + console.error( + `[HugoAura / Main / Aikari IPC Handler / Install Aikari] Error running installer: ${stderr}` + ); + resolve({ success: false }); + } + resolve({ success: true }); + } + ); + }); + + callbackFn({ + id: "INSTALL_STAGE", + progress: 15, + status: "progressing", + dlUrl: null, + savePath: null, + message: "正在安装 Aikari...", + }); + + const instResult = await runInstPromise; + + callbackFn({ + id: "INSTALL_STAGE", + progress: 100, + status: instResult.success ? "done" : "failed", + dlUrl: null, + savePath: null, + message: instResult.success + ? "Aikari 安装成功" + : "安装失败, 请检查 %TEMP%/Aikari-Install-Temp 下的安装日志", + }); + + if (instResult.success) { + if (global.__HUGO_AURA__.aikariStats) { + global.__HUGO_AURA__.aikariStats.installed = true; + global.__HUGO_AURA__.aikariStats.status = "dead"; + } } - ); + + fs.unlinkSync(binPath); + } }, }; @@ -231,6 +292,15 @@ const applyAikariIpcHandler = (ipcMain) => { ); const AIKARI_SVC_NAME = "HugoAuraAikari"; + const AIKARI_TEMP_DL_DIR = path.join( + require("os").tmpdir(), + "Aikari-Install-Temp" + ); + const AIKARI_TEMP_INSTALLER_FILENAME = path.join( + AIKARI_TEMP_DL_DIR, + "Aikari-Installer.exe" + ); + const isAikariDetached = process.argv.includes("--aikari-detach"); global.__HUGO_AURA__.aikariStats = { @@ -569,12 +639,21 @@ const applyAikariIpcHandler = (ipcMain) => { * * @param {import("electron").IpcMainInvokeEvent} _evt * @param {{channel?: "stable" | "alpha", reportTo?: import("../../../types/main/core").WindowName}} arg - * @returns {void} + * @returns {Promise} */ - (_evt, arg) => { + async (_evt, arg) => { + if (fs.existsSync(AIKARI_TEMP_DL_DIR)) { + try { + fs.unlinkSync(AIKARI_TEMP_DL_DIR); + } catch (err) { + console.error(err); + } + } else { + fs.mkdirSync(AIKARI_TEMP_DL_DIR); + } const channel = arg.channel ? arg.channel : "stable"; const reportWin = arg.reportTo ? arg.reportTo : "assistant"; - functions.handleAikariDownload( + functions.handleAikariDlAndInstall( channel, (status) => { ipcMain.send( @@ -583,7 +662,7 @@ const applyAikariIpcHandler = (ipcMain) => { status ); }, - AIKARI_LAUNCHER_PATH + AIKARI_TEMP_INSTALLER_FILENAME ); } ); diff --git a/src/aura/ui/composables/rawCmdExec/fs.js b/src/aura/ui/composables/rawCmdExec/fs.js index 7cf3a80..72336e1 100644 --- a/src/aura/ui/composables/rawCmdExec/fs.js +++ b/src/aura/ui/composables/rawCmdExec/fs.js @@ -3,23 +3,23 @@ const childProc = require("child_process"); const fileSystemRawCmds = { getDiskCaptions: async () => { const waitForCmd = new Promise((resolve) => { - childProc.exec( - "wmic logicaldisk get caption", - (error, stdout, stderr) => { - if (error) { - console.error( - `[HugoAura / UI / Composables / Raw CMD / FS] Failed to exec wmic getCaption: ${error}` - ); - resolve([]); - } - const drives = stdout - .trim() - .split("\r\n") - .slice(1) - .map((line) => line.trim()); - resolve(drives); + childProc.exec("fsutil fsinfo drives", (error, stdout, stderr) => { + if (error) { + console.error( + `[HugoAura / UI / Composables / Raw CMD / FS] Failed to exec fsutil getCaption: ${error}` + ); + resolve([]); } - ); + const finResult = []; + stdout + .trim() + .split(": ")[1] + .split(":\\") + .forEach((line) => { + if (line !== "") finResult.push(line.trim() + ":"); + }); + resolve(finResult); + }); }); return waitForCmd; }, diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/aikariStatus.js b/src/aura/ui/pages/configSubPages/behaviourCtrl/aikariStatus.js index aa970fb..59c0f30 100644 --- a/src/aura/ui/pages/configSubPages/behaviourCtrl/aikariStatus.js +++ b/src/aura/ui/pages/configSubPages/behaviourCtrl/aikariStatus.js @@ -284,6 +284,8 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) false, null ); + const isHostNotInit = + await global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.showWarnToastIfHostsNotInitialized(); const ret = await ipcRenderer.invoke( `${IPC_METHOD_BASE}.aikariLifecycleControl`, { target: "startSvc" } @@ -291,14 +293,16 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) if (ret.success) { lifecycleStatus.svcRunning = true; global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateStatusContent(); - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( - "success", - "Aikari 已启动", - null, - true, - true, - 2000 - ); + if (!isHostNotInit) { + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( + "success", + "Aikari 已启动", + null, + true, + true, + 2000 + ); + } await global.__HUGO_AURA_GLOBAL__.utils.sleep(100); await ipcRenderer.invoke( `${IPC_METHOD_BASE}.retryAikariConnect` @@ -396,7 +400,12 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) GLOBAL_FUNCTIONS.updateOperationBtnStatus("Start", true); GLOBAL_FUNCTIONS.updateOperationBtnStatus("Stop", true); } else { - updateStatusEl(acIdInst, atIdInst, "SUCCESS", "已安装"); + updateStatusEl( + acIdInst, + atIdInst, + "SUCCESS", + "应用已安装, 服务已安装" + ); GLOBAL_FUNCTIONS.updateOperationBtnStatus("InstallSvc", true); GLOBAL_FUNCTIONS.updateOperationBtnStatus( "UninstallSvc", @@ -465,6 +474,30 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) } }, + showWarnToastIfHostsNotInitialized: async () => { + const dnsModule = require("dns"); + const lookupPromise = new Promise((resolve) => { + dnsModule.lookup("iot-broker-mis.seewo.com", (err, result) => { + resolve(err ? err : result); + }); + }); + const result = await lookupPromise; + if (result) { + if (!result.startsWith("127.")) { + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( + "error", + "警告: 页面即将刷新", + `

您似乎是首次运行 Aikari, 基于 Aikari PLS 模块的实现原理, 我们需要修改 Hosts 文件并重启 SeewoCore 进程以开始拦截流量。

+

重启 SeewoCore 进程会导致管家前端页面在重启完成后自动发生刷新, 因此稍后请留意此变更。

`, + true, + false, + null + ); + return true; + } + } + }, + refreshAikariStatus: async (init = false) => { const isDetachedRet = await ipcRenderer.invoke( `${IPC_METHOD_BASE}.aikariLifecycleQuery`, @@ -636,7 +669,7 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) } }, - downloadAikariBin: async (retrieveMode = false) => { + downloadAndInstallAikariBin: async (retrieveMode = false) => { const GLOBAL_FUNCTIONS = global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus; const CUR_CHANNEL = `${IPC_METHOD_BASE}.post.reportAikariInstallStep`; @@ -671,25 +704,50 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) const callbackFn = (_evt, info) => { switch (info.status) { case "failed": - GLOBAL_FUNCTIONS.updateToast( - "error", - "下载失败", - `

${ - info.message ? info.message : "检查日志以获取错误信息" - }

- ${info.errorObj ? info.errorObj : ""} -

`, - true, - true, - 5000 - ); + if (info.id !== "INSTALL_STAGE") { + GLOBAL_FUNCTIONS.updateToast( + "error", + "下载失败", + `

${ + info.message ? info.message : "检查日志以获取错误信息" + }

+ ${info.errorObj ? info.errorObj : ""} +

`, + true, + true, + 5000 + ); + + GLOBAL_FUNCTIONS.updatePBarStatus( + 100, + "下载时发生错误", + "danger", + false + ); + } else { + GLOBAL_FUNCTIONS.updateToast( + "error", + "安装失败", + `

${ + info.message + ? info.message + : "检查 HugoAura 日志或安装器日志 (%TEMP%/Aikari-Install-Temp) 以获取错误信息" + }

+ ${info.errorObj ? info.errorObj : ""} +

`, + true, + true, + 15000 + ); + + GLOBAL_FUNCTIONS.updatePBarStatus( + 100, + `发生错误: ${info.message}`, + "danger", + false + ); + } - GLOBAL_FUNCTIONS.updatePBarStatus( - 100, - "下载时发生错误", - "danger", - false - ); setTimeout(() => { GLOBAL_FUNCTIONS.switchPBarShowStatus(false); }, 1000); @@ -703,66 +761,102 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) ); break; case "done": - GLOBAL_FUNCTIONS.updateToast( - "success", - "下载成功", - null, - true, - true, - 2500 - ); + if (info.id !== "INSTALL_STAGE") { + GLOBAL_FUNCTIONS.updateToast( + "success", + "下载成功", + null, + true, + true, + 2500 + ); - GLOBAL_FUNCTIONS.updatePBarStatus( - 100, - "下载成功", - "success", - false - ); - setTimeout(() => { - GLOBAL_FUNCTIONS.switchPBarShowStatus(false); - }, 1000); + GLOBAL_FUNCTIONS.updatePBarStatus( + 100, + "下载成功", + "success", + false + ); + break; + } else { + GLOBAL_FUNCTIONS.updateToast( + "success", + "安装成功", + null, + true, + true, + 2500 + ); - ipcRenderer.off(CUR_CHANNEL, callbackFn); - GLOBAL_FUNCTIONS.updateOperationBtnStatus("Refresh", false); - GLOBAL_FUNCTIONS.updateOperationBtnStatus( - "Install", - true, - "下载应用" - ); - lifecycleStatus.installed = true; - global.__HUGO_AURA__.aikariStats.installed = true; - ipcRenderer.invoke( - `${IPC_METHOD_BASE}.updateAikariStatus`, - global.__HUGO_AURA__.aikariStats - ); - GLOBAL_FUNCTIONS.updateStatusContent(); - break; + GLOBAL_FUNCTIONS.updatePBarStatus( + 100, + "Aikari 安装成功", + "success", + false + ); + + setTimeout(() => { + GLOBAL_FUNCTIONS.switchPBarShowStatus(false); + }, 1000); + + ipcRenderer.off(CUR_CHANNEL, callbackFn); + GLOBAL_FUNCTIONS.updateOperationBtnStatus("Refresh", false); + GLOBAL_FUNCTIONS.updateOperationBtnStatus( + "Install", + true, + "下载应用" + ); + lifecycleStatus.installed = true; + global.__HUGO_AURA__.aikariStats.installed = true; + setTimeout(() => { + ipcRenderer.invoke( + `${IPC_METHOD_BASE}.updateAikariStatus`, + global.__HUGO_AURA__.aikariStats + ); + GLOBAL_FUNCTIONS.updateStatusContent(); + }, 500); + break; + } case "waiting": - GLOBAL_FUNCTIONS.updatePBarStatus(0, "正在连接", "normal"); + GLOBAL_FUNCTIONS.updatePBarStatus( + 0, + info.message ? info.message : "正在连接", + "normal" + ); if ( - !global.__HUGO_AURA_UI_REACTIVES__.subConfig.aikariStatus + (!global.__HUGO_AURA_UI_REACTIVES__.subConfig.aikariStatus .curDlTaskId || - global.__HUGO_AURA_UI_REACTIVES__.subConfig.aikariStatus - .curDlTaskId !== info.id + global.__HUGO_AURA_UI_REACTIVES__.subConfig.aikariStatus + .curDlTaskId !== info.id) && + info.id !== "INSTALL_STAGE" ) { global.__HUGO_AURA_UI_REACTIVES__.subConfig.aikariStatus.curDlTaskId = info.id; } break; case "progressing": - const roundProgress = Math.round(info.progress); - GLOBAL_FUNCTIONS.updatePBarStatus( - roundProgress, - `正在下载中... ${roundProgress}% (${( - info.curBytes / - 1024 / - 1024 - ).toFixed(2)}MB / ${(info.totalBytes / 1024 / 1024).toFixed( - 2 - )}MB)`, // POWERED BY PRETTIER - "normal", - true - ); + if (info.id !== "INSTALL_STAGE") { + const roundProgress = Math.round(info.progress); + GLOBAL_FUNCTIONS.updatePBarStatus( + roundProgress, + `正在下载中... ${roundProgress}% (${( + info.curBytes / + 1024 / + 1024 + ).toFixed(2)}MB / ${(info.totalBytes / 1024 / 1024).toFixed( + 2 + )}MB)`, // POWERED BY PRETTIER + "normal", + true + ); + } else { + GLOBAL_FUNCTIONS.updatePBarStatus( + info.progress, + `正在安装 Aikari...`, + "normal", + false + ); + } break; case "struggling": GLOBAL_FUNCTIONS.updatePBarStatus(100, info.message, "warning"); diff --git a/src/core/hook.js b/src/core/hook.js index 32206e4..a2484e0 100755 --- a/src/core/hook.js +++ b/src/core/hook.js @@ -27,7 +27,7 @@ if (!global.__HUGO_AURA_API__) { "https://api-aura-projekts.minorice.moe", "https://api.aura.vim.moe", ], - aikariUpdate: "/api/getPLSLatestVersion", + aikariUpdate: "/api/getAikariLatestVersion", auraUpdate: "/api/getAuraLatestVersion", }; global.__HUGO_AURA_API__ = __HUGO_AURA_API__; diff --git a/src/core/preload.js b/src/core/preload.js index 3ba7e28..a6a420c 100755 --- a/src/core/preload.js +++ b/src/core/preload.js @@ -1,6 +1,6 @@ // @ts-check -const __AURA_VERSION__ = "0.1.1-beta-patch-1"; +const __AURA_VERSION__ = "0.2.0-rc1"; (() => { if (require.main) return; // 如果只是导入 Aura Version, 不运行闭包逻辑