From 6da8348b41ba6c93b57998f91d77af3a0c10ed1e Mon Sep 17 00:00:00 2001 From: Minoricew <154642983+Minoricew@users.noreply.github.com> Date: Fri, 6 Jun 2025 02:05:04 +0800 Subject: [PATCH] [Feat] Basic PLS lifecycle mgmt --- .gitignore | 53 ++- .../init/main/ipcModules/plsIpcHandler.js | 51 ++- src/aura/init/shared/default.json | 1 - src/aura/types/shared/global.d.ts | 2 + src/aura/types/shared/pls/status.d.ts | 2 + src/aura/ui/composables/plsConfigManager.js | 15 +- src/aura/ui/composables/settingsRenderer.js | 50 ++- src/aura/ui/css/form.css | 9 + src/aura/ui/hookDefinitions/assistant.js | 2 +- src/aura/ui/js/global.js | 20 + src/aura/ui/js/plsConnectionManager.js | 387 ++++++++++-------- src/aura/ui/js/plsListener.js | 58 +++ src/aura/ui/pages/config/config.html | 3 +- .../behaviourCtrl/plsStatus.css | 63 ++- .../behaviourCtrl/plsStatus.html | 85 ++++ .../configSubPages/behaviourCtrl/plsStatus.js | 165 ++++++-- .../behaviourCtrl/settings/basic.js | 36 +- src/aura/ui/pls/routes/basic.js | 8 +- 18 files changed, 739 insertions(+), 271 deletions(-) mode change 100644 => 100755 .gitignore create mode 100755 src/aura/ui/js/plsListener.js diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index 478d139..67c28fb --- a/.gitignore +++ b/.gitignore @@ -1,29 +1,24 @@ -# Dependencies - -node_modules/ -.npm -.yarn - -# ESLint Cache - -.eslintcache - -# NYC Test Output - -.nyc_output - -# Build Artifacts - -/dist -/buikd - -# dotEnv Files - -.env -.env* - -# Misc - -.DS_Store -*.log -*.bak +# SSA Defaults + +_extraResources +addons/ +app.asar/addons +app.asar/assets +app.asar/config +app.asar/node_modules +app.asar/public +app.asar/main.js +app.asar/package.json +assets/ + +autoConfiguration.json + +# NPM Packages +node_modules/ + +# OS Files +desktop.ini +.DS_Store + +# Editor Files +.vscode/ diff --git a/src/aura/init/main/ipcModules/plsIpcHandler.js b/src/aura/init/main/ipcModules/plsIpcHandler.js index bbbc5dd..638038a 100755 --- a/src/aura/init/main/ipcModules/plsIpcHandler.js +++ b/src/aura/init/main/ipcModules/plsIpcHandler.js @@ -2,6 +2,7 @@ const __SCOPE = "main"; +const os = require("os"); const fs = require("fs"); const path = require("path"); @@ -31,7 +32,7 @@ const applyPlsIpcHandler = (ipcMain) => { * @returns {{ success: boolean; data: { isExists: boolean }; error?: Error }} */ (_event, _arg) => { - const plsFolderPath = path.join(__dirname, "../../../proxy"); + const plsFolderPath = path.join("C:\\Program Files", "HugoAura PLS"); try { const result = fs.existsSync(plsFolderPath); return { @@ -52,7 +53,7 @@ const applyPlsIpcHandler = (ipcMain) => { `${methodBase}.getPlsStats`, /** * - * @returns {{ success: boolean; data: PLSStatus | null | undefined; }} + * @returns {{ success: boolean; data: import("../../../types/shared/pls/status").PLSStatus | null | undefined; }} */ (_event, _arg) => { return { @@ -67,7 +68,7 @@ const applyPlsIpcHandler = (ipcMain) => { /** * * @param {import("electron").IpcMainInvokeEvent} _event - * @param {PLSStatus} arg + * @param {import("../../../types/shared/pls/status").PLSStatus} arg * @returns */ (_event, arg) => { @@ -103,6 +104,7 @@ const applyPlsIpcHandler = (ipcMain) => { */ (_event, arg) => { global.__HUGO_AURA__.plsSettings = arg; + ipcMain.send("assistant", `${methodBase}.post.onPlsSettingsUpdate`, arg); return { success: true, }; @@ -133,6 +135,7 @@ const applyPlsIpcHandler = (ipcMain) => { */ (_event, arg) => { global.__HUGO_AURA__.plsRules = arg; + ipcMain.send("assistant", `${methodBase}.post.onPlsRulesUpdate`, arg); return { success: true, }; @@ -185,6 +188,48 @@ const applyPlsIpcHandler = (ipcMain) => { }; } ); + + ipcMain.handle( + `${methodBase}.retryPlsConnect`, + /** + * + * @param {import("electron").IpcMainInvokeEvent} _event + * @param {any} arg + * @returns {{ success: boolean, status: "Already" | "Retrying" }} + */ + (_event, arg) => { + if (global.__HUGO_AURA__.plsStats?.connected) { + return { + success: true, + status: "Already", + }; + } else { + ipcMain.send("desktopAssistant", `${methodBase}.retryPlsConnect`, arg); + + return { + success: true, + status: "Retrying", + }; + } + } + ); + + ipcMain.handle( + `${methodBase}.post.updateRetryStatus`, + + /** + * + * @param {import("electron").IpcMainInvokeEvent} _event + * @param {{ success: boolean }} arg + */ + (_event, arg) => { + ipcMain.send("assistant", `${methodBase}.post.updateRetryStatus`, arg); + + return { + success: true, + }; + } + ); }; module.exports = { applyPlsIpcHandler }; diff --git a/src/aura/init/shared/default.json b/src/aura/init/shared/default.json index 740256a..970b987 100755 --- a/src/aura/init/shared/default.json +++ b/src/aura/init/shared/default.json @@ -26,7 +26,6 @@ "enabled": true } }, - "plsToken": "66ccff0d000721114514191981023333", "auraSettings": { "settingsPasswordEnabled": false, "settingsPasswordWithSalt": "32703D292460CC9A3B867494D6AD9A8E4A3ADF0FAA4D6867BC4D412CC3927D02E47C6D0B1763BB53E57B2241C6193433561CDA09D7C48CA03983072B876F0965", diff --git a/src/aura/types/shared/global.d.ts b/src/aura/types/shared/global.d.ts index 108ba2a..fbd248c 100755 --- a/src/aura/types/shared/global.d.ts +++ b/src/aura/types/shared/global.d.ts @@ -3,6 +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"; type MainProcessOnlyVal = T; type RendererProcessOnlyVal = T; @@ -15,6 +16,7 @@ interface GlobalHugoAuraInfo { plsRules?: Record | null; plsSettings?: Record | null; plsStats?: PLSStatus | null; + plsWs?: RendererProcessOnlyVal; uiHooks?: MainProcessOnlyVal; windowHooks?: MainProcessOnlyVal; version: RendererProcessOnlyVal; diff --git a/src/aura/types/shared/pls/status.d.ts b/src/aura/types/shared/pls/status.d.ts index a1bae3f..6f710b3 100755 --- a/src/aura/types/shared/pls/status.d.ts +++ b/src/aura/types/shared/pls/status.d.ts @@ -1,3 +1,5 @@ +import { RendererProcessOnlyVal } from "../global"; + interface PLSStatus { installed: boolean; detached: boolean; diff --git a/src/aura/ui/composables/plsConfigManager.js b/src/aura/ui/composables/plsConfigManager.js index 18aa464..6560ea7 100755 --- a/src/aura/ui/composables/plsConfigManager.js +++ b/src/aura/ui/composables/plsConfigManager.js @@ -8,7 +8,7 @@ const updatePlsStatusFromLocal = async () => { const plsStatus = ( await global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.getPlsStats`) ).data; - global.__HUGO_AURA_GLOBAL__.plsStatus = plsStatus; + global.__HUGO_AURA__.plsStats = plsStatus; return plsStatus; }; @@ -16,7 +16,7 @@ const updatePlsSettingsFromLocal = async () => { const plsSettings = ( await global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.getPlsSettings`) ).data; - global.__HUGO_AURA_GLOBAL__.plsSettings = plsSettings; + global.__HUGO_AURA__.plsSettings = plsSettings; return plsSettings; }; @@ -24,7 +24,7 @@ const updatePlsRulesFromLocal = async () => { const plsRules = ( await global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.getPlsRules`) ).data; - global.__HUGO_AURA_GLOBAL__.plsRules = plsRules; + global.__HUGO_AURA__.plsRules = plsRules; return plsRules; }; @@ -49,10 +49,11 @@ const genRandomHex = () => { const updatePlsConfigToRemote = async (configKey, configValue) => { const configLevels = configKey.split("."); /** @type {Record} */ + // @ts-expect-error let localUpdateTarget = configLevels[0] === "ruleSettings" - ? global.__HUGO_AURA_GLOBAL__.plsRules - : global.__HUGO_AURA_GLOBAL__.plsSettings; + ? global.__HUGO_AURA__.plsRules + : global.__HUGO_AURA__.plsSettings; for (const level of configLevels.slice(0, -1)) { localUpdateTarget = localUpdateTarget[level]; } @@ -80,8 +81,8 @@ const updatePlsConfigToRemote = async (configKey, configValue) => { global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.ws.sendWsMessage`, data); global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.syncPlsConfig`, { - basic: global.__HUGO_AURA_GLOBAL__.plsSettings, - rules: global.__HUGO_AURA_GLOBAL__.plsRules, + basic: global.__HUGO_AURA__.plsSettings, + rules: global.__HUGO_AURA__.plsRules, }); }; diff --git a/src/aura/ui/composables/settingsRenderer.js b/src/aura/ui/composables/settingsRenderer.js index a606972..968c995 100755 --- a/src/aura/ui/composables/settingsRenderer.js +++ b/src/aura/ui/composables/settingsRenderer.js @@ -22,7 +22,7 @@ const showRelaunchPLSToast = () => { const toast = document.getElementById("relaunchPlsNotifyToast"); const toastBs = bootstrap.Toast.getOrCreateInstance(toast); - if (global.__HUGO_AURA_GLOBAL__.plsStatus.detached) { + if (global.__HUGO_AURA__.plsStats.detached) { const relaunchBtn = document.getElementById("plsRelaunchBtn"); relaunchBtn.disabled = true; relaunchBtn.textContent = "分离模式下无法执行"; @@ -71,6 +71,18 @@ const settingsRenderer = (pendingEl, settingsObj, isPls = false) => { powerIcon.setAttribute("data-bs-title", "需要重启 Electron 进程"); entryTitle.appendChild(powerIcon); } + if (entry.PLSRequired) { + const plsIcon = document.createElement("i"); + plsIcon.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); + } if (entry.restartPLS) { const plsIcon = document.createElement("i"); plsIcon.classList.add( @@ -217,6 +229,35 @@ const settingsRenderer = (pendingEl, settingsObj, isPls = false) => { break; } + const setDisableStatus = (el, isDisable, hint = null) => { + if (isDisable) { + el.classList.add("ase-operation-area-disabled"); + if (hint) { + el.setAttribute("data-bs-toggle", "tooltip"); + el.setAttribute("data-bs-placement", "top"); + el.setAttribute("data-bs-title", hint); + } + } else { + el.setAttribute("data-bs-toggle", ""); + el.setAttribute("data-bs-placement", ""); + el.setAttribute("data-bs-title", ""); + el.classList.remove("ase-operation-area-disabled"); + } + }; + + if (entry.PLSRequired) { + if (!global.__HUGO_AURA__.plsStats.connected) { + setDisableStatus(entryOperationArea, true, "连接至 PLS 以继续"); + } + + document.addEventListener("onPLSStatsUpdate", (event) => { + if (event.detail.connected) { + setDisableStatus(entryOperationArea, false); + } else { + setDisableStatus(entryOperationArea, true, "连接至 PLS 以继续"); + } + }); + } entryContainerEl.appendChild(entryOperationArea); const isShow = entry.auraIf(); if (!isShow) entryContainerEl.classList.add("aura-settings-entry-hidden"); @@ -245,12 +286,7 @@ const settingsRenderer = (pendingEl, settingsObj, isPls = false) => { } pendingEl.appendChild(formEl); - const tooltipTriggerList = document.querySelectorAll( - '[data-bs-toggle="tooltip"]' - ); - [...tooltipTriggerList].map( - (tooltipTriggerEl) => new bootstrap.Tooltip(tooltipTriggerEl) - ); + global.__HUGO_AURA_GLOBAL__.utils.refreshBsTooltip(); }; module.exports = { settingsRenderer }; diff --git a/src/aura/ui/css/form.css b/src/aura/ui/css/form.css index f6afa93..b692f1f 100755 --- a/src/aura/ui/css/form.css +++ b/src/aura/ui/css/form.css @@ -46,6 +46,15 @@ flex: 0.75; } +.aura-settings-entry-operation-area.ase-operation-area-disabled { + opacity: 0.25; + cursor: not-allowed; +} + +.aura-settings-entry-operation-area.ase-operation-area-disabled * { + pointer-events: none; +} + .aura-settings-entry-operation-area.form-switch { transform: scale(1.2); } diff --git a/src/aura/ui/hookDefinitions/assistant.js b/src/aura/ui/hookDefinitions/assistant.js index 0173e59..7030b26 100755 --- a/src/aura/ui/hookDefinitions/assistant.js +++ b/src/aura/ui/hookDefinitions/assistant.js @@ -65,7 +65,7 @@ const def = { "ui/layui/css/layui.css", "ui/bootstrap/bootstrap.min.css", ], - globalJS: ["ui/js/global.js", "ui/bootstrap/bootstrap.bundle.min.js"], + globalJS: ["ui/js/global.js", "ui/js/plsListener.js", "ui/bootstrap/bootstrap.bundle.min.js"], onLoaded: ` console.log('[HugoAura / UI / Hooks / Assistant] Page loaded.'); `, diff --git a/src/aura/ui/js/global.js b/src/aura/ui/js/global.js index cb7f74e..bb02a08 100755 --- a/src/aura/ui/js/global.js +++ b/src/aura/ui/js/global.js @@ -1,9 +1,29 @@ (() => { + /* Util: Sleep */ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); + /* Util: BootStrap Tooltip Ctrl */ + let tooltipTriggerCache = null; + const refreshBsTooltip = () => { + if (tooltipTriggerCache) { + [...tooltipTriggerCache].map((el) => + bootstrap.Tooltip.getInstance(el).disable() + ); + } + + const tooltipTriggerList = document.querySelectorAll( + '[data-bs-toggle="tooltip"]' + ); + tooltipTriggerCache = tooltipTriggerList; + [...tooltipTriggerList].map( + (tooltipTriggerEl) => new bootstrap.Tooltip(tooltipTriggerEl) + ); + }; + if (!window.__HUGO_AURA_GLOBAL__) window.__HUGO_AURA_GLOBAL__ = {}; window.__HUGO_AURA_GLOBAL__.utils = { sleep, + refreshBsTooltip, }; })(); diff --git a/src/aura/ui/js/plsConnectionManager.js b/src/aura/ui/js/plsConnectionManager.js index 6229dc4..1a91b63 100755 --- a/src/aura/ui/js/plsConnectionManager.js +++ b/src/aura/ui/js/plsConnectionManager.js @@ -1,192 +1,233 @@ // @ts-check - -const IPC_METHOD_BASE = "$aura.pls"; -const REQUIRE_BASE = "../../aura/ui"; -const __SCOPE = "desktopAssistant"; - -const { pushMsgHandler } = require(`${REQUIRE_BASE}/pls/pushHandler`); - -/** @type {number} */ -let failedCounter = 0; -/** @type {boolean} */ -let isErrorOccurred = false; - -/** - * - * @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.` - ); - return; - } - - /** @type {WebSocket} */ - const plsWs = new WebSocket( - `wss://pls.hugoaura.local:22077/?auth=${authToken}` - ); - - plsWs.onopen = () => { - callback(true, plsWs); - }; - - plsWs.onerror = () => { - isErrorOccurred = true; - failedCounter += 1; - callback(false, plsWs); - }; - - plsWs.onclose = () => { - console.error( - "[HugoAura / UI / PLS Manager / ERROR] WebSocket connection closed." - ); - if (isErrorOccurred) return; - failedCounter += 1; - callback(false, plsWs); - }; -}; - -/** - * - * @param {WebSocket} wsObj - */ -const registerSendReqListener = (wsObj) => { - global.ipcRenderer.on( - `${IPC_METHOD_BASE}.ws.post.onReqSendMsg`, - /** - * - * @param {Event} _evt - * @param {any} arg - */ - (_evt, arg) => { - wsObj.send(JSON.stringify(arg)); - } - ); -}; - -/** - * - * @param {boolean} result - * @param {WebSocket} wsObj - * @returns - */ -const connectionResultCallback = (result, wsObj) => { - global.__HUGO_AURA_GLOBAL__.plsStats.launched = result; - global.__HUGO_AURA_GLOBAL__.plsStats.connected = result; - global.ipcRenderer.invoke( - `${IPC_METHOD_BASE}.updatePlsStats`, - global.__HUGO_AURA_GLOBAL__.plsStats - ); - if (!result) { - console.error( - `[HugoAura / UI / PLS Manager / ERROR] Failed connecting to PLS WebSocket server, retrying ...` - ); - createPlsConnection( - global.__HUGO_AURA_GLOBAL__.plsStats.authToken, - connectionResultCallback - ); - return; - } - global.__HUGO_AURA_GLOBAL__.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 () => { - failedCounter = 0; - isErrorOccurred = false; - - const curPlsStats = await global.ipcRenderer.invoke( - `${IPC_METHOD_BASE}.getPlsStats` - ); - let updatedPlsStats = {}; - if (curPlsStats === null || !curPlsStats.success) { - updatedPlsStats = { +(() => { + if (!global.__HUGO_AURA__.plsStats) + global.__HUGO_AURA__.plsStats = { installed: false, - launched: false, detached: false, connected: false, + launched: false, + status: "unknown", version: "未知", - status: "dead", - authToken: "66ccff0d000721114514191981023333", + authToken: "", }; - } else { - updatedPlsStats = curPlsStats.data; - } - const isPlsFolderExists = ( - await global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.getPlsFolderExists`) - ).data.isExists; - updatedPlsStats.installed = isPlsFolderExists; + const IPC_METHOD_BASE = "$aura.pls"; + const REQUIRE_BASE = "../../aura/ui"; + const __SCOPE = "desktopAssistant"; - global.__HUGO_AURA_GLOBAL__.plsStats = updatedPlsStats; - console.debug( - "[HugoAura / UI / PLS Manager / DEBUG] Updated plsStats:", - global.__HUGO_AURA_GLOBAL__.plsStats - ); + const { pushMsgHandler } = require(`${REQUIRE_BASE}/pls/pushHandler`); - global.ipcRenderer.invoke( - `${IPC_METHOD_BASE}.updatePlsStats`, - updatedPlsStats - ); + /** @type {number} */ + let failedCounter = 0; + /** @type {boolean} */ + let isErrorOccurred = false; - const startConnPls = () => { - createPlsConnection(updatedPlsStats.authToken, connectionResultCallback); + const sendRetryStatusToMain = (/** @type {Boolean} */ status) => { + global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.post.updateRetryStatus`, { + success: status, + }); }; - if (updatedPlsStats.detached && updatedPlsStats.installed) { - startConnPls(); - } + /** + * + * @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; + } - global.ipcRenderer.on(`${IPC_METHOD_BASE}.post.onPlsLaunched`, (_event) => { - setTimeout(() => { + /** @type {WebSocket} */ + const plsWs = new WebSocket( + `wss://pls.hugoaura.local:22077/?auth=${authToken}` + ); + + plsWs.onopen = () => { + callback(true, plsWs); + }; + + plsWs.onerror = () => { + isErrorOccurred = true; + failedCounter += 1; + callback(false, plsWs); + }; + + plsWs.onclose = () => { + console.error( + "[HugoAura / UI / PLS Manager / ERROR] WebSocket connection closed." + ); + if (isErrorOccurred) return; + failedCounter += 1; + callback(false, plsWs); + }; + }; + + /** + * + * @param {WebSocket} wsObj + */ + const registerSendReqListener = (wsObj) => { + global.ipcRenderer.on( + `${IPC_METHOD_BASE}.ws.post.onReqSendMsg`, + /** + * + * @param {import("electron").IpcRendererEvent} _evt + * @param {any} arg + */ + (_evt, arg) => { + wsObj.send(JSON.stringify(arg)); + } + ); + }; + + /** + * + * @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; + + failedCounter = 0; + isErrorOccurred = false; + + const curPlsStats = await global.ipcRenderer.invoke( + `${IPC_METHOD_BASE}.getPlsStats` + ); + let updatedPlsStats = {}; + if (curPlsStats === null || !curPlsStats.success) { + updatedPlsStats = { + installed: false, + launched: false, + detached: false, + connected: false, + version: "未知", + status: "dead", + authToken: "66ccff0d000721114514191981023333", + }; + } else { + updatedPlsStats = curPlsStats.data; + } + + const isPlsFolderExists = ( + await global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.getPlsFolderExists`) + ).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 + ); + + const startConnPls = () => { + createPlsConnection(updatedPlsStats.authToken, connectionResultCallback); + }; + + /* + if (updatedPlsStats.detached && updatedPlsStats.installed) { + */ + if (updatedPlsStats.installed) { startConnPls(); - }, 5000); - }); -}; + } else { + sendRetryStatusToMain(false); + } -const onSetup = () => { - if (!global.global.ipcRenderer) { - // @ts-ignore - global.global.ipcRenderer = require("electron").global.ipcRenderer; - } + /* + global.ipcRenderer.on(`${IPC_METHOD_BASE}.post.onPlsLaunched`, (_event) => { + setTimeout(() => { + startConnPls(); + }, 5000); + }); + */ + }; - initPlsConnection(); -}; + const onSetup = () => { + if (!global.ipcRenderer) { + // @ts-ignore + global.ipcRenderer = require("electron").global.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(); + } + ); + }; -(() => { onSetup(); })(); diff --git a/src/aura/ui/js/plsListener.js b/src/aura/ui/js/plsListener.js new file mode 100755 index 0000000..7fe5920 --- /dev/null +++ b/src/aura/ui/js/plsListener.js @@ -0,0 +1,58 @@ +(() => { + const IPC_METHOD_BASE = "$aura.pls"; + const REQUIRE_BASE = "../../aura/ui"; + const __SCOPE = "assistant"; + const { + updatePlsStatusFromLocal, + } = require(`${REQUIRE_BASE}/composables/plsConfigManager`); + + const setupListeners = () => { + if (!global.ipcRenderer) + global.ipcRenderer = require("electron").ipcRenderer; + + ipcRenderer.on( + `${IPC_METHOD_BASE}.post.onPlsStatsUpdate`, + (_event, arg) => { + global.__HUGO_AURA__.plsStats = arg; + } + ); + + ipcRenderer.on( + `${IPC_METHOD_BASE}.post.onPlsSettingsUpdate`, + (_event, arg) => { + global.__HUGO_AURA__.plsSettings = arg; + } + ); + + ipcRenderer.on( + `${IPC_METHOD_BASE}.post.onPlsRulesUpdate`, + (_event, arg) => { + global.__HUGO_AURA__.plsRules = arg; + } + ); + + ipcRenderer.on( + `${IPC_METHOD_BASE}.post.updateRetryStatus`, + (_event, arg) => { + document.dispatchEvent( + new CustomEvent("onPLSStatsUpdate", { + detail: { + connected: arg.success, + }, + }) + ); + if ( + global.__HUGO_AURA_LOADER__["Aura.UI.Assistant.Config.BehaviourCtrl"] + .active + ) { + setTimeout(() => { + global.__HUGO_AURA_GLOBAL__.utils.refreshBsTooltip(); + }, 500); + } + } + ); + }; + + updatePlsStatusFromLocal(); + setupListeners(); +})(); diff --git a/src/aura/ui/pages/config/config.html b/src/aura/ui/pages/config/config.html index 4a7f52e..1d355c7 100755 --- a/src/aura/ui/pages/config/config.html +++ b/src/aura/ui/pages/config/config.html @@ -106,10 +106,9 @@
-
diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.css b/src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.css index bfda3c5..8ec253f 100755 --- a/src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.css +++ b/src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.css @@ -18,12 +18,73 @@ } .acs-bc-pls-status-page-main-logo { - max-width: 13.5%; + max-width: 11%; opacity: 0.45; margin-top: 1.5rem; margin-bottom: 1.5rem; } +.acs-bc-psp-operations-container { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + gap: 0.5rem; + margin-bottom: 1rem; +} + +.acs-bc-psp-operation-btn { + --svg-color: rgb(17, 140, 255); + + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + margin-left: 0.75rem; + margin-right: 0.75rem; + + transition: opacity 0.25s, color 0.5s; +} + +.acs-bc-psp-operation-btn p { + font-size: normal; + margin-left: 5px; + margin-top: -1px; + color: var(--svg-color); +} + +.acs-bc-psp-operation-btn svg { + max-width: 16px; + max-height: 16px; +} + +.acs-bc-psp-operation-btn.acs-bc-psp-o-btn-dangerous { + --svg-color: rgb(244, 8, 8); +} + +.acs-bc-psp-operation-btn[aura-disabled="true"] { + --svg-color: rgba(0, 0, 0, 0.25); +} + +.acs-bc-psp-operation-btn[aura-disabled="true"]:hover, +.acs-bc-psp-operation-btn[aura-disabled="true"]:active { + cursor: not-allowed !important; + opacity: 1 !important; +} + +.acs-bc-psp-operation-btn:hover, +.acs-bc-psp-operation-btn:active { + cursor: pointer; +} + +.acs-bc-psp-operation-btn:hover { + opacity: 0.6; +} + +.acs-bc-psp-operation-btn:active { + opacity: 0.3; +} + .acs-bc-pls-status-page-status-el { display: flex; align-items: center; diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.html b/src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.html index e7e65b4..9909eb6 100755 --- a/src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.html +++ b/src/aura/ui/pages/configSubPages/behaviourCtrl/plsStatus.html @@ -9,6 +9,91 @@ class="acs-bc-pls-status-page-main-logo" /> +
+
+ + + +

刷新状态

+
+ +
+ + + + +

下载内核

+
+ +
+ + + + + +

安装服务

+
+ +
+ + + + +

卸载服务

+
+
+

安装状态

{ const REQUIRE_BASE = "../../aura/ui/pages/configSubPages/behaviourCtrl"; const IPC_METHOD_BASE = "$aura.pls"; + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus = { + updateOperationBtnStatus: async (btnName, side, btnContent = null) => { + const btnEl = document.getElementById(`acsBcPsp-operBtn-${btnName}`); + if (!btnEl) return false; + btnEl.setAttribute("aura-disabled", side ? "true" : "false"); + if (btnContent) { + const btnPEl = btnEl.getElementsByTagName("p")[0]; + btnPEl.textContent = btnContent; + } + if (side) { + btnEl.onclick = () => {}; + } else { + switch (btnName) { + case "Refresh": + btnEl.onclick = () => + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.refreshPlsStatus(); + break; + case "Download": + break; + case "Install": + break; + case "Uninstall": + break; + default: + break; + } + } + return true; + }, + + updateStatus: async () => { + const curPlsStats = await updatePlsStatusFromLocal(); + + const acIdInst = "acs-bc-psp-installStatus-container"; + const atIdInst = "acs-bc-psp-installStatus-text"; + switch (curPlsStats.installed) { + case true: + updateStatusEl(acIdInst, atIdInst, "SUCCESS", "已安装"); + GLOBAL_FUNCTIONS.updateOperationBtnStatus("Install", false); + GLOBAL_FUNCTIONS.updateOperationBtnStatus("Uninstall", false); + break; + case false: + updateStatusEl(acIdInst, atIdInst, "PENDING", "未安装"); + GLOBAL_FUNCTIONS.updateOperationBtnStatus("Install", true); + GLOBAL_FUNCTIONS.updateOperationBtnStatus("Uninstall", true); + } + + const acIdLaunch = "acs-bc-psp-launchStatus-container"; + const atIdLaunch = "acs-bc-psp-launchStatus-text"; + switch (curPlsStats.launched) { + case true: + updateStatusEl(acIdLaunch, atIdLaunch, "SUCCESS", "已启动"); + break; + case false: + updateStatusEl(acIdLaunch, atIdLaunch, "PENDING", "未启动"); + break; + } + + const acIdConn = "acs-bc-psp-connStatus-container"; + const atIdConn = "acs-bc-psp-connStatus-text"; + switch (curPlsStats.connected) { + case true: + updateStatusEl(acIdConn, atIdConn, "SUCCESS", "已连接"); + break; + case false: + updateStatusEl(acIdConn, atIdConn, "FAILED", "连接失败"); + break; + } + + if (curPlsStats.version && curPlsStats.version !== "未知") { + const versionTextEl = document.getElementById( + "acs-bc-psp-version-text" + ); + versionTextEl.textContent = "v" + curPlsStats.version; + } + }, + + refreshPlsStatus: async () => { + const updateOperationBtnStatus = + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus + .updateOperationBtnStatus; + updateOperationBtnStatus("Refresh", true); + const result = await ipcRenderer.invoke( + `${IPC_METHOD_BASE}.retryPlsConnect` + ); + if (result.success && result.status === "Retrying") { + updateOperationBtnStatus("Refresh", true, "正在重连"); + + ipcRenderer.once( + `${IPC_METHOD_BASE}.post.updateRetryStatus`, + async (_evt, _arg) => { + await global.__HUGO_AURA_GLOBAL__.utils.sleep(50); + updateOperationBtnStatus("Refresh", false, "刷新状态"); + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateStatus(); + } + ); + } else if (result.success && result.status === "Already") { + updateOperationBtnStatus("Refresh", false, "刷新状态"); + } + }, + }; + + const GLOBAL_FUNCTIONS = + global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus; + const { updatePlsStatusFromLocal, } = require(`${REQUIRE_BASE}/../../../composables/plsConfigManager`); + const initBsTooltip = () => { + const tooltipTriggerList = document.querySelectorAll( + '[data-bs-toggle="tooltip"]' + ); + const _tooltipList = [...tooltipTriggerList].map( + (tooltipTriggerEl) => new bootstrap.Tooltip(tooltipTriggerEl) + ); + }; + const updateStatusEl = ( areaContainerId, areaTextId, @@ -37,49 +154,13 @@ return true; }; - const updateStatus = async () => { - const curPlsStats = await updatePlsStatusFromLocal(); - - const acIdInst = "acs-bc-psp-installStatus-container"; - const atIdInst = "acs-bc-psp-installStatus-text"; - switch (curPlsStats.installed) { - case true: - updateStatusEl(acIdInst, atIdInst, "SUCCESS", "已安装"); - break; - case false: - updateStatusEl(acIdInst, atIdInst, "PENDING", "未安装"); - } - - const acIdLaunch = "acs-bc-psp-launchStatus-container"; - const atIdLaunch = "acs-bc-psp-launchStatus-text"; - switch (curPlsStats.launched) { - case true: - updateStatusEl(acIdLaunch, atIdLaunch, "SUCCESS", "已启动"); - break; - case false: - updateStatusEl(acIdLaunch, atIdLaunch, "PENDING", "未启动"); - break; - } - - const acIdConn = "acs-bc-psp-connStatus-container"; - const atIdConn = "acs-bc-psp-connStatus-text"; - switch (curPlsStats.connected) { - case true: - updateStatusEl(acIdConn, atIdConn, "SUCCESS", "已连接"); - break; - case false: - updateStatusEl(acIdConn, atIdConn, "FAILED", "连接失败"); - break; - } - - if (curPlsStats.version && curPlsStats.version !== "未知") { - const versionTextEl = document.getElementById("acs-bc-psp-version-text"); - versionTextEl.textContent = "v" + curPlsStats.version; - } - }; - const onMounted = () => { - updateStatus(); + GLOBAL_FUNCTIONS.updateOperationBtnStatus("Refresh", false); + initBsTooltip(); + GLOBAL_FUNCTIONS.updateStatus(); + document.addEventListener("onPLSStatsUpdate", () => { + GLOBAL_FUNCTIONS.updateStatus(); + }); }; onMounted(); diff --git a/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/basic.js b/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/basic.js index d1baa92..812e887 100755 --- a/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/basic.js +++ b/src/aura/ui/pages/configSubPages/behaviourCtrl/settings/basic.js @@ -9,6 +9,7 @@ const basicSettings = [ id: 0, categoryName: "可访问性", child: [ + /* { index: 0, id: "authToken", @@ -18,7 +19,7 @@ const basicSettings = [ description: "选择一个安全的密钥, 用于 PLS 侧验证 Aura 前端身份", restart: true, reload: false, - restartPLS: false, + restartPLS: true, associateVal: null, auraIf: () => true, defaultValue: "", @@ -38,6 +39,39 @@ const basicSettings = [ return { valid: true }; }, }, + */ + { + index: 0, + id: "plsListenPort", + type: "input", + subType: "text", + name: "PLS WS 监听端口", + description: "PLS 的 WebSocket 服务器将监听指定的端口", + restart: false, + reload: false, + PLSRequired: true, + restartPLS: true, + associateVal: null, + auraIf: () => true, + defaultValue: "", + placeHolder: "输入端口号 (10000 ~ 65535)", + valueGetter: () => { + if (!global.__HUGO_AURA__.plsSettings) return ""; + return global.__HUGO_AURA__.plsSettings.wsPort; + }, + callbackFn: (newVal) => { + if (newVal === "" || !newVal) + return { valid: false, hint: "请输入端口号" }; + + const numberNewVal = Number(newVal); + if (numberNewVal === NaN || !(10000 <= numberNewVal <= 65535)) { + return { valid: false, hint: "请输入合法的端口号 (10000 ~ 65535)" }; + } + + global.__HUGO_AURA__.plsSettings.wsPort = numberNewVal; + return { valid: true }; + }, + }, ], }, ]; diff --git a/src/aura/ui/pls/routes/basic.js b/src/aura/ui/pls/routes/basic.js index ffdf4be..acd70e8 100755 --- a/src/aura/ui/pls/routes/basic.js +++ b/src/aura/ui/pls/routes/basic.js @@ -11,17 +11,17 @@ const basicRouteHandler = (parsedWsMsg) => { const target = parsedWsMsg.type.split(".").slice(-1)[0]; switch (target) { case "pushPlsInfo": - global.__HUGO_AURA_GLOBAL__.plsStats.status = parsedWsMsg.data.status; - global.__HUGO_AURA_GLOBAL__.plsStats.version = parsedWsMsg.data.version; + 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_GLOBAL__.plsStats + global.__HUGO_AURA__.plsStats ); console.debug( "[HugoAura / UI / PLS Routes / DEBUG] Updated plsStats basic info:", - global.__HUGO_AURA_GLOBAL__.plsStats + global.__HUGO_AURA__.plsStats ); break; default: