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
下一代希沃管家注入式修改方案
@@ -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。开发者将在能力 / 时间限度内尽可能处理。
-

## ✨ 概览
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, 不运行闭包逻辑