From 08290301a387e434b7a0ee6986351e356b2c5b24 Mon Sep 17 00:00:00 2001 From: Minoricew <154642983+Minoricew@users.noreply.github.com> Date: Fri, 14 Nov 2025 02:58:09 +0800 Subject: [PATCH] =?UTF-8?q?[=F0=9F=94=84=20Chore]=20Prepare=20for=20Aikari?= =?UTF-8?q?=20(1/2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. [/] 一些无意义的重命名工作 2. [*] 修改了 WebSocket 对接逻辑 --- .github/workflows/pack.yml | 2 - .gitignore | 1 + src/aura/init/main/ipcHandler.js | 4 +- .../{plsIpcHandler.js => aikariIpcHandler.js} | 229 +++++------ src/aura/types/render/global.d.ts | 4 +- .../types/shared/{pls => aikari}/status.d.ts | 17 +- .../shared/{pls => aikari}/websocket.d.ts | 7 +- src/aura/types/shared/global.d.ts | 12 +- src/aura/ui/aikari/onConnectedSeq.js | 80 ++++ src/aura/ui/{pls => aikari}/pushHandler.js | 2 +- src/aura/ui/aikari/routes/basic.js | 49 +++ src/aura/ui/{pls => aikari}/routes/config.js | 8 +- .../ui/composables/aikariConfigManager.js | 83 ++++ src/aura/ui/composables/plsConfigManager.js | 81 ---- src/aura/ui/composables/settingsRenderer.js | 64 ++- src/aura/ui/hookDefinitions/assistant.js | 10 +- src/aura/ui/js/aikariConnectionManager.js | 372 ++++++++++++++++++ .../js/{plsListener.js => aikariListener.js} | 28 +- src/aura/ui/js/plsConnectionManager.js | 357 ----------------- src/aura/ui/pages/config/config.html | 10 +- src/aura/ui/pages/config/config.js | 2 +- .../{plsStatus.css => aikariStatus.css} | 52 +-- .../{plsStatus.html => aikariStatus.html} | 41 +- .../{plsStatus.js => aikariStatus.js} | 262 ++++++------ .../behaviourCtrl/behaviourCtrl.js | 12 +- .../behaviourCtrl/settings/basic.js | 52 +-- .../behaviourCtrl/settings/deviceSecurity.js | 34 +- .../freezeOverridePreview.js | 5 +- .../pages/windows/auraWsKeepAlive/index.html | 2 +- src/aura/ui/pls/routes/basic.js | 48 --- src/aura/ui/static/aikari_color_reversed.png | Bin 0 -> 39590 bytes src/aura/ui/static/aura_pls.png | Bin 21320 -> 0 bytes src/core/hook.js | 2 +- 33 files changed, 1006 insertions(+), 926 deletions(-) rename src/aura/init/main/ipcModules/{plsIpcHandler.js => aikariIpcHandler.js} (65%) mode change 100755 => 100644 rename src/aura/types/shared/{pls => aikari}/status.d.ts (52%) mode change 100755 => 100644 rename src/aura/types/shared/{pls => aikari}/websocket.d.ts (64%) mode change 100755 => 100644 create mode 100644 src/aura/ui/aikari/onConnectedSeq.js rename src/aura/ui/{pls => aikari}/pushHandler.js (89%) mode change 100755 => 100644 create mode 100644 src/aura/ui/aikari/routes/basic.js rename src/aura/ui/{pls => aikari}/routes/config.js (69%) mode change 100755 => 100644 create mode 100644 src/aura/ui/composables/aikariConfigManager.js delete mode 100755 src/aura/ui/composables/plsConfigManager.js create mode 100644 src/aura/ui/js/aikariConnectionManager.js rename src/aura/ui/js/{plsListener.js => aikariListener.js} (71%) mode change 100755 => 100644 delete mode 100755 src/aura/ui/js/plsConnectionManager.js rename src/aura/ui/pages/configSubPages/behaviourCtrl/{plsStatus.css => aikariStatus.css} (74%) mode change 100755 => 100644 rename src/aura/ui/pages/configSubPages/behaviourCtrl/{plsStatus.html => aikariStatus.html} (78%) mode change 100755 => 100644 rename src/aura/ui/pages/configSubPages/behaviourCtrl/{plsStatus.js => aikariStatus.js} (72%) mode change 100755 => 100644 delete mode 100755 src/aura/ui/pls/routes/basic.js create mode 100644 src/aura/ui/static/aikari_color_reversed.png delete mode 100755 src/aura/ui/static/aura_pls.png diff --git a/.github/workflows/pack.yml b/.github/workflows/pack.yml index 2421041..19a159b 100644 --- a/.github/workflows/pack.yml +++ b/.github/workflows/pack.yml @@ -1,8 +1,6 @@ name: Pack source code & Create CI/CD Release on: - schedule: - - cron: '0 5 * * *' push: branches: [dev, stable] pull_request: diff --git a/.gitignore b/.gitignore index c59f453..19cc5c9 100755 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ autoConfiguration.json # NPM Packages node_modules/ +package-lock.json # OS Files desktop.ini diff --git a/src/aura/init/main/ipcHandler.js b/src/aura/init/main/ipcHandler.js index 066ce4c..3699301 100755 --- a/src/aura/init/main/ipcHandler.js +++ b/src/aura/init/main/ipcHandler.js @@ -80,7 +80,7 @@ const buildIpcMain = (electron) => { const { applyDebugIpcHandler } = require("./ipcModules/debugIpcHandler"); const { applyConfigIpcHandler } = require("./ipcModules/configIpcHandler"); const { applyFsIpcHandler } = require("./ipcModules/fsIpcHandler"); - const { applyPlsIpcHandler } = require("./ipcModules/plsIpcHandler"); + const { applyAikariIpcHandler } = require("./ipcModules/aikariIpcHandler"); ipcMain.handle("$aura.base.restartApplication", async () => { app.relaunch(); @@ -91,7 +91,7 @@ const buildIpcMain = (electron) => { applyDebugIpcHandler(ipcMain); applyConfigIpcHandler(ipcMain); applyFsIpcHandler(ipcMain); - applyPlsIpcHandler(ipcMain); + applyAikariIpcHandler(ipcMain); }; module.exports = { buildIpcMain }; diff --git a/src/aura/init/main/ipcModules/plsIpcHandler.js b/src/aura/init/main/ipcModules/aikariIpcHandler.js old mode 100755 new mode 100644 similarity index 65% rename from src/aura/init/main/ipcModules/plsIpcHandler.js rename to src/aura/init/main/ipcModules/aikariIpcHandler.js index b6ed349..f8cf273 --- a/src/aura/init/main/ipcModules/plsIpcHandler.js +++ b/src/aura/init/main/ipcModules/aikariIpcHandler.js @@ -68,7 +68,7 @@ const functions = { * @param {(arg: DownloadTask) => any} callbackFn * @param {string} binPath */ - handlePLSDownload: async (channel, callbackFn, binPath) => { + handleAikariDownload: async (channel, callbackFn, binPath) => { // TODO: Channel selection const apiInfo = global.__HUGO_AURA_API__; @@ -78,7 +78,7 @@ const functions = { const reqPromise = new Promise((resolveHttpRequest) => { nodeHttps .get( - `${apiDomain}${apiInfo.plsUpdate}?channel=${channel}`, + `${apiDomain}${apiInfo.aikariUpdate}?channel=${channel}`, (rep) => { let dataChunk = ""; rep.on("data", (chunk) => { @@ -167,12 +167,12 @@ const functions = { status: "failed", dlUrl: null, savePath: null, - message: "未能获取 PLS 版本信息, 所有 API 域名均无法连接", + message: "未能获取 Aikari 版本信息, 所有 API 域名均无法连接", }); return false; } - const plsVersionInfo = rawResInfo.data; + const aikariVersionInfo = rawResInfo.data; let deviceArch = process.env.PROCESSOR_ARCHITEW6432 ? process.env.PROCESSOR_ARCHITEW6432 @@ -180,7 +180,7 @@ const functions = { // @ts-expect-error deviceArch = deviceArch.toLowerCase(); - if (!Object.keys(plsVersionInfo.data.downloadUrl).includes(deviceArch)) { + if (!Object.keys(aikariVersionInfo.data.downloadUrl).includes(deviceArch)) { callbackFn({ id: "", progress: 0, @@ -193,13 +193,13 @@ const functions = { } fsComposables.downloadFile( - plsVersionInfo.data.downloadUrl[deviceArch], + aikariVersionInfo.data.downloadUrl[deviceArch], binPath, (...args) => { if (args[0].status === "done") { - if (global.__HUGO_AURA__.plsStats) { - global.__HUGO_AURA__.plsStats.installed = true; - global.__HUGO_AURA__.plsStats.status = "dead"; + if (global.__HUGO_AURA__.aikariStats) { + global.__HUGO_AURA__.aikariStats.installed = true; + global.__HUGO_AURA__.aikariStats.status = "dead"; } } @@ -213,37 +213,43 @@ const functions = { * * @param {import("../../../types/main/electron").AuraIPCMain} ipcMain */ -const applyPlsIpcHandler = (ipcMain) => { - const methodBase = "$aura.pls"; +const applyAikariIpcHandler = (ipcMain) => { + const methodBase = "$aura.aikari"; - const PLS_INSTALL_DIR = path.join("C:\\Program Files", "HugoAura PLS", "bin"); - const PLS_BIN_PATH = path.join(PLS_INSTALL_DIR, "HugoAura-PLS.exe"); - const PLS_SVC_NAME = "HugoAuraPLS"; + const AIKARI_DEFAULT_INSTALL_DIR = path.join( + "C:\\Program Files", + "HugoAura Aikari" + ); + const AIKARI_LAUNCHER_PATH = path.join( + AIKARI_DEFAULT_INSTALL_DIR, + "Aikari-Launcher.exe" + ); + const AIKARI_SVC_NAME = "HugoAuraAikari"; - const isPlsDetached = process.argv.includes("--pls-detach"); + const isAikariDetached = process.argv.includes("--aikari-detach"); - global.__HUGO_AURA__.plsStats = { + global.__HUGO_AURA__.aikariStats = { installed: false, launched: false, - detached: isPlsDetached, + detached: isAikariDetached, connected: false, version: "unknown", status: "dead", - authToken: global.__HUGO_AURA_CONFIG__.plsToken, + authToken: global.__HUGO_AURA_CONFIG__.aikariToken, }; ipcMain.handle( - `${methodBase}.getPlsBinExists`, + `${methodBase}.getIfAikariBinExists`, /** * * @returns {{ success: boolean; data: { isExists: boolean }; error?: Error }} */ (_event, _arg) => { try { - const result = fs.existsSync(PLS_BIN_PATH); + const result = fs.existsSync(AIKARI_LAUNCHER_PATH); - if (global.__HUGO_AURA__.plsStats?.status === "notInstalled") { - global.__HUGO_AURA__.plsStats.status = "dead"; + if (global.__HUGO_AURA__.aikariStats?.status === "notInstalled") { + global.__HUGO_AURA__.aikariStats.status = "dead"; } return { @@ -252,7 +258,7 @@ const applyPlsIpcHandler = (ipcMain) => { }; } catch (e) { // @ts-expect-error - global.__HUGO_AURA__.plsStats.status = "notInstalled"; + global.__HUGO_AURA__.aikariStats.status = "notInstalled"; return { success: false, data: { isExists: false }, @@ -263,7 +269,7 @@ const applyPlsIpcHandler = (ipcMain) => { ); ipcMain.handle( - `${methodBase}.ensurePlsInstallDir`, + `${methodBase}.ensureAikariInstallDir`, /** * * @param {import("electron").IpcMainInvokeEvent} _event @@ -271,24 +277,24 @@ const applyPlsIpcHandler = (ipcMain) => { * @returns {{ success: boolean; data: { alreadyExists: boolean; createdDir: string; }; error?: Error }} */ (_event, _arg) => { - const alreadyExists = fs.existsSync(PLS_INSTALL_DIR); + const alreadyExists = fs.existsSync(AIKARI_DEFAULT_INSTALL_DIR); if (alreadyExists) { return { success: true, data: { alreadyExists: true, - createdDir: PLS_INSTALL_DIR, + createdDir: AIKARI_DEFAULT_INSTALL_DIR, }, }; } try { - fs.mkdirSync(PLS_INSTALL_DIR, { recursive: true }); + fs.mkdirSync(AIKARI_DEFAULT_INSTALL_DIR, { recursive: true }); return { success: true, data: { alreadyExists: false, - createdDir: PLS_INSTALL_DIR, + createdDir: AIKARI_DEFAULT_INSTALL_DIR, }, }; } catch (error) { @@ -296,7 +302,7 @@ const applyPlsIpcHandler = (ipcMain) => { success: false, data: { alreadyExists: false, - createdDir: PLS_INSTALL_DIR, + createdDir: AIKARI_DEFAULT_INSTALL_DIR, }, error: error, }; @@ -305,30 +311,30 @@ const applyPlsIpcHandler = (ipcMain) => { ); ipcMain.handle( - `${methodBase}.getPlsStats`, + `${methodBase}.getAikariStatus`, /** * - * @returns {{ success: boolean; data: import("../../../types/shared/pls/status").PLSStatus | null | undefined; }} + * @returns {{ success: boolean; data: import("../../../types/shared/aikari/status").AikariStatus | null | undefined; }} */ (_event, _arg) => { return { success: true, - data: global.__HUGO_AURA__.plsStats, + data: global.__HUGO_AURA__.aikariStats, }; } ); ipcMain.handle( - `${methodBase}.updatePlsStats`, + `${methodBase}.updateAikariStatus`, /** * * @param {import("electron").IpcMainInvokeEvent} _event - * @param {import("../../../types/shared/pls/status").PLSStatus} arg + * @param {import("../../../types/shared/aikari/status").AikariStatus} arg * @returns */ (_event, arg) => { - global.__HUGO_AURA__.plsStats = arg; - ipcMain.send("assistant", `${methodBase}.post.onPlsStatsUpdate`, arg); + global.__HUGO_AURA__.aikariStats = arg; + ipcMain.send("assistant", `${methodBase}.post.onAikariStatsUpdate`, arg); return { success: true, }; @@ -336,7 +342,7 @@ const applyPlsIpcHandler = (ipcMain) => { ); ipcMain.handle( - `${methodBase}.getPlsSettings`, + `${methodBase}.getAikariSettings`, /** * * @returns {{ success: boolean; data: Record | null | undefined }} @@ -344,13 +350,13 @@ const applyPlsIpcHandler = (ipcMain) => { (_event, _arg) => { return { success: true, - data: global.__HUGO_AURA__.plsSettings, + data: global.__HUGO_AURA__.aikariSettings, }; } ); ipcMain.handle( - `${methodBase}.updatePlsSettings`, + `${methodBase}.updateAikariSettings`, /** * * @param {import("electron").IpcMainInvokeEvent} _event @@ -358,8 +364,12 @@ const applyPlsIpcHandler = (ipcMain) => { * @returns */ (_event, arg) => { - global.__HUGO_AURA__.plsSettings = arg; - ipcMain.send("assistant", `${methodBase}.post.onPlsSettingsUpdate`, arg); + global.__HUGO_AURA__.aikariSettings = arg; + ipcMain.send( + "assistant", + `${methodBase}.post.onAikariSettingsUpdate`, + arg + ); return { success: true, }; @@ -367,7 +377,7 @@ const applyPlsIpcHandler = (ipcMain) => { ); ipcMain.handle( - `${methodBase}.getPlsRules`, + `${methodBase}.getAikariRules`, /** * * @returns {{ success: boolean; data: Record | null | undefined }} @@ -375,13 +385,13 @@ const applyPlsIpcHandler = (ipcMain) => { (_event, _arg) => { return { success: true, - data: global.__HUGO_AURA__.plsRules, + data: global.__HUGO_AURA__.aikariRules, }; } ); ipcMain.handle( - `${methodBase}.updatePlsRules`, + `${methodBase}.updateAikariRules`, /** * * @param {import("electron").IpcMainInvokeEvent} _event @@ -389,8 +399,8 @@ const applyPlsIpcHandler = (ipcMain) => { * @returns */ (_event, arg) => { - global.__HUGO_AURA__.plsRules = arg; - ipcMain.send("assistant", `${methodBase}.post.onPlsRulesUpdate`, arg); + global.__HUGO_AURA__.aikariRules = arg; + ipcMain.send("assistant", `${methodBase}.post.onAikariRulesUpdate`, arg); return { success: true, }; @@ -402,7 +412,7 @@ const applyPlsIpcHandler = (ipcMain) => { /** * * @param {import("electron").IpcMainEvent} _event - * @param {PLSResponse} arg + * @param {AikariResponse} arg */ (_event, arg) => { ipcMain.send("assistant", `${methodBase}.ws.post.onNewMsgRecv`, arg); @@ -414,7 +424,7 @@ const applyPlsIpcHandler = (ipcMain) => { /** * * @param {import("electron").IpcMainInvokeEvent} _event - * @param {ClientPLSRequest} arg + * @param {ClientAikariRequest} arg */ (_event, arg) => { ipcMain.send( @@ -426,17 +436,17 @@ const applyPlsIpcHandler = (ipcMain) => { ); ipcMain.handle( - `${methodBase}.syncPlsConfig`, + `${methodBase}.syncAikariConfig`, /** * * @param {import("electron").IpcMainInvokeEvent} event * @param {{ basic: Record, rules: Record }} arg */ (event, arg) => { - global.__HUGO_AURA__.plsRules = arg.rules; - global.__HUGO_AURA__.plsSettings = arg.basic; + global.__HUGO_AURA__.aikariRules = arg.rules; + global.__HUGO_AURA__.aikariSettings = arg.basic; - ipcMain.send("*", `${methodBase}.syncPlsConfig`, arg, event.sender); + ipcMain.send("*", `${methodBase}.syncAikariConfig`, arg, event.sender); return { success: true, @@ -445,24 +455,27 @@ const applyPlsIpcHandler = (ipcMain) => { ); ipcMain.handle( - `${methodBase}.plsLifecycleQuery`, + `${methodBase}.aikariLifecycleQuery`, /** * * @param {import("electron").IpcMainInvokeEvent} _event - * @param {{ target: import("../../../types/shared/pls/status").PLSLifecycleType }} arg + * @param {{ target: import("../../../types/shared/aikari/status").AikariLifecycleType }} arg * @returns {Promise<{ success: boolean, result: boolean }>} */ async (_event, arg) => { switch (arg.target) { case "isDetached": - return { success: true, result: isPlsDetached }; + return { success: true, result: isAikariDetached }; case "isSvcInstalled": - return await functions.querySvcDetail(PLS_SVC_NAME, "SERVICE_NAME"); + return await functions.querySvcDetail( + AIKARI_SVC_NAME, + "SERVICE_NAME" + ); case "isSvcStart": - return await functions.querySvcDetail(PLS_SVC_NAME, "RUNNING"); + return await functions.querySvcDetail(AIKARI_SVC_NAME, "RUNNING"); default: console.warn( - `[HugoAura / IPC / PLS] Invalid arg.target: ${arg.target}` + `[HugoAura / IPC / Aikari] Invalid arg.target: ${arg.target}` ); return { success: false, @@ -473,98 +486,68 @@ const applyPlsIpcHandler = (ipcMain) => { ); ipcMain.handle( - `${methodBase}.plsLifecycleControl`, + `${methodBase}.aikariLifecycleControl`, /** * * @param {*} _event - * @param {{ target: import("../../../types/shared/pls/status").PLSLifecycleControlType }} arg + * @param {{ target: import("../../../types/shared/aikari/status").AikariLifecycleControlType }} arg * @returns {Promise<{ success: boolean, errorObj?: Error }>} */ async (_event, arg) => { - const logHeader = "[HugoAura / IPC / PLS] "; + const logHeader = "[HugoAura / IPC / Aikari] "; + // TODO: Impl this switch (arg.target) { case "instSvc": return await functions.execCommand( logHeader, - PLS_BIN_PATH, + AIKARI_LAUNCHER_PATH, "--startup auto install" ); - case "rmSvc": { + case "uninstSvc": { const result = await functions.execCommand( logHeader, - PLS_BIN_PATH, + AIKARI_LAUNCHER_PATH, "remove" ); return result; } case "startSvc": - return await functions.execCommand(logHeader, PLS_BIN_PATH, "start"); + return await functions.execCommand( + logHeader, + AIKARI_LAUNCHER_PATH, + "start" + ); case "stopSvc": { const result = await functions.execCommand( logHeader, - PLS_BIN_PATH, + AIKARI_LAUNCHER_PATH, "stop" ); - if (result.success && global.__HUGO_AURA__.plsStats) { - global.__HUGO_AURA__.plsStats.connected = false; - global.__HUGO_AURA__.plsStats.launched = false; - global.__HUGO_AURA__.plsStats.version = "unknown"; - global.__HUGO_AURA__.plsStats.status = "dead"; + if (result.success && global.__HUGO_AURA__.aikariStats) { + global.__HUGO_AURA__.aikariStats.connected = false; + global.__HUGO_AURA__.aikariStats.launched = false; + global.__HUGO_AURA__.aikariStats.version = "unknown"; + global.__HUGO_AURA__.aikariStats.status = "dead"; ipcMain.send( "assistant", - `${methodBase}.post.onPlsStatsUpdate`, - global.__HUGO_AURA__.plsStats + `${methodBase}.post.onAikariStatsUpdate`, + global.__HUGO_AURA__.aikariStats ); ipcMain.send( "auraWsKeepAlive", - `${methodBase}.post.plsStopped`, + `${methodBase}.post.aikariStopped`, {} ); } return result; } - case "rmBin": - const unlinkPromise = new Promise((resolve) => { - fs.unlink(PLS_BIN_PATH, (error) => { - if (error) { - resolve({ - success: false, - errorObj: error, - }); - console.error( - `${logHeader} Failed to remove PLS bin, error:`, - error - ); - return false; - } - - resolve({ - success: true, - errorObj: null, - }); - return true; - }); - }); - - const unlinkRet = await unlinkPromise; - - if (unlinkRet.success && global.__HUGO_AURA__.plsStats) { - global.__HUGO_AURA__.plsStats.connected = false; - global.__HUGO_AURA__.plsStats.launched = false; - global.__HUGO_AURA__.plsStats.installed = false; - global.__HUGO_AURA__.plsStats.version = "unknown"; - - ipcMain.send( - "assistant", - `${methodBase}.post.onPlsStatsUpdate`, - global.__HUGO_AURA__.plsStats - ); - } - - return unlinkRet; + case "inst": + // TODO: Impl Aikari INST + case "uninst": + // same default: return { success: false, errorObj: new Error("Method not found") }; } @@ -572,7 +555,7 @@ const applyPlsIpcHandler = (ipcMain) => { ); ipcMain.handle( - `${methodBase}.downloadPls`, + `${methodBase}.downloadAndInstallAikari`, /** * * @param {import("electron").IpcMainInvokeEvent} _evt @@ -582,22 +565,22 @@ const applyPlsIpcHandler = (ipcMain) => { (_evt, arg) => { const channel = arg.channel ? arg.channel : "stable"; const reportWin = arg.reportTo ? arg.reportTo : "assistant"; - functions.handlePLSDownload( + functions.handleAikariDownload( channel, (status) => { ipcMain.send( reportWin, - `${methodBase}.post.reportPlsDownloadStatus`, + `${methodBase}.post.reportAikariInstallStep`, status ); }, - PLS_BIN_PATH + AIKARI_LAUNCHER_PATH ); } ); ipcMain.handle( - `${methodBase}.retryPlsConnect`, + `${methodBase}.retryAikariConnect`, /** * * @param {import("electron").IpcMainInvokeEvent} _event @@ -605,13 +588,17 @@ const applyPlsIpcHandler = (ipcMain) => { * @returns {{ success: boolean, status: "Already" | "Retrying" }} */ (_event, arg) => { - if (global.__HUGO_AURA__.plsStats?.connected) { + if (global.__HUGO_AURA__.aikariStats?.connected) { return { success: true, status: "Already", }; } else { - ipcMain.send("auraWsKeepAlive", `${methodBase}.retryPlsConnect`, arg); + ipcMain.send( + "auraWsKeepAlive", + `${methodBase}.retryAikariConnect`, + arg + ); return { success: true, @@ -639,4 +626,4 @@ const applyPlsIpcHandler = (ipcMain) => { ); }; -module.exports = { applyPlsIpcHandler }; +module.exports = { applyAikariIpcHandler }; diff --git a/src/aura/types/render/global.d.ts b/src/aura/types/render/global.d.ts index 3bf021a..ea87f79 100755 --- a/src/aura/types/render/global.d.ts +++ b/src/aura/types/render/global.d.ts @@ -3,14 +3,14 @@ interface HugoAuraGlobal { } interface AssistantHugoAuraGlobal extends HugoAuraGlobal { - plsStatus: PLSStatus; + plsStatus: AikariStatus; plsRules: Record; plsSettings: Record; } interface AuraWSKeepAliveWindowHugoAuraGlobal extends HugoAuraGlobal { plsWs: WebSocket | null; - plsStats: PLSStatus; + plsStats: AikariStatus; } type UIFunctionsObject = Record; diff --git a/src/aura/types/shared/pls/status.d.ts b/src/aura/types/shared/aikari/status.d.ts old mode 100755 new mode 100644 similarity index 52% rename from src/aura/types/shared/pls/status.d.ts rename to src/aura/types/shared/aikari/status.d.ts index 0538d06..8c4e77e --- a/src/aura/types/shared/pls/status.d.ts +++ b/src/aura/types/shared/aikari/status.d.ts @@ -1,28 +1,29 @@ import { RendererProcessOnlyVal } from "../global"; -type PLSStatusDesc = +type AikariStatusDesc = | "dead" | "running" | "notReady" | "downloading" + | "installing" | "notInstalled"; -interface PLSStatus { +interface AikariStatus { installed: boolean; detached: boolean; connected: boolean; launched: boolean; - status: PLSStatusDesc; + status: AikariStatusDesc; version: string; authToken: string; } -type PLSLifecycleType = "isDetached" | "isSvcInstalled" | "isSvcStart"; +type AikariLifecycleType = "isDetached" | "isSvcInstalled" | "isSvcStart"; -type PLSLifecycleControlType = +type AikariLifecycleControlType = | "instSvc" - | "rmSvc" + | "uninstSvc" | "startSvc" | "stopSvc" - | "rmBin" - | "dlBin"; + | "uninst" + | "inst"; diff --git a/src/aura/types/shared/pls/websocket.d.ts b/src/aura/types/shared/aikari/websocket.d.ts old mode 100755 new mode 100644 similarity index 64% rename from src/aura/types/shared/pls/websocket.d.ts rename to src/aura/types/shared/aikari/websocket.d.ts index 9533b70..c4cd9e4 --- a/src/aura/types/shared/pls/websocket.d.ts +++ b/src/aura/types/shared/aikari/websocket.d.ts @@ -1,17 +1,18 @@ -interface ClientPLSRequest { +interface ClientAikariRequest { method: string; data: Record; eventId: string; + module: string; } -interface PLSResponse { +interface AikariResponse { success: boolean; code: number; data: Record; eventId: string; } -interface PLSPush { +interface AikariPush { success: boolean; type: string; data: Record; diff --git a/src/aura/types/shared/global.d.ts b/src/aura/types/shared/global.d.ts index 01823ff..849bd3b 100755 --- a/src/aura/types/shared/global.d.ts +++ b/src/aura/types/shared/global.d.ts @@ -3,7 +3,7 @@ import type EventBus from "../../utils/eventBus"; import { HookedWindowsMap, UIHooksMap, WindowHooksMap } from "../main/core"; import { UIHooksObject } from "../render/uiHook"; import ConfigManager from "../../init/shared/configManager"; -import { PLSStatus } from "./pls/status"; +import { AikariStatus } from "./aikari/status"; type MainProcessOnlyVal = T; type RendererProcessOnlyVal = T; @@ -15,10 +15,10 @@ interface GlobalHugoAuraInfo { hookedWindows?: MainProcessOnlyVal; ipcInit?: MainProcessOnlyVal; auraDir: MainProcessOnlyVal; - plsRules?: Record | null; - plsSettings?: Record | null; - plsStats?: PLSStatus | null; - plsWs?: RendererProcessOnlyVal; + aikariRules?: Record | null; + aikariSettings?: Record | null; + aikariStats?: AikariStatus | null; + aikariWs?: RendererProcessOnlyVal; uiHooks?: MainProcessOnlyVal; windowHooks?: MainProcessOnlyVal; version: RendererProcessOnlyVal; @@ -26,7 +26,7 @@ interface GlobalHugoAuraInfo { interface GlobalHugoAuraApiInfo { domains: string[]; - plsUpdate: string; + aikariUpdate: string; auraUpdate: string; } diff --git a/src/aura/ui/aikari/onConnectedSeq.js b/src/aura/ui/aikari/onConnectedSeq.js new file mode 100644 index 0000000..c4e287a --- /dev/null +++ b/src/aura/ui/aikari/onConnectedSeq.js @@ -0,0 +1,80 @@ +// @ts-check + +const { genRandomHex } = require("../../utils/crypto"); + +const IPC_METHOD_BASE = "$aura.aikari"; + +/** @type {Map} */ +const wsGetCallbacks = new Map(); + +const actions = { + getAikariVersion: async (originalAikariStates, wsObj) => { + const eventId = genRandomHex(); + wsObj.send( + JSON.stringify({ + module: "launcher", + eventId: eventId, + method: "basic.props.getVersion", + data: {}, + }) + ); + const promise = new Promise((resolve) => { + wsGetCallbacks.set(eventId, resolve); + }); + const data = await promise; + if (data.success) { + originalAikariStates.version = data.data.version; + console.debug( + "[HugoAura / UI / Aikari OCMS] Updated Aikari version info: " + + data.data.version + ); + } + }, + getAikariLauncherConfig: async (wsObj) => { + const eventId = genRandomHex(); + wsObj.send( + JSON.stringify({ + module: "launcher", + eventId, + method: "config.actions.getConfig", + data: {}, + }) + ); + const promise = new Promise((resolve) => { + wsGetCallbacks.set(eventId, resolve); + }); + const data = await promise; + if (data.success) { + console.debug( + "[HugoAura / UI / Aikari OCMS] Received Aikari launcher config: ", + data + ); + return data.data; + } else { + return null; + } + }, +}; + +const onAikariConnectedMsgSeq = async ({ curAikariStates, wsObj }) => { + const updatedAikariStates = { ...curAikariStates }; + const onMsgRecvListener = (data) => { + if (wsGetCallbacks.has(data.detail.eventId)) { + wsGetCallbacks.get(data.detail.eventId)(data.detail); + } + }; + document.addEventListener("onAikariMessageRecv", onMsgRecvListener); + // Get Aikari Version + await actions.getAikariVersion(updatedAikariStates, wsObj); + const aikariLauncherConfig = await actions.getAikariLauncherConfig(wsObj); + if (aikariLauncherConfig) { + global.ipcRenderer.invoke( + `${IPC_METHOD_BASE}.updateAikariSettings`, + aikariLauncherConfig + ); + } + + return updatedAikariStates; +}; + +module.exports = { onAikariConnectedMsgSeq }; diff --git a/src/aura/ui/pls/pushHandler.js b/src/aura/ui/aikari/pushHandler.js old mode 100755 new mode 100644 similarity index 89% rename from src/aura/ui/pls/pushHandler.js rename to src/aura/ui/aikari/pushHandler.js index bf33426..3e96c8d --- a/src/aura/ui/pls/pushHandler.js +++ b/src/aura/ui/aikari/pushHandler.js @@ -7,7 +7,7 @@ const { configRouteHandler } = require(`${REQUIRE_BASE}/routes/config`); /** * - * @param {PLSPush} parsedWsMsg + * @param {AikariPush} parsedWsMsg * @returns */ const pushMsgHandler = (parsedWsMsg) => { diff --git a/src/aura/ui/aikari/routes/basic.js b/src/aura/ui/aikari/routes/basic.js new file mode 100644 index 0000000..755497a --- /dev/null +++ b/src/aura/ui/aikari/routes/basic.js @@ -0,0 +1,49 @@ +// @ts-check + +const IPC_METHOD_BASE = "$aura.aikari"; + +// TODO: REFACTOR +/** + * + * @param {AikariPush} parsedWsMsg + * @returns + */ +const basicRouteHandler = (parsedWsMsg) => { + const target = parsedWsMsg.type.split(".").slice(-1)[0]; + switch (target) { + case "pushPlsInfo": + if (global.__HUGO_AURA__.aikariStats) { + global.__HUGO_AURA__.aikariStats.status = parsedWsMsg.data.status; + global.__HUGO_AURA__.aikariStats.version = parsedWsMsg.data.version; + } + + global.ipcRenderer.invoke( + `${IPC_METHOD_BASE}.updateAikariStatus`, + global.__HUGO_AURA__.aikariStats + ); + + console.debug( + "[HugoAura / UI / Aikari Routes / DEBUG] Updated aikariStats basic info:", + global.__HUGO_AURA__.aikariStats + ); + break; + + case "plsNotReadyError": + if (global.__HUGO_AURA__.aikariStats) { + global.__HUGO_AURA__.aikariStats.launched = true; + global.__HUGO_AURA__.aikariStats.connected = false; + global.__HUGO_AURA__.aikariStats.status = "notReady"; + } + + global.ipcRenderer.invoke( + `${IPC_METHOD_BASE}.updateAikariStatus`, + global.__HUGO_AURA__.aikariStats + ); + break; + default: + return false; + } + return true; +}; + +module.exports = { basicRouteHandler }; diff --git a/src/aura/ui/pls/routes/config.js b/src/aura/ui/aikari/routes/config.js old mode 100755 new mode 100644 similarity index 69% rename from src/aura/ui/pls/routes/config.js rename to src/aura/ui/aikari/routes/config.js index 2d8bdae..de18813 --- a/src/aura/ui/pls/routes/config.js +++ b/src/aura/ui/aikari/routes/config.js @@ -1,10 +1,10 @@ // @ts-check -const IPC_METHOD_BASE = "$aura.pls"; +const IPC_METHOD_BASE = "$aura.aikari"; /** * - * @param {PLSPush} parsedWsMsg + * @param {AikariPush} parsedWsMsg * @returns */ const configRouteHandler = (parsedWsMsg) => { @@ -12,13 +12,13 @@ const configRouteHandler = (parsedWsMsg) => { switch (target) { case "pushBasicConfig": global.ipcRenderer.invoke( - `${IPC_METHOD_BASE}.updatePlsSettings`, + `${IPC_METHOD_BASE}.updateAikariSettings`, parsedWsMsg.data ); break; case "pushRuleSettings": global.ipcRenderer.invoke( - `${IPC_METHOD_BASE}.updatePlsRules`, + `${IPC_METHOD_BASE}.updateAikariRules`, parsedWsMsg.data ); break; diff --git a/src/aura/ui/composables/aikariConfigManager.js b/src/aura/ui/composables/aikariConfigManager.js new file mode 100644 index 0000000..51828b7 --- /dev/null +++ b/src/aura/ui/composables/aikariConfigManager.js @@ -0,0 +1,83 @@ +// @ts-check + +const __SCOPE = "assistant / rendererCommon"; + +const IPC_METHOD_BASE = "$aura.aikari"; + +const updateAikariStatusFromLocal = async () => { + const aikariStatus = ( + await global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.getAikariStatus`) + ).data; + global.__HUGO_AURA__.aikariStats = aikariStatus; + return aikariStatus; +}; + +const updateAikariSettingsFromLocal = async () => { + const aikariSettings = ( + await global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.getAikariSettings`) + ).data; + global.__HUGO_AURA__.aikariSettings = aikariSettings; + return aikariSettings; +}; + +const updateAikariRulesFromLocal = async () => { + const aikariRules = ( + await global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.getAikariRules`) + ).data; + global.__HUGO_AURA__.aikariRules = aikariRules; + return aikariRules; +}; + +const { genRandomHex } = require("../../utils/crypto"); + +/** + * + * @param {string} configKey + * @param {any} configValue + */ +const updateAikariConfigToRemote = async (configKey, configValue) => { + const configLevels = configKey.split("."); + + const aikariConfigUpdateEvent = new CustomEvent("onAikariConfigUpdate", { + detail: { + path: configLevels, + value: configValue, + }, + }); + document.dispatchEvent(aikariConfigUpdateEvent); + const settingsEntries = document.getElementsByClassName( + "aura-settings-entry" + ); + if (settingsEntries.length > 0) { + Array.from(settingsEntries).forEach((entry) => { + entry.dispatchEvent(aikariConfigUpdateEvent); + }); + } + + /** + * @type {ClientAikariRequest} + */ + /* + const data = { + method: "config.action.updateConfig", + data: { + key: configKey, + value: configValue, + }, + eventId: genRandomHex(), // 不用 crypto, 因为会带来不必要的性能开销 + };*/ + // TODO: Impl this ↑ + + // global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.ws.sendWsMessage`, data); + global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.syncAikariConfig`, { + basic: global.__HUGO_AURA__.aikariSettings, + rules: global.__HUGO_AURA__.aikariRules, + }); +}; + +module.exports = { + updateAikariRulesFromLocal, + updateAikariStatusFromLocal, + updateAikariSettingsFromLocal, + updateAikariConfigToRemote, +}; diff --git a/src/aura/ui/composables/plsConfigManager.js b/src/aura/ui/composables/plsConfigManager.js deleted file mode 100755 index 694a863..0000000 --- a/src/aura/ui/composables/plsConfigManager.js +++ /dev/null @@ -1,81 +0,0 @@ -// @ts-check - -const __SCOPE = "assistant / rendererCommon"; - -const IPC_METHOD_BASE = "$aura.pls"; - -const updatePlsStatusFromLocal = async () => { - const plsStatus = ( - await global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.getPlsStats`) - ).data; - global.__HUGO_AURA__.plsStats = plsStatus; - return plsStatus; -}; - -const updatePlsSettingsFromLocal = async () => { - const plsSettings = ( - await global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.getPlsSettings`) - ).data; - global.__HUGO_AURA__.plsSettings = plsSettings; - return plsSettings; -}; - -const updatePlsRulesFromLocal = async () => { - const plsRules = ( - await global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.getPlsRules`) - ).data; - global.__HUGO_AURA__.plsRules = plsRules; - return plsRules; -}; - -const { genRandomHex } = require("../../utils/crypto"); - -/** - * - * @param {string} configKey - * @param {any} configValue - */ -const updatePlsConfigToRemote = async (configKey, configValue) => { - const configLevels = configKey.split("."); - - const plsConfigUpdateEvent = new CustomEvent("onPLSConfigUpdate", { - detail: { - path: configLevels, - value: configValue, - }, - }); - document.dispatchEvent(plsConfigUpdateEvent); - const settingsEntries = document.getElementsByClassName( - "aura-settings-entry" - ); - if (settingsEntries.length > 0) { - Array.from(settingsEntries).forEach((entry) => { - entry.dispatchEvent(plsConfigUpdateEvent); - }); - } - - /** - * @type {ClientPLSRequest} - */ - const data = { - method: "config.action.updateConfig", - data: { - key: configKey, - value: configValue, - }, - eventId: genRandomHex(), // 不用 crypto, 因为会带来不必要的性能开销 - }; - - global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.ws.sendWsMessage`, data); - global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.syncPlsConfig`, { - basic: global.__HUGO_AURA__.plsSettings, - rules: global.__HUGO_AURA__.plsRules, - }); -}; - -module.exports = { - updatePlsRulesFromLocal, - updatePlsStatusFromLocal, - updatePlsSettingsFromLocal, - updatePlsConfigToRemote, -}; diff --git a/src/aura/ui/composables/settingsRenderer.js b/src/aura/ui/composables/settingsRenderer.js index 9b2abe5..c148407 100755 --- a/src/aura/ui/composables/settingsRenderer.js +++ b/src/aura/ui/composables/settingsRenderer.js @@ -18,12 +18,12 @@ const showRelaunchToast = () => { if (!toastBs.isShown()) toastBs.show(); }; -const showRelaunchPLSToast = () => { - const toast = document.getElementById("relaunchPlsNotifyToast"); +const showRelaunchAikariToast = () => { + const toast = document.getElementById("relaunchAikariNotifyToast"); const toastBs = bootstrap.Toast.getOrCreateInstance(toast); - if (global.__HUGO_AURA__.plsStats.detached) { - const relaunchBtn = document.getElementById("plsRelaunchBtn"); + if (global.__HUGO_AURA__.aikariStats.detached) { + const relaunchBtn = document.getElementById("aikariRelaunchBtn"); relaunchBtn.disabled = true; relaunchBtn.textContent = "分离模式下无法执行"; } @@ -37,12 +37,6 @@ const showToast = (entry) => { } else if (entry.restart) { showRelaunchToast(); } - - /* - else if (entry.restartPLS) { - showRelaunchPLSToast(); - } - */ }; const setDisableStatus = (el, isDisable, hint = null) => { @@ -225,29 +219,29 @@ const renderNormalSettingsItem = (entry, formEl) => { powerIcon.setAttribute("data-bs-title", "需要重启 Electron 进程"); entryTitle.appendChild(powerIcon); } - if (entry.PLSRequired) { - const plsIcon = document.createElement("i"); - plsIcon.classList.add( + if (entry.AikariRequired) { + const aikariIcon = document.createElement("i"); + aikariIcon.classList.add( "layui-icon", "layui-icon-component", "aura-settings-entry-property-icon" ); - plsIcon.setAttribute("data-bs-toggle", "tooltip"); - plsIcon.setAttribute("data-bs-placement", "top"); - plsIcon.setAttribute("data-bs-title", "需要 PLS 支持"); - entryTitle.appendChild(plsIcon); + aikariIcon.setAttribute("data-bs-toggle", "tooltip"); + aikariIcon.setAttribute("data-bs-placement", "top"); + aikariIcon.setAttribute("data-bs-title", "需要 Aikari 支持"); + entryTitle.appendChild(aikariIcon); } - if (entry.restartPLS) { - const plsIcon = document.createElement("i"); - plsIcon.classList.add( + if (entry.restartAikari) { + const aikariIcon = document.createElement("i"); + aikariIcon.classList.add( "layui-icon", "layui-icon-logout", "aura-settings-entry-property-icon" ); - plsIcon.setAttribute("data-bs-toggle", "tooltip"); - plsIcon.setAttribute("data-bs-placement", "top"); - plsIcon.setAttribute("data-bs-title", "需要重启 PLS 进程"); - entryTitle.appendChild(plsIcon); + aikariIcon.setAttribute("data-bs-toggle", "tooltip"); + aikariIcon.setAttribute("data-bs-placement", "top"); + aikariIcon.setAttribute("data-bs-title", "需要重启 Aikari 进程"); + entryTitle.appendChild(aikariIcon); } if (entry.reload) { const reloadIcon = document.createElement("i"); @@ -308,27 +302,27 @@ const renderNormalSettingsItem = (entry, formEl) => { insertOrRemoveEl(entryOperationArea, targetEl, true); } }; - const channel = entry.PLSRequired - ? "onPLSConfigUpdate" + const channel = entry.AikariRequired + ? "onAikariConfigUpdate" : "onHugoAuraConfigUpdate"; entryContainerEl.addEventListener(channel, evtListener); // createOnLeaveEvtListener(channel, evtListener); } - if (entry.PLSRequired) { - if (!global.__HUGO_AURA__.plsStats.connected) { - setDisableStatus(entryOperationArea, true, "连接至 PLS 以继续"); + if (entry.AikariRequired) { + if (!global.__HUGO_AURA__.aikariStats.connected) { + setDisableStatus(entryOperationArea, true, "连接至 Aikari 以继续"); } const evtListener = (event) => { if (event.detail.connected) { setDisableStatus(entryOperationArea, false); } else { - setDisableStatus(entryOperationArea, true, "连接至 PLS 以继续"); + setDisableStatus(entryOperationArea, true, "连接至 Aikari 以继续"); } }; - entryContainerEl.addEventListener("onPLSStatsUpdate", evtListener); - // createOnLeaveEvtListener("onPLSStatsUpdate", evtListener); + entryContainerEl.addEventListener("onAikariStatsUpdate", evtListener); + // createOnLeaveEvtListener("onAikariStatsUpdate", evtListener); } entryContainerEl.appendChild(entryOperationArea); const isShow = entry.auraIf(); @@ -360,8 +354,8 @@ const renderNormalSettingsItem = (entry, formEl) => { updateDisableStatus(); } }; - const channel = entry.PLSRequired - ? "onPLSConfigUpdate" + const channel = entry.AikariRequired + ? "onAikariConfigUpdate" : "onHugoAuraConfigUpdate"; entryContainerEl.addEventListener(channel, evtListener); // createOnLeaveEvtListener(channel, evtListener); @@ -403,7 +397,7 @@ const renderPreviewItem = (entry, formEl) => { }; document.addEventListener( - eventChannel === "pls" ? "onPLSConfigUpdate" : "onHugoAuraConfigUpdate", + eventChannel === "pls" ? "onAikariConfigUpdate" : "onHugoAuraConfigUpdate", eventListener ); createOnLeaveEvtListener(eventListener); // Clean up diff --git a/src/aura/ui/hookDefinitions/assistant.js b/src/aura/ui/hookDefinitions/assistant.js index 4ae580d..35ba5c7 100755 --- a/src/aura/ui/hookDefinitions/assistant.js +++ b/src/aura/ui/hookDefinitions/assistant.js @@ -41,13 +41,13 @@ const def = { selectorMode: "appendChild", pageCSS: "ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.css", childs: { - PlsStatus: { + AikariStatus: { active: false, - pageURI: "ui/pages/configSubPages/behaviourCtrl/plsStatus.html", - pageScript: "ui/pages/configSubPages/behaviourCtrl/plsStatus.js", + pageURI: "ui/pages/configSubPages/behaviourCtrl/aikariStatus.html", + pageScript: "ui/pages/configSubPages/behaviourCtrl/aikariStatus.js", pageSelector: "#status-subpage", selectorMode: "appendChild", - pageCSS: "ui/pages/configSubPages/behaviourCtrl/plsStatus.css", + pageCSS: "ui/pages/configSubPages/behaviourCtrl/aikariStatus.css", }, DeviceSecurity: { childs: { @@ -86,7 +86,7 @@ const def = { ], globalJS: [ "ui/js/global.js", - "ui/js/plsListener.js", + "ui/js/aikariListener.js", "ui/bootstrap/bootstrap.bundle.min.js", ], onLoaded: ` diff --git a/src/aura/ui/js/aikariConnectionManager.js b/src/aura/ui/js/aikariConnectionManager.js new file mode 100644 index 0000000..125c5ac --- /dev/null +++ b/src/aura/ui/js/aikariConnectionManager.js @@ -0,0 +1,372 @@ +// @ts-check +(() => { + if (!global.__HUGO_AURA__) + global.__HUGO_AURA__ = { + configInit: true, + auraDir: "", + version: "", + }; + + if (!global.__HUGO_AURA__.aikariStats) + global.__HUGO_AURA__.aikariStats = { + installed: false, + detached: false, + connected: false, + launched: false, + status: "dead", + version: "unknown", + authToken: "", + }; + + const IPC_METHOD_BASE = "$aura.aikari"; + const REQUIRE_BASE = "../../.."; + const __SCOPE = "auraWsKeepAlive"; + + const AIKARI_RPC_CONFIG_REG_PATH = "Aikari\\RPC"; + + const { pushMsgHandler } = require(`${REQUIRE_BASE}/aikari/pushHandler`); + const { + onAikariConnectedMsgSeq, + } = require(`${REQUIRE_BASE}/aikari/onConnectedSeq`); + const RegistryManager = require(`${REQUIRE_BASE}/../init/shared/registryManager`); + + const registryManager = new RegistryManager(); + + /** @type {number} */ + let failedCounter = 0; + /** @type {boolean} */ + let isErrorOccurred = false; + + /** @type {number} */ + let plsPort = 22077; + /** @type {"wss" | "ws"} */ + let plsProtocol = "wss"; + + /** @type {boolean} */ + let isRetrying = false; + + /** @type {any} */ + let curSendListener = null; + let curSendGetListener = null; + + const sendRetryStatusToMain = (/** @type {Boolean} */ status) => { + global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.post.updateRetryStatus`, { + success: status, + }); + }; + + const clearReqSendIpcListener = () => { + if (curSendListener) { + global.ipcRenderer.off( + `${IPC_METHOD_BASE}.ws.post.onReqSendMsg`, + curSendListener + ); + curSendListener = null; + } + }; + + const clearSendGetIpcListener = () => { + if (curSendGetListener) { + global.ipcRenderer.off( + `${IPC_METHOD_BASE}.ws.post.onSendGetMsg`, + curSendListener + ); + curSendGetListener = null; + } + }; + + const startConnAikariProc = async (updatedAikariStats) => { + const authTokenRet = await registryManager.readRegKey( + AIKARI_RPC_CONFIG_REG_PATH, + "authToken", + true + ); + if (authTokenRet.success) { + updatedAikariStats.authToken = authTokenRet.data; + // @ts-expect-error + global.__HUGO_AURA__.aikariStats.authToken = authTokenRet.data; + } else { + sendRetryStatusToMain(false); + return; + } + const portRet = await registryManager.readRegKey( + AIKARI_RPC_CONFIG_REG_PATH, + "wsPort", + true + ); + if (portRet.success) { + try { + plsPort = Number(portRet.data); + } catch { + console.warn( + `[HugoAura / UI / Aikari Conn Manager] Invalid Aikari port: ${portRet.data}` + ); + } + } + // TODO: wsHost + createAikariConnection(updatedAikariStats.authToken, connectionResultCallback); + }; + + /** + * + * @param {string} authToken + * @param {any} callback + * @returns + */ + const createAikariConnection = (authToken, callback) => { + if (failedCounter >= 3) { + console.error( + `[HugoAura / UI / Aikari Conn Manager / ERROR] Failed connecting to PLS WebSocket server, please check the status of PLS process.` + ); + sendRetryStatusToMain(false); + return; + } + + /** @type {WebSocket} */ + const aikariWs = new WebSocket( + `${plsProtocol}://aikari.hugoaura.local:${plsPort}/?auth=${authToken}` + ); + + aikariWs.onopen = () => { + callback(true, aikariWs); + }; + + aikariWs.onerror = () => { + isErrorOccurred = true; + failedCounter += 1; + callback(false, aikariWs); + }; + + aikariWs.onclose = () => { + clearReqSendIpcListener(); + if (global.__HUGO_AURA__.aikariStats) { + if (global.__HUGO_AURA__.aikariStats.status === "notReady") { + if (isRetrying) { + sendRetryStatusToMain(false); + return; + } + console.warn( + "[HugoAura / UI / Aikari Conn Manager / WARN] Aikari not ready, try again after 10s..." + ); + isRetrying = true; + setTimeout(async () => { + isRetrying = false; + startConnAikariProc(global.__HUGO_AURA__.aikariStats); + }, 10000); + sendRetryStatusToMain(false); + return; + } + + if (global.__HUGO_AURA__.aikariStats.launched === false) { + console.warn( + "[HugoAura / UI / Aikari Conn Manager / WARN] Aikari stopped, closing WebSocket connection." + ); + return; + } + } + + console.error( + "[HugoAura / UI / Aikari Conn Manager / ERROR] WebSocket connection closed." + ); + if (isErrorOccurred) return; + failedCounter += 1; + callback(false, aikariWs); + }; + }; + + /** + * + * @param {WebSocket} wsObj + */ + const registerSendReqListener = (wsObj) => { + clearReqSendIpcListener(); + /** + * + * @param {import("electron").IpcRendererEvent} _evt + * @param {any} arg + */ + curSendListener = (_evt, arg) => { + wsObj.send(JSON.stringify(arg)); + }; + global.ipcRenderer.on( + `${IPC_METHOD_BASE}.ws.post.onReqSendMsg`, + curSendListener + ); + }; + + /** + * + * @param {boolean} result + * @param {WebSocket} wsObj + * @returns + */ + const connectionResultCallback = async (result, wsObj) => { + if (!global.__HUGO_AURA__.aikariStats) return; // 😅 typescript + + global.__HUGO_AURA__.aikariStats.launched = result; + global.__HUGO_AURA__.aikariStats.connected = result; + global.ipcRenderer.invoke( + `${IPC_METHOD_BASE}.updateAikariStatus`, + global.__HUGO_AURA__.aikariStats + ); + if (!result) { + console.error( + `[HugoAura / UI / Aikari Conn Manager / ERROR] Failed connecting to Aikari WebSocket server, retrying ...` + ); + createAikariConnection( + global.__HUGO_AURA__.aikariStats.authToken, + connectionResultCallback + ); + return; + } + wsObj.onmessage = aikariPushHandler; + + registerSendReqListener(wsObj); + + global.__HUGO_AURA__.aikariWs = wsObj; + + global.__HUGO_AURA__.aikariStats = await onAikariConnectedMsgSeq({ + curAikariStates: global.__HUGO_AURA__.aikariStats, + wsObj, + }); + global.ipcRenderer.invoke( + `${IPC_METHOD_BASE}.updateAikariStatus`, + global.__HUGO_AURA__.aikariStats + ); + + sendRetryStatusToMain(true); + }; + + /** + * + * @param {MessageEvent} event + */ + const aikariPushHandler = (event) => { + try { + /** @type {Record} */ + const parsedEvent = JSON.parse(event.data); + console.debug( + "[HugoAura / UI / Aikari Conn Manager / DEBUG] Received new server message: " + ); + if (!parsedEvent.eventId || parsedEvent.eventId === "N/A") { + // Push + pushMsgHandler(parsedEvent); + } else { + // Not push + global.ipcRenderer.send( + `${IPC_METHOD_BASE}.ws.broadcastMessageRecv`, + parsedEvent + ); + + const msgRecvEvent = new CustomEvent("onAikariMessageRecv", { + detail: parsedEvent, + }); + document.dispatchEvent(msgRecvEvent); + } + } catch { + console.error( + "[HugoAura / UI / Aikari Conn Manager / ERROR] Failed to resolve server message: ", + event.data + ); + } + }; + + const initAikariWebSocketConnection = async () => { + if (!global.__HUGO_AURA__.aikariStats) return; + + if (isRetrying) { + sendRetryStatusToMain(false); + return; + } + + failedCounter = 0; + isErrorOccurred = false; + + const curPlsStats = await global.ipcRenderer.invoke( + `${IPC_METHOD_BASE}.getAikariStatus` + ); + let updatedAikariStats = {}; + if ( + (curPlsStats === null || !curPlsStats.success) && + curPlsStats.status !== "downloading" && + curPlsStats.status !== "installing" + ) { + updatedAikariStats = { + installed: false, + launched: false, + detached: false, + connected: false, + version: "unknown", + status: "dead", + authToken: "", + }; + } else { + updatedAikariStats = curPlsStats.data; + } + + const isAikariBinExists = ( + await global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.getIfAikariBinExists`) + ).data.isExists; + updatedAikariStats.installed = isAikariBinExists; + // @ts-expect-error + global.__HUGO_AURA__.aikariStats = updatedAikariStats; + console.debug( + "[HugoAura / UI / Aikari Conn Manager / DEBUG] Updated early aikariStats:", + global.__HUGO_AURA__.aikariStats + ); + + global.ipcRenderer.invoke( + `${IPC_METHOD_BASE}.updateAikariStatus`, + updatedAikariStats + ); + + /* + if (updatedPlsStats.detached && updatedPlsStats.installed) { + */ + if (updatedAikariStats.installed || updatedAikariStats.detached) { + await startConnAikariProc(updatedAikariStats); + } else { + sendRetryStatusToMain(false); + } + + /* + global.ipcRenderer.on(`${IPC_METHOD_BASE}.post.onPlsLaunched`, (_event) => { + setTimeout(() => { + startConnPls(); + }, 5000); + }); + */ + }; + + const onSetup = () => { + if (!global.ipcRenderer) { + // @ts-ignore + global.ipcRenderer = require("electron").ipcRenderer; + } + + initAikariWebSocketConnection(); + + global.ipcRenderer.on( + `${IPC_METHOD_BASE}.retryAikariConnect`, + (_evt, _arg) => { + if (!global.__HUGO_AURA__.aikariStats) return; + if (global.__HUGO_AURA__.aikariStats.connected) return; + initAikariWebSocketConnection(); + } + ); + + global.ipcRenderer.on( + `${IPC_METHOD_BASE}.post.aikariStopped`, + (_evt, _arg) => { + if (!global.__HUGO_AURA__.aikariStats) return; + global.__HUGO_AURA__.aikariStats.launched = false; + global.__HUGO_AURA__.aikariStats.connected = false; + global.__HUGO_AURA__.aikariStats.version = "unknown"; + } + ); + }; + + setTimeout(() => { + onSetup(); + }, 1500); +})(); diff --git a/src/aura/ui/js/plsListener.js b/src/aura/ui/js/aikariListener.js old mode 100755 new mode 100644 similarity index 71% rename from src/aura/ui/js/plsListener.js rename to src/aura/ui/js/aikariListener.js index 9cf5ad5..88057b8 --- a/src/aura/ui/js/plsListener.js +++ b/src/aura/ui/js/aikariListener.js @@ -1,21 +1,21 @@ (() => { - const IPC_METHOD_BASE = "$aura.pls"; + const IPC_METHOD_BASE = "$aura.aikari"; const REQUIRE_BASE = "../../aura/ui"; const __SCOPE = "assistant"; const { - updatePlsStatusFromLocal, - } = require(`${REQUIRE_BASE}/composables/plsConfigManager`); + updateAikariStatusFromLocal, + } = require(`${REQUIRE_BASE}/composables/aikariConfigManager`); const setupListeners = () => { if (!global.ipcRenderer) global.ipcRenderer = require("electron").ipcRenderer; ipcRenderer.on( - `${IPC_METHOD_BASE}.post.onPlsStatsUpdate`, + `${IPC_METHOD_BASE}.post.onAikariStatsUpdate`, (_event, arg) => { - global.__HUGO_AURA__.plsStats = arg; + global.__HUGO_AURA__.aikariStats = arg; - const event = new CustomEvent("onPLSStatsUpdate", { + const event = new CustomEvent("onAikariStatsUpdate", { detail: { connected: arg.connected, }, @@ -35,11 +35,11 @@ ); ipcRenderer.on( - `${IPC_METHOD_BASE}.post.onPlsSettingsUpdate`, + `${IPC_METHOD_BASE}.post.onAikariSettingsUpdate`, (_event, arg) => { - global.__HUGO_AURA__.plsSettings = arg; + global.__HUGO_AURA__.aikariSettings = arg; - const event = new CustomEvent("onPLSConfigUpdate", { + const event = new CustomEvent("onAikariConfigUpdate", { detail: { path: ["root", "settings"], value: arg, @@ -60,11 +60,11 @@ ); ipcRenderer.on( - `${IPC_METHOD_BASE}.post.onPlsRulesUpdate`, + `${IPC_METHOD_BASE}.post.onAikariRulesUpdate`, (_event, arg) => { - global.__HUGO_AURA__.plsRules = arg; + global.__HUGO_AURA__.aikariRules = arg; - const event = new CustomEvent("onPLSConfigUpdate", { + const event = new CustomEvent("onAikariConfigUpdate", { detail: { path: ["root", "ruleSettings"], value: arg, @@ -87,7 +87,7 @@ ipcRenderer.on( `${IPC_METHOD_BASE}.post.updateRetryStatus`, (_event, arg) => { - const event = new CustomEvent("onPLSStatsUpdate", { + const event = new CustomEvent("onAikariStatsUpdate", { detail: { connected: arg.success, }, @@ -107,6 +107,6 @@ ); }; - updatePlsStatusFromLocal(); + updateAikariStatusFromLocal(); setupListeners(); })(); diff --git a/src/aura/ui/js/plsConnectionManager.js b/src/aura/ui/js/plsConnectionManager.js deleted file mode 100755 index 14ed7d2..0000000 --- a/src/aura/ui/js/plsConnectionManager.js +++ /dev/null @@ -1,357 +0,0 @@ -// @ts-check -(() => { - if (!global.__HUGO_AURA__) - global.__HUGO_AURA__ = { - configInit: true, - auraDir: "", - version: "", - }; - - if (!global.__HUGO_AURA__.plsStats) - global.__HUGO_AURA__.plsStats = { - installed: false, - detached: false, - connected: false, - launched: false, - status: "dead", - version: "unknown", - authToken: "", - }; - - const IPC_METHOD_BASE = "$aura.pls"; - const REQUIRE_BASE = "../../.."; - const __SCOPE = "auraWsKeepAlive"; - - const PLS_REG_PATH = "ProxyLayerServices"; - - const { pushMsgHandler } = require(`${REQUIRE_BASE}/pls/pushHandler`); - const RegistryManager = require(`${REQUIRE_BASE}/../init/shared/registryManager`); - - const registryManager = new RegistryManager(); - - /** @type {number} */ - let failedCounter = 0; - /** @type {boolean} */ - let isErrorOccurred = false; - - /** @type {number} */ - let plsPort = 22077; - /** @type {"wss" | "ws"} */ - let plsProtocol = "wss"; - - /** @type {boolean} */ - let isRetrying = false; - - /** @type {any} */ - let curSendListener = null; - - const sendRetryStatusToMain = (/** @type {Boolean} */ status) => { - global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.post.updateRetryStatus`, { - success: status, - }); - }; - - const calcFullAuthToken = (/** @type {string} */ authToken) => { - const conjToken = authToken + "AuraXAuth 0xFFFFFF NeverEnds"; - const crypto = require("crypto"); - return crypto.createHash("sha512").update(conjToken).digest("hex"); - }; - - const clearIpcListener = () => { - if (curSendListener) { - global.ipcRenderer.off( - `${IPC_METHOD_BASE}.ws.post.onReqSendMsg`, - curSendListener - ); - curSendListener = null; - } - }; - - const startConnPlsProc = async (updatedPlsStats) => { - const authTokenRet = await registryManager.readRegKey( - PLS_REG_PATH, - "AuthToken", - true - ); - if (authTokenRet.success) { - updatedPlsStats.authToken = authTokenRet.data; - // @ts-expect-error - global.__HUGO_AURA__.plsStats.authToken = authTokenRet.data; - } else { - sendRetryStatusToMain(false); - return; - } - const portRet = await registryManager.readRegKey( - PLS_REG_PATH, - "WsPort", - true - ); - if (portRet.success) { - try { - plsPort = Number(portRet.data); - } catch { - console.warn( - `[HugoAura / UI / PLS Manager] Invalid PLS port: ${portRet.data}` - ); - } - } - const protoRet = await registryManager.readRegKey( - PLS_REG_PATH, - "Protocol", - true - ); - if (protoRet.success) { - plsProtocol = protoRet.data; - } - createPlsConnection(updatedPlsStats.authToken, connectionResultCallback); - }; - - /** - * - * @param {string} authToken - * @param {any} callback - * @returns - */ - const createPlsConnection = (authToken, callback) => { - if (failedCounter >= 3) { - console.error( - `[HugoAura / UI / PLS Manager / ERROR] Failed connecting to PLS WebSocket server, please check the status of PLS process.` - ); - sendRetryStatusToMain(false); - return; - } - - const fullAuthToken = calcFullAuthToken(authToken); - - /** @type {WebSocket} */ - const plsWs = new WebSocket( - `${plsProtocol}://pls.hugoaura.local:${plsPort}/?auth=${fullAuthToken}` - ); - - plsWs.onopen = () => { - callback(true, plsWs); - }; - - plsWs.onerror = () => { - isErrorOccurred = true; - failedCounter += 1; - callback(false, plsWs); - }; - - plsWs.onclose = () => { - clearIpcListener(); - if (global.__HUGO_AURA__.plsStats) { - if (global.__HUGO_AURA__.plsStats.status === "notReady") { - if (isRetrying) { - sendRetryStatusToMain(false); - return; - } - console.warn( - "[HugoAura / UI / PLS Manager / WARN] PLS not ready, try again after 10s..." - ); - isRetrying = true; - setTimeout(async () => { - isRetrying = false; - startConnPlsProc(global.__HUGO_AURA__.plsStats); - }, 10000); - sendRetryStatusToMain(false); - return; - } - - if (global.__HUGO_AURA__.plsStats.launched === false) { - console.warn( - "[HugoAura / UI / PLS Manager / WARN] PLS stopped, closing WebSocket connection." - ); - return; - } - } - - console.error( - "[HugoAura / UI / PLS Manager / ERROR] WebSocket connection closed." - ); - if (isErrorOccurred) return; - failedCounter += 1; - callback(false, plsWs); - }; - }; - - /** - * - * @param {WebSocket} wsObj - */ - const registerSendReqListener = (wsObj) => { - clearIpcListener(); - /** - * - * @param {import("electron").IpcRendererEvent} _evt - * @param {any} arg - */ - curSendListener = (_evt, arg) => { - wsObj.send(JSON.stringify(arg)); - }; - global.ipcRenderer.on( - `${IPC_METHOD_BASE}.ws.post.onReqSendMsg`, - curSendListener - ); - }; - - /** - * - * @param {boolean} result - * @param {WebSocket} wsObj - * @returns - */ - const connectionResultCallback = (result, wsObj) => { - if (!global.__HUGO_AURA__.plsStats) return; // 😅 typescript - - global.__HUGO_AURA__.plsStats.launched = result; - global.__HUGO_AURA__.plsStats.connected = result; - global.ipcRenderer.invoke( - `${IPC_METHOD_BASE}.updatePlsStats`, - global.__HUGO_AURA__.plsStats - ); - if (!result) { - console.error( - `[HugoAura / UI / PLS Manager / ERROR] Failed connecting to PLS WebSocket server, retrying ...` - ); - createPlsConnection( - global.__HUGO_AURA__.plsStats.authToken, - connectionResultCallback - ); - return; - } - - sendRetryStatusToMain(true); - - global.__HUGO_AURA__.plsWs = wsObj; - registerSendReqListener(wsObj); - wsObj.onmessage = plsPushHandler; - }; - - /** - * - * @param {MessageEvent} event - */ - const plsPushHandler = (event) => { - try { - /** @type {Record} */ - const parsedEvent = JSON.parse(event.data); - console.debug( - "[HugoAura / UI / PLS Manager / DEBUG] Received new server message: " - ); - if (!parsedEvent.eventId) { - // Push - pushMsgHandler(parsedEvent); - } else { - // Not push - global.ipcRenderer.send( - `${IPC_METHOD_BASE}.ws.broadcastMessageRecv`, - parsedEvent - ); - } - } catch { - console.error( - "[HugoAura / UI / PLS Manager / ERROR] Failed to resolve server message: ", - event.data - ); - } - }; - - const initPlsConnection = async () => { - if (!global.__HUGO_AURA__.plsStats) return; - - if (isRetrying) { - sendRetryStatusToMain(false); - return; - } - - failedCounter = 0; - isErrorOccurred = false; - - const curPlsStats = await global.ipcRenderer.invoke( - `${IPC_METHOD_BASE}.getPlsStats` - ); - let updatedPlsStats = {}; - if ( - (curPlsStats === null || !curPlsStats.success) && - curPlsStats.status !== "downloading" - ) { - updatedPlsStats = { - installed: false, - launched: false, - detached: false, - connected: false, - version: "unknown", - status: "dead", - authToken: "66ccff0d000721114514191981023333", - }; - } else { - updatedPlsStats = curPlsStats.data; - } - - const isPlsFolderExists = ( - await global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.getPlsBinExists`) - ).data.isExists; - updatedPlsStats.installed = isPlsFolderExists; - // @ts-expect-error - global.__HUGO_AURA__.plsStats = updatedPlsStats; - console.debug( - "[HugoAura / UI / PLS Manager / DEBUG] Updated early plsStats:", - global.__HUGO_AURA__.plsStats - ); - - global.ipcRenderer.invoke( - `${IPC_METHOD_BASE}.updatePlsStats`, - updatedPlsStats - ); - - /* - if (updatedPlsStats.detached && updatedPlsStats.installed) { - */ - if (updatedPlsStats.installed) { - await startConnPlsProc(updatedPlsStats); - } else { - sendRetryStatusToMain(false); - } - - /* - global.ipcRenderer.on(`${IPC_METHOD_BASE}.post.onPlsLaunched`, (_event) => { - setTimeout(() => { - startConnPls(); - }, 5000); - }); - */ - }; - - const onSetup = () => { - if (!global.ipcRenderer) { - // @ts-ignore - global.ipcRenderer = require("electron").ipcRenderer; - } - - initPlsConnection(); - - global.ipcRenderer.on( - `${IPC_METHOD_BASE}.retryPlsConnect`, - (_evt, _arg) => { - if (!global.__HUGO_AURA__.plsStats) return; - if (global.__HUGO_AURA__.plsStats.connected) return; - initPlsConnection(); - } - ); - - global.ipcRenderer.on( - `${IPC_METHOD_BASE}.post.plsStopped`, - (_evt, _arg) => { - if (!global.__HUGO_AURA__.plsStats) return; - global.__HUGO_AURA__.plsStats.launched = false; - global.__HUGO_AURA__.plsStats.connected = false; - global.__HUGO_AURA__.plsStats.version = "unknown"; - } - ); - }; - - setTimeout(() => { - onSetup(); - }, 1500); -})(); diff --git a/src/aura/ui/pages/config/config.html b/src/aura/ui/pages/config/config.html index 22f9c8d..49bfd4c 100755 --- a/src/aura/ui/pages/config/config.html +++ b/src/aura/ui/pages/config/config.html @@ -293,14 +293,14 @@
- 重启 PLS 进程以应用设置 + 重启 Aikari 进程以应用设置
-

请重启 PLS 进程以应用修改的设置

+

请重启 Aikari 进程以应用修改的设置

已修改的配置将自动保存

diff --git a/src/aura/ui/pages/config/config.js b/src/aura/ui/pages/config/config.js index c63d4ec..7cf4d45 100755 --- a/src/aura/ui/pages/config/config.js +++ b/src/aura/ui/pages/config/config.js @@ -106,7 +106,7 @@ global.__HUGO_AURA_UI_FUNCTIONS__.config = { if (!side) { setTimeout(() => { global.__HUGO_AURA_LOADER__[ - "Aura.UI.Assistant.Config.BehaviourCtrl.PlsStatus" + "Aura.UI.Assistant.Config.BehaviourCtrl.AikariStatus" ].active = false; }, 500); } diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.css b/src/aura/ui/pages/configSubPages/behaviourCtrl/aikariStatus.css old mode 100755 new mode 100644 similarity index 74% rename from src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.css rename to src/aura/ui/pages/configSubPages/behaviourCtrl/aikariStatus.css index 4598933..d130f8f --- a/src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.css +++ b/src/aura/ui/pages/configSubPages/behaviourCtrl/aikariStatus.css @@ -1,15 +1,15 @@ -.acs-behaviour-control-pls-status-page { +.acs-behaviour-control-aikari-status-page { display: flex; flex-direction: column; justify-content: center; align-items: center; } -.acs-behaviour-control-pls-status-page p { +.acs-behaviour-control-aikari-status-page p { font-family: sans-serif; } -.acs-bc-pls-status-page-pls-description { +.acs-bc-aikari-status-page-aikari-description { margin-top: 0.5rem; max-width: 80%; opacity: 0.35; @@ -17,11 +17,11 @@ text-align: center; } -.acs-bc-pls-status-page-main-logo { - max-width: 11%; +.acs-bc-aikari-status-page-main-logo { + max-width: 15%; opacity: 0.45; - margin-top: 1.5rem; - margin-bottom: 1.5rem; + margin-top: 1rem; + margin-bottom: 1rem; } .acs-bc-psp-operations-container { @@ -133,7 +133,7 @@ margin-top: 1px; } -.acs-bc-pls-status-page-status-el { +.acs-bc-aikari-status-page-status-el { display: flex; align-items: center; width: 40%; @@ -141,17 +141,17 @@ border-bottom: 1px solid rgba(0, 0, 0, 0.25); } -.acs-bc-pls-status-page-status-el div { +.acs-bc-aikari-status-page-status-el div { display: flex; align-items: center; } -.acs-bc-pls-status-page-status-area { +.acs-bc-aikari-status-page-status-area { flex-grow: 1; justify-content: flex-end; } -.acs-bc-pls-status-page-status-area-circle { +.acs-bc-aikari-status-page-status-area-circle { height: 10px; width: 10px; border-radius: 100%; @@ -159,48 +159,48 @@ margin-top: 2px; } -.acs-bc-pls-status-page-status-area.pending - .acs-bc-pls-status-page-status-area-circle { +.acs-bc-aikari-status-page-status-area.pending + .acs-bc-aikari-status-page-status-area-circle { background-color: rgba(0, 0, 0, 0.375); } -.acs-bc-pls-status-page-status-area.pending p { +.acs-bc-aikari-status-page-status-area.pending p { opacity: 0.5; } -.acs-bc-pls-status-page-status-area.success - .acs-bc-pls-status-page-status-area-circle { +.acs-bc-aikari-status-page-status-area.success + .acs-bc-aikari-status-page-status-area-circle { background-color: rgb(0, 175, 38); } -.acs-bc-pls-status-page-status-area.success p { +.acs-bc-aikari-status-page-status-area.success p { color: rgb(0, 150, 33); } -.acs-bc-pls-status-page-status-area.failed - .acs-bc-pls-status-page-status-area-circle { +.acs-bc-aikari-status-page-status-area.failed + .acs-bc-aikari-status-page-status-area-circle { background-color: rgb(175, 0, 0); } -.acs-bc-pls-status-page-status-area.failed p { +.acs-bc-aikari-status-page-status-area.failed p { color: rgb(175, 0, 0); } -.acs-bc-pls-status-page-status-area.warning - .acs-bc-pls-status-page-status-area-circle { +.acs-bc-aikari-status-page-status-area.warning + .acs-bc-aikari-status-page-status-area-circle { background-color: rgb(212, 127, 0); } -.acs-bc-pls-status-page-status-area.warning p { +.acs-bc-aikari-status-page-status-area.warning p { color: rgb(212, 127, 0); } -.acs-bc-pls-status-page-status-area.info - .acs-bc-pls-status-page-status-area-circle { +.acs-bc-aikari-status-page-status-area.info + .acs-bc-aikari-status-page-status-area-circle { background-color: #3d78ff; } -.acs-bc-pls-status-page-status-area.info p { +.acs-bc-aikari-status-page-status-area.info p { color: #3d78ff; } diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.html b/src/aura/ui/pages/configSubPages/behaviourCtrl/aikariStatus.html old mode 100755 new mode 100644 similarity index 78% rename from src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.html rename to src/aura/ui/pages/configSubPages/behaviourCtrl/aikariStatus.html index 4c9123d..99d736a --- a/src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.html +++ b/src/aura/ui/pages/configSubPages/behaviourCtrl/aikariStatus.html @@ -1,12 +1,11 @@ -
-

- HugoAura ProxyLayerServices (Aura-PLS) 是基于 Python + MITMProxy - 实现的代理服务, 用于解密并修改希沃基础服务 (SeewoCore) 的 MQTT 数据包, - 实现行为监控、伪造上报等功能 +

+

+ HugoAura Aikari 是基于 C++ 实现的 HugoAura 特权访问服务, 集成篡改 MQTT + 数据包、冰点穿透增强等功能, 实现行为监控、伪造上报

@@ -155,61 +154,61 @@
-
+

安装状态

- +

未安装

-
+

启动状态

- +

未启动

-
+

连接状态

- +

已断开

-
+

版本

-
+

不可用

- +
-
+
diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.js b/src/aura/ui/pages/configSubPages/behaviourCtrl/aikariStatus.js old mode 100755 new mode 100644 similarity index 72% rename from src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.js rename to src/aura/ui/pages/configSubPages/behaviourCtrl/aikariStatus.js index 92f1958..3e1a6a6 --- a/src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.js +++ b/src/aura/ui/pages/configSubPages/behaviourCtrl/aikariStatus.js @@ -6,7 +6,7 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) (() => { const REQUIRE_BASE = "../../aura/ui/pages/configSubPages/behaviourCtrl"; - const IPC_METHOD_BASE = "$aura.pls"; + const IPC_METHOD_BASE = "$aura.aikari"; const lifecycleStatus = { installed: false, @@ -15,12 +15,12 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) svcRunning: false, }; - global.__HUGO_AURA_UI_REACTIVES__.subConfig.plsStatus = { + global.__HUGO_AURA_UI_REACTIVES__.subConfig.aikariStatus = { toastAutoHideTimeout: null, curDlTaskId: null, }; - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus = { + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus = { updateToast: async ( variant, title, @@ -29,17 +29,17 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) autoHide = true, hideAfter = 3000 ) => { - const toastRootEl = document.getElementById("plsStatusNotifyToast"); + const toastRootEl = document.getElementById("aikariStatusNotifyToast"); const toastHeaderEl = document.getElementById( - "plsStatusNotifyToastTitle" + "aikariStatusNotifyToastTitle" ); - const toastBodyEl = document.getElementById("plsStatusNotifyToastBody"); + const toastBodyEl = document.getElementById("aikariStatusNotifyToastBody"); const bsToastIns = bootstrap.Toast.getOrCreateInstance(toastRootEl); if (bsToastIns.isShown) { bsToastIns.hide(); const timeout = - global.__HUGO_AURA_UI_REACTIVES__.subConfig.plsStatus + global.__HUGO_AURA_UI_REACTIVES__.subConfig.aikariStatus .toastAutoHideTimeout; if (timeout) { clearTimeout(timeout); @@ -60,7 +60,7 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) bsToastIns.show(); if (autoHide && hideAfter) { - global.__HUGO_AURA_UI_REACTIVES__.subConfig.plsStatus.toastAutoHideTimeout = + global.__HUGO_AURA_UI_REACTIVES__.subConfig.aikariStatus.toastAutoHideTimeout = setTimeout(() => { bsToastIns.hide(); }, hideAfter); @@ -85,7 +85,7 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) switch (btnName) { case "Refresh": btnEl.onclick = () => { - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( "warning", "正在更新", null, @@ -93,12 +93,12 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) false, null ); - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.refreshPlsStatus(); + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.refreshAikariStatus(); }; break; case "Download": btnEl.onclick = async () => { - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.downloadPLSBin(); + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.downloadAndInstallAikariBin(); }; break; @@ -106,11 +106,11 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) // 如果后续要引入错误视觉反馈, 合并到单个 fn 反而会增加实现复杂度 case "Install": btnEl.onclick = async () => { - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateOperationBtnStatus( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateOperationBtnStatus( "Install", true ); - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( "info", "正在请求安装", null, @@ -119,12 +119,12 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) null ); const ret = await ipcRenderer.invoke( - `${IPC_METHOD_BASE}.plsLifecycleControl`, + `${IPC_METHOD_BASE}.aikariLifecycleControl`, { target: "instSvc" } ); if (ret.success) { lifecycleStatus.svcInstalled = true; - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( "success", "服务安装成功", null, @@ -133,7 +133,7 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) 2000 ); } else { - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( "error", "服务安装失败", `

${ret.errorObj}

`, @@ -142,17 +142,17 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) null ); } - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateStatusContent(); + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateStatusContent(); }; break; case "Uninstall": if (btnContent === "删除内核") { btnEl.onclick = async () => { - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateOperationBtnStatus( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateOperationBtnStatus( "Uninstall", true ); - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( "warning", "正在删除内核", null, @@ -161,20 +161,20 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) null ); const ret = await ipcRenderer.invoke( - `${IPC_METHOD_BASE}.plsLifecycleControl`, + `${IPC_METHOD_BASE}.aikariLifecycleControl`, { target: "rmBin" } ); if (ret.success) { lifecycleStatus.installed = false; lifecycleStatus.svcInstalled = false; - global.__HUGO_AURA__.plsStats.installed = false; - global.__HUGO_AURA__.plsStats.connected = false; - global.__HUGO_AURA__.plsStats.launched = false; + global.__HUGO_AURA__.aikariStats.installed = false; + global.__HUGO_AURA__.aikariStats.connected = false; + global.__HUGO_AURA__.aikariStats.launched = false; ipcRenderer.invoke( - `${IPC_METHOD_BASE}.updatePlsStats`, - global.__HUGO_AURA__.plsStats + `${IPC_METHOD_BASE}.updateAikariStatus`, + global.__HUGO_AURA__.aikariStats ); - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( "success", "内核已删除", null, @@ -183,7 +183,7 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) 2000 ); } else { - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( "error", "内核删除失败", `

@@ -194,15 +194,15 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) null ); } - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateStatusContent(); + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateStatusContent(); }; } else { btnEl.onclick = async () => { - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateOperationBtnStatus( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateOperationBtnStatus( "Uninstall", true ); - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( "info", lifecycleStatus.svcRunning ? "正在停止服务并卸载" @@ -214,11 +214,11 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) ); if (lifecycleStatus.svcRunning) { const stopRet = await ipcRenderer.invoke( - `${IPC_METHOD_BASE}.plsLifecycleControl`, + `${IPC_METHOD_BASE}.aikariLifecycleControl`, { target: "stopSvc" } ); if (!stopRet.success) { - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( "error", "服务卸载失败: 无法停止服务", `

${ @@ -227,7 +227,7 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) : "检查日志以获取详细信息" }

- 您可以尝试手动停止 PLS 服务 + 您可以尝试手动停止 Aikari 服务

`, true, false, @@ -238,12 +238,12 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) } } const ret = await ipcRenderer.invoke( - `${IPC_METHOD_BASE}.plsLifecycleControl`, + `${IPC_METHOD_BASE}.aikariLifecycleControl`, { target: "rmSvc" } ); if (ret.success) { lifecycleStatus.svcInstalled = false; - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( "success", "服务卸载成功", null, @@ -252,7 +252,7 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) 2000 ); } else { - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( "error", "服务卸载失败", "

检查日志以获取详细信息

", @@ -261,18 +261,18 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) null ); } - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateStatusContent(); + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateStatusContent(); }; } break; case "Start": btnEl.onclick = async () => { - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateOperationBtnStatus( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateOperationBtnStatus( "Start", true ); - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( "info", "正在请求启动", null, @@ -281,29 +281,29 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) null ); const ret = await ipcRenderer.invoke( - `${IPC_METHOD_BASE}.plsLifecycleControl`, + `${IPC_METHOD_BASE}.aikariLifecycleControl`, { target: "startSvc" } ); if (ret.success) { lifecycleStatus.svcRunning = true; - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateStatusContent(); - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateStatusContent(); + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( "success", - "PLS 已启动", + "Aikari 已启动", null, true, true, 2000 ); await global.__HUGO_AURA_GLOBAL__.utils.sleep(100); - await ipcRenderer.invoke(`${IPC_METHOD_BASE}.retryPlsConnect`); - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateStatusContent(); + await ipcRenderer.invoke(`${IPC_METHOD_BASE}.retryAikariConnect`); + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateStatusContent(); } else { - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateStatusContent(); - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateStatusContent(); + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( "error", - "PLS 启动失败", - "

检查 PLS 日志目录以获取详细信息

", + "Aikari 启动失败", + "

检查 Aikari 日志目录以获取详细信息

", true, false, null @@ -313,11 +313,11 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) break; case "Stop": btnEl.onclick = async () => { - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateOperationBtnStatus( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateOperationBtnStatus( "Stop", true ); - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( "info", "正在请求停止", null, @@ -326,33 +326,33 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) null ); const ret = await ipcRenderer.invoke( - `${IPC_METHOD_BASE}.plsLifecycleControl`, + `${IPC_METHOD_BASE}.aikariLifecycleControl`, { target: "stopSvc" } ); if (ret.success) { lifecycleStatus.svcRunning = false; - global.__HUGO_AURA__.plsStats.launched = false; - global.__HUGO_AURA__.plsStats.version = "unknown"; - global.__HUGO_AURA__.plsStats.status = "dead"; + global.__HUGO_AURA__.aikariStats.launched = false; + global.__HUGO_AURA__.aikariStats.version = "unknown"; + global.__HUGO_AURA__.aikariStats.status = "dead"; - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( "success", - "PLS 已停止", + "Aikari 已停止", null, true, true, 2000 ); } else { - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( "error", - "PLS 停止失败", + "Aikari 停止失败", null, true, false, null ); - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateStatusContent(); + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateStatusContent(); } }; break; @@ -364,10 +364,10 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) }, updateStatusContent: async () => { - const curPlsStats = await updatePlsStatusFromLocal(); + const curAikariStats = await updateAikariStatusFromLocal(); - if (curPlsStats.status === "downloading") { - GLOBAL_FUNCTIONS.downloadPLSBin(true); + if (curAikariStats.status === "downloading") { + GLOBAL_FUNCTIONS.downloadAndInstallAikariBin(true); } const acIdInst = "acs-bc-psp-installStatus-container"; @@ -411,9 +411,9 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) GLOBAL_FUNCTIONS.updateOperationBtnStatus("Start", true); GLOBAL_FUNCTIONS.updateOperationBtnStatus("Stop", true); } else if (lifecycleStatus.svcInstalled && lifecycleStatus.installed) { - switch (lifecycleStatus.svcRunning || curPlsStats.launched) { + switch (lifecycleStatus.svcRunning || curAikariStats.launched) { case true: - if (curPlsStats.status !== "notReady") { + if (curAikariStats.status !== "notReady") { updateStatusEl(acIdLaunch, atIdLaunch, "SUCCESS", "已启动"); GLOBAL_FUNCTIONS.updateOperationBtnStatus("Start", true); GLOBAL_FUNCTIONS.updateOperationBtnStatus("Stop", false); @@ -433,12 +433,12 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) const acIdConn = "acs-bc-psp-connStatus-container"; const atIdConn = "acs-bc-psp-connStatus-text"; - switch (curPlsStats.connected) { + switch (curAikariStats.connected) { case true: updateStatusEl(acIdConn, atIdConn, "SUCCESS", "已连接"); break; case false: - if (curPlsStats.status !== "notReady") { + if (curAikariStats.status !== "notReady") { updateStatusEl(acIdConn, atIdConn, "FAILED", "连接失败"); } else { updateStatusEl(acIdConn, atIdConn, "PENDING", "等待启动"); @@ -447,45 +447,16 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) } const versionTextEl = document.getElementById("acs-bc-psp-version-text"); - if (curPlsStats.version && curPlsStats.version !== "unknown") { - versionTextEl.textContent = "v" + curPlsStats.version; + if (curAikariStats.version && curAikariStats.version !== "unknown") { + versionTextEl.textContent = curAikariStats.version; } else { versionTextEl.textContent = "不可用" } }, - refreshPlsStatus: async (init = false) => { - const binExistsRet = await ipcRenderer.invoke( - `${IPC_METHOD_BASE}.getPlsBinExists` - ); - if (binExistsRet.success && binExistsRet.data.isExists) { - lifecycleStatus.installed = true; - global.__HUGO_AURA__.plsStats.installed = true; - ipcRenderer.invoke( - `${IPC_METHOD_BASE}.updatePlsStats`, - global.__HUGO_AURA__.plsStats - ); - } else { - lifecycleStatus.installed = false; - global.__HUGO_AURA__.plsStats.installed = false; - ipcRenderer.invoke( - `${IPC_METHOD_BASE}.updatePlsStats`, - global.__HUGO_AURA__.plsStats - ); - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( - "error", - "请下载 PLS 内核以继续", - null, - true, - true, - 3000 - ); - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateStatusContent(); - return; - } - + refreshAikariStatus: async (init = false) => { const isDetachedRet = await ipcRenderer.invoke( - `${IPC_METHOD_BASE}.plsLifecycleQuery`, + `${IPC_METHOD_BASE}.aikariLifecycleQuery`, { target: "isDetached" } ); if (isDetachedRet.success && isDetachedRet.result) { @@ -494,8 +465,37 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) lifecycleStatus.detached = false; } + const binExistsRet = await ipcRenderer.invoke( + `${IPC_METHOD_BASE}.getIfAikariBinExists` + ); + if ((binExistsRet.success && binExistsRet.data.isExists) || lifecycleStatus.detached) { + lifecycleStatus.installed = true; + global.__HUGO_AURA__.aikariStats.installed = true; + ipcRenderer.invoke( + `${IPC_METHOD_BASE}.updateAikariStatus`, + global.__HUGO_AURA__.aikariStats + ); + } else { + lifecycleStatus.installed = false; + global.__HUGO_AURA__.aikariStats.installed = false; + ipcRenderer.invoke( + `${IPC_METHOD_BASE}.updateAikariStatus`, + global.__HUGO_AURA__.aikariStats + ); + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( + "error", + "请下载 Aikari 内核以继续", + null, + true, + true, + 3000 + ); + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateStatusContent(); + return; + } + const isSvcInstalledRet = await ipcRenderer.invoke( - `${IPC_METHOD_BASE}.plsLifecycleQuery`, + `${IPC_METHOD_BASE}.aikariLifecycleQuery`, { target: "isSvcInstalled" } ); if (isSvcInstalledRet.success && isSvcInstalledRet.result) { @@ -505,7 +505,7 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) } const isSvcRunningRet = await ipcRenderer.invoke( - `${IPC_METHOD_BASE}.plsLifecycleQuery`, + `${IPC_METHOD_BASE}.aikariLifecycleQuery`, { target: "isSvcStart" } ); if (isSvcRunningRet.success && isSvcRunningRet.result) { @@ -515,16 +515,16 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) } if (init) { - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateStatusContent(); + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateStatusContent(); return; } const updateOperationBtnStatus = - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus .updateOperationBtnStatus; updateOperationBtnStatus("Refresh", true); const result = await ipcRenderer.invoke( - `${IPC_METHOD_BASE}.retryPlsConnect` + `${IPC_METHOD_BASE}.retryAikariConnect` ); if (result.success && result.status === "Retrying") { updateOperationBtnStatus("Refresh", true, "正在重连"); @@ -534,7 +534,7 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) async (_evt, arg) => { await global.__HUGO_AURA_GLOBAL__.utils.sleep(50); updateOperationBtnStatus("Refresh", false, "刷新状态"); - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( arg.success ? "success" : "error", arg.success ? "更新成功" : "连接失败", null, @@ -542,12 +542,12 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) true, 3000 ); - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateStatusContent(); + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateStatusContent(); } ); } else if (result.success && result.status === "Already") { updateOperationBtnStatus("Refresh", false, "刷新状态"); - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus.updateToast( "success", "更新成功", null, @@ -622,15 +622,15 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) } }, - downloadPLSBin: async (retrieveMode = false) => { + downloadAikariBin: async (retrieveMode = false) => { const GLOBAL_FUNCTIONS = - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus; - const CUR_CHANNEL = `${IPC_METHOD_BASE}.post.reportPlsDownloadStatus`; + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus; + const CUR_CHANNEL = `${IPC_METHOD_BASE}.post.reportAikariInstallStep`; if (!retrieveMode) { GLOBAL_FUNCTIONS.updateOperationBtnStatus("Download", true, "正在检查"); GLOBAL_FUNCTIONS.updateOperationBtnStatus("Refresh", true); - await ipcRenderer.invoke(`${IPC_METHOD_BASE}.ensurePlsInstallDir`); + await ipcRenderer.invoke(`${IPC_METHOD_BASE}.ensureAikariInstallDir`); GLOBAL_FUNCTIONS.updateToast( "info", "准备开始下载...", @@ -716,22 +716,22 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) "下载内核" ); lifecycleStatus.installed = true; - global.__HUGO_AURA__.plsStats.installed = true; + global.__HUGO_AURA__.aikariStats.installed = true; ipcRenderer.invoke( - `${IPC_METHOD_BASE}.updatePlsStats`, - global.__HUGO_AURA__.plsStats + `${IPC_METHOD_BASE}.updateAikariStatus`, + global.__HUGO_AURA__.aikariStats ); GLOBAL_FUNCTIONS.updateStatusContent(); break; case "waiting": GLOBAL_FUNCTIONS.updatePBarStatus(0, "正在连接", "normal"); if ( - !global.__HUGO_AURA_UI_REACTIVES__.subConfig.plsStatus + !global.__HUGO_AURA_UI_REACTIVES__.subConfig.aikariStatus .curDlTaskId || - global.__HUGO_AURA_UI_REACTIVES__.subConfig.plsStatus + global.__HUGO_AURA_UI_REACTIVES__.subConfig.aikariStatus .curDlTaskId !== info.id ) { - global.__HUGO_AURA_UI_REACTIVES__.subConfig.plsStatus.curDlTaskId = + global.__HUGO_AURA_UI_REACTIVES__.subConfig.aikariStatus.curDlTaskId = info.id; } break; @@ -766,7 +766,7 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) ipcRenderer.on(CUR_CHANNEL, callbackFn); - ipcRenderer.invoke(`${IPC_METHOD_BASE}.downloadPls`, { + ipcRenderer.invoke(`${IPC_METHOD_BASE}.downloadAndInstallAikari`, { channel: "stable", reportTo: "assistant", }); @@ -774,7 +774,7 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) cancelDownloadTask: async () => { const taskId = - global.__HUGO_AURA_UI_REACTIVES__.subConfig.plsStatus.curDlTaskId; + global.__HUGO_AURA_UI_REACTIVES__.subConfig.aikariStatus.curDlTaskId; if (!taskId) { GLOBAL_FUNCTIONS.updateToast( @@ -819,11 +819,11 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) }; const GLOBAL_FUNCTIONS = - global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus; + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.aikariStatus; const { - updatePlsStatusFromLocal, - } = require(`${REQUIRE_BASE}/../../../composables/plsConfigManager`); + updateAikariStatusFromLocal, + } = require(`${REQUIRE_BASE}/../../../composables/aikariConfigManager`); const initBsTooltip = () => { const tooltipTriggerList = document.querySelectorAll( @@ -845,21 +845,21 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) switch (target) { case "PENDING": areaContainerEl.className = - "acs-bc-pls-status-page-status-area pending"; + "acs-bc-aikari-status-page-status-area pending"; break; case "SUCCESS": areaContainerEl.className = - "acs-bc-pls-status-page-status-area success"; + "acs-bc-aikari-status-page-status-area success"; break; case "FAILED": - areaContainerEl.className = "acs-bc-pls-status-page-status-area failed"; + areaContainerEl.className = "acs-bc-aikari-status-page-status-area failed"; break; case "WARNING": areaContainerEl.className = - "acs-bc-pls-status-page-status-area warning"; + "acs-bc-aikari-status-page-status-area warning"; break; case "INFO": - areaContainerEl.className = "acs-bc-pls-status-page-status-area info"; + areaContainerEl.className = "acs-bc-aikari-status-page-status-area info"; break; default: return false; @@ -871,14 +871,14 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig) const onMounted = () => { initBsTooltip(); GLOBAL_FUNCTIONS.updateOperationBtnStatus("Refresh", false); - GLOBAL_FUNCTIONS.refreshPlsStatus(true); + GLOBAL_FUNCTIONS.refreshAikariStatus(true); const eventListener = () => { GLOBAL_FUNCTIONS.updateStatusContent(); }; - document.addEventListener("onPLSStatsUpdate", eventListener); + document.addEventListener("onAikariStatsUpdate", eventListener); global.__HUGO_AURA_GLOBAL__.utils.createOnLeaveEvtListener( - "onPLSStatsUpdate", + "onAikariStatsUpdate", eventListener ); }; diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.js b/src/aura/ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.js index ba3cf5f..23a8585 100755 --- a/src/aura/ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.js +++ b/src/aura/ui/pages/configSubPages/behaviourCtrl/behaviourCtrl.js @@ -10,13 +10,13 @@ const { deviceSecuritySettings } = require(`${REQUIRE_BASE}/deviceSecurity`); const { - updatePlsSettingsFromLocal, - updatePlsRulesFromLocal, - } = require(`${REQUIRE_BASE}/../../../../composables/plsConfigManager`); + updateAikariSettingsFromLocal, + updateAikariRulesFromLocal, + } = require(`${REQUIRE_BASE}/../../../../composables/aikariConfigManager`); const initStatusPage = () => { global.__HUGO_AURA_LOADER__[ - "Aura.UI.Assistant.Config.BehaviourCtrl.PlsStatus" + "Aura.UI.Assistant.Config.BehaviourCtrl.AikariStatus" ].active = true; }; @@ -33,8 +33,8 @@ }; const renderSubPages = async () => { - await updatePlsSettingsFromLocal(); - await updatePlsRulesFromLocal(); + await updateAikariSettingsFromLocal(); + await updateAikariRulesFromLocal(); initBasicSettingsPage(); initDeviceSecuritySettingsPage(); diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/basic.js b/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/basic.js index f0ed0f6..82006ab 100755 --- a/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/basic.js +++ b/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/basic.js @@ -1,8 +1,8 @@ const REQUIRE_BASE = "."; const { - updatePlsConfigToRemote, -} = require(`${REQUIRE_BASE}/../../../../composables/plsConfigManager`); + updateAikariConfigToRemote, +} = require(`${REQUIRE_BASE}/../../../../composables/aikariConfigManager`); const reusableChkFn = { checkRelativePath: () => { @@ -42,8 +42,8 @@ const basicSettings = [ reactiveVal: ["root.settings"], restart: false, reload: false, - PLSRequired: true, - restartPLS: false, + AikariRequired: true, + restartAikari: false, warning: true, warningContent: "PLS 仍会在默认端口被占用时, 自动随机端口重试", associateVal: null, @@ -51,8 +51,8 @@ const basicSettings = [ defaultValue: "", placeHolder: "输入端口号 (10000 ~ 65535)", valueGetter: () => { - if (!global.__HUGO_AURA__.plsSettings) return ""; - return global.__HUGO_AURA__.plsSettings.wsPort; + if (!global.__HUGO_AURA__.aikariSettings) return ""; + return global.__HUGO_AURA__.aikariSettings.wsPort; }, callbackFn: (newVal) => { if (newVal === "" || !newVal) @@ -63,8 +63,8 @@ const basicSettings = [ return { valid: false, hint: "请输入合法的端口号 (10000 ~ 65535)" }; } - global.__HUGO_AURA__.plsSettings.wsPort = numberNewVal; - updatePlsConfigToRemote("wsPort", numberNewVal); + global.__HUGO_AURA__.aikariSettings.wsPort = numberNewVal; + updateAikariConfigToRemote("wsPort", numberNewVal); return { valid: true }; }, }, @@ -79,8 +79,8 @@ const basicSettings = [ reactiveVal: ["root.settings"], restart: false, reload: false, - PLSRequired: true, - restartPLS: true, + AikariRequired: true, + restartAikari: true, tip: true, tipTitle: '路径相对于 "%PROGRAMDATA%\\HugoAura\\Aura-PLS\\", 使用 "/" 作为路径符', @@ -89,8 +89,8 @@ const basicSettings = [ defaultValue: "", placeHolder: "输入相对路径, 例如: config/vme50/cert.crt", valueGetter: () => { - if (!global.__HUGO_AURA__.plsSettings) return ""; - return global.__HUGO_AURA__.plsSettings.certPath; + if (!global.__HUGO_AURA__.aikariSettings) return ""; + return global.__HUGO_AURA__.aikariSettings.certPath; }, callbackFn: (newVal) => { const validate = reusableChkFn.checkRelativePath(); @@ -98,8 +98,8 @@ const basicSettings = [ return validate; } - global.__HUGO_AURA__.plsSettings.certPath = newVal; - updatePlsConfigToRemote("certPath", newVal); + global.__HUGO_AURA__.aikariSettings.certPath = newVal; + updateAikariConfigToRemote("certPath", newVal); return { valid: true }; }, }, @@ -114,8 +114,8 @@ const basicSettings = [ reactiveVal: ["root.settings"], restart: false, reload: false, - PLSRequired: true, - restartPLS: true, + AikariRequired: true, + restartAikari: true, tip: true, tipTitle: '路径相对于 "%PROGRAMDATA%\\HugoAura\\Aura-PLS\\", 使用 "/" 作为路径符', @@ -126,8 +126,8 @@ const basicSettings = [ defaultValue: "", placeHolder: "输入相对路径, 例如: config/vme50/cert.key", valueGetter: () => { - if (!global.__HUGO_AURA__.plsSettings) return ""; - return global.__HUGO_AURA__.plsSettings.keyPath; + if (!global.__HUGO_AURA__.aikariSettings) return ""; + return global.__HUGO_AURA__.aikariSettings.keyPath; }, callbackFn: (newVal) => { const validate = reusableChkFn.checkRelativePath(); @@ -135,8 +135,8 @@ const basicSettings = [ return validate; } - global.__HUGO_AURA__.plsSettings.keyPath = newVal; - updatePlsConfigToRemote("keyPath", newVal); + global.__HUGO_AURA__.aikariSettings.keyPath = newVal; + updateAikariConfigToRemote("keyPath", newVal); return { valid: true }; }, }, @@ -150,20 +150,20 @@ const basicSettings = [ reactiveVal: ["root.settings"], restart: false, reload: false, - PLSRequired: true, - restartPLS: true, + AikariRequired: true, + restartAikari: true, associateVal: null, auraIf: () => true, defaultValue: false, valueGetter: () => { - if (!global.__HUGO_AURA__.plsSettings) return ""; - return global.__HUGO_AURA__.plsSettings.regenCert; + if (!global.__HUGO_AURA__.aikariSettings) return ""; + return global.__HUGO_AURA__.aikariSettings.regenCert; }, callbackFn: (newVal) => { if (typeof newVal !== "boolean") return false; - global.__HUGO_AURA__.plsSettings.regenCert = newVal; - updatePlsConfigToRemote("regenCert", newVal); + global.__HUGO_AURA__.aikariSettings.regenCert = newVal; + updateAikariConfigToRemote("regenCert", newVal); return true; }, }, diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/deviceSecurity.js b/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/deviceSecurity.js index 455111c..e4b47ce 100755 --- a/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/deviceSecurity.js +++ b/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/deviceSecurity.js @@ -1,8 +1,8 @@ const REQUIRE_BASE = "."; const { - updatePlsConfigToRemote, -} = require(`${REQUIRE_BASE}/../../../../composables/plsConfigManager`); + updateAikariConfigToRemote, +} = require(`${REQUIRE_BASE}/../../../../composables/aikariConfigManager`); const composables = {}; @@ -21,23 +21,23 @@ const deviceSecuritySettings = [ reactiveVal: ["root.ruleSettings"], restart: false, reload: false, - PLSRequired: true, - restartPLS: false, + AikariRequired: true, + restartAikari: false, associateVal: null, auraIf: () => true, defaultValue: false, valueGetter: () => { - if (!global.__HUGO_AURA__.plsRules) return ""; - return global.__HUGO_AURA__.plsRules.client.security.uploadFreezeInfo + if (!global.__HUGO_AURA__.aikariRules) return ""; + return global.__HUGO_AURA__.aikariRules.client.security.uploadFreezeInfo .enable; }, callbackFn: (newVal) => { if (typeof newVal !== "boolean") return; - if (!global.__HUGO_AURA__.plsRules) return; + if (!global.__HUGO_AURA__.aikariRules) return; - global.__HUGO_AURA__.plsRules.client.security.uploadFreezeInfo.enable = + global.__HUGO_AURA__.aikariRules.client.security.uploadFreezeInfo.enable = newVal; - updatePlsConfigToRemote( + updateAikariConfigToRemote( "ruleSettings.client.security.uploadFreezeInfo.enable", newVal ); @@ -53,30 +53,30 @@ const deviceSecuritySettings = [ "选择一种篡改模式, 选中的磁盘范围会被上报为冻结 (不是实际行为)", restart: false, reload: false, - PLSRequired: true, - restartPLS: false, + AikariRequired: true, + restartAikari: false, reactive: true, reactiveVal: ["root.ruleSettings"], associateVal: ["ruleSettings.client.security.uploadFreezeInfo.enable"], auraIf: () => { - if (!global.__HUGO_AURA__.plsRules) return true; + if (!global.__HUGO_AURA__.aikariRules) return true; - return global.__HUGO_AURA__.plsRules.client.security.uploadFreezeInfo + return global.__HUGO_AURA__.aikariRules.client.security.uploadFreezeInfo .enable; }, defaultValue: "allFreeze", templates: ["allFreeze", "systemOnly", "exceptSecondDisk"], templateLabels: ["全部冻结", "仅系统盘", "第二磁盘除外"], valueGetter: () => { - if (!global.__HUGO_AURA__.plsRules) return; + if (!global.__HUGO_AURA__.aikariRules) return; - return global.__HUGO_AURA__.plsRules.client.security.uploadFreezeInfo + return global.__HUGO_AURA__.aikariRules.client.security.uploadFreezeInfo .rewriteMode; }, callbackFn: (newVal) => { - global.__HUGO_AURA__.plsRules.client.security.uploadFreezeInfo.rewriteMode = + global.__HUGO_AURA__.aikariRules.client.security.uploadFreezeInfo.rewriteMode = newVal; - updatePlsConfigToRemote( + updateAikariConfigToRemote( "ruleSettings.client.security.uploadFreezeInfo.rewriteMode", newVal ); diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/previews/freezeOverridePreview/freezeOverridePreview.js b/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/previews/freezeOverridePreview/freezeOverridePreview.js index 7976a50..ba6e765 100755 --- a/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/previews/freezeOverridePreview/freezeOverridePreview.js +++ b/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/previews/freezeOverridePreview/freezeOverridePreview.js @@ -148,9 +148,10 @@ )[0]; const eventListener = (_event) => { - if (!global.__HUGO_AURA__.plsRules) return; + // if (!global.__HUGO_AURA__.plsRules) return; composables.getAndUpdateDiskInfo( - global.__HUGO_AURA__.plsRules.client.security.uploadFreezeInfo + // global.__HUGO_AURA__.plsRules.client.security.uploadFreezeInfo + { enable: false } ); }; rootEl.addEventListener("onAssociateValueUpdated", eventListener); diff --git a/src/aura/ui/pages/windows/auraWsKeepAlive/index.html b/src/aura/ui/pages/windows/auraWsKeepAlive/index.html index 5689393..aa262ed 100644 --- a/src/aura/ui/pages/windows/auraWsKeepAlive/index.html +++ b/src/aura/ui/pages/windows/auraWsKeepAlive/index.html @@ -10,7 +10,7 @@ - + diff --git a/src/aura/ui/pls/routes/basic.js b/src/aura/ui/pls/routes/basic.js deleted file mode 100755 index 610efb0..0000000 --- a/src/aura/ui/pls/routes/basic.js +++ /dev/null @@ -1,48 +0,0 @@ -// @ts-check - -const IPC_METHOD_BASE = "$aura.pls"; - -/** - * - * @param {PLSPush} parsedWsMsg - * @returns - */ -const basicRouteHandler = (parsedWsMsg) => { - const target = parsedWsMsg.type.split(".").slice(-1)[0]; - switch (target) { - case "pushPlsInfo": - if (global.__HUGO_AURA__.plsStats) { - global.__HUGO_AURA__.plsStats.status = parsedWsMsg.data.status; - global.__HUGO_AURA__.plsStats.version = parsedWsMsg.data.version; - } - - global.ipcRenderer.invoke( - `${IPC_METHOD_BASE}.updatePlsStats`, - global.__HUGO_AURA__.plsStats - ); - - console.debug( - "[HugoAura / UI / PLS Routes / DEBUG] Updated plsStats basic info:", - global.__HUGO_AURA__.plsStats - ); - break; - - case "plsNotReadyError": - if (global.__HUGO_AURA__.plsStats) { - global.__HUGO_AURA__.plsStats.launched = true; - global.__HUGO_AURA__.plsStats.connected = false; - global.__HUGO_AURA__.plsStats.status = "notReady"; - } - - global.ipcRenderer.invoke( - `${IPC_METHOD_BASE}.updatePlsStats`, - global.__HUGO_AURA__.plsStats - ); - break; - default: - return false; - } - return true; -}; - -module.exports = { basicRouteHandler }; diff --git a/src/aura/ui/static/aikari_color_reversed.png b/src/aura/ui/static/aikari_color_reversed.png new file mode 100644 index 0000000000000000000000000000000000000000..e8bcf6a0a2630b3d34fc47e647118bf18776ca73 GIT binary patch literal 39590 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 >L{n=u(FAR^GiwS*vCm&Iwsqt{^;-PSWA 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 literal 0 HcmV?d00001 diff --git a/src/aura/ui/static/aura_pls.png b/src/aura/ui/static/aura_pls.png deleted file mode 100755 index d2bb2bf3da7ec11d1185ac972e0f0ca2c322c67e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21320 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 diff --git a/src/core/hook.js b/src/core/hook.js index fefbd82..32206e4 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", ], - plsUpdate: "/api/getPLSLatestVersion", + aikariUpdate: "/api/getPLSLatestVersion", auraUpdate: "/api/getAuraLatestVersion", }; global.__HUGO_AURA_API__ = __HUGO_AURA_API__;