7 Commits

Author SHA1 Message Date
Minoricew
e63c989d88 [🚧 Fix] Infrastructure logic errors
1. [/] 修复了 Header Icon 默认样式为 Hidden, 导致 UI Loader 尝试 Revive 后 Header Icon 消失的异常。
2. [/] 修正了一个 PLS 连接逻辑错误 (未正确处理更新 `installed` 参数的时机)。
3. [/] 修正了冰点上报拦截预览视图中, 未正确判断状态码导致的异常。
2025-06-13 22:26:36 +08:00
Minoricew
70ffa3f581 [ Feat] <Settings UI> Support custom access methods
1. [/] 修复了 PLS 下载时, 目录未递归创建导致的 ENOENT 错误。
2. [+] 现在可以通过多种方式访问 Aura 设置 UI 了, 更多详细信息, 请参见 #18。
3. [↑] 优化了 Tooltip 的渲染逻辑。
2025-06-13 16:24:10 +08:00
Minoricew
c0249693a8 [🚧 Fix] <Settings> Invalid (outdated) tip msg in pref/aura
1. [-] 删除了来自旧版本的 Tip (现在配置文件已经可以手动启 / 禁用加密了)
2025-06-13 12:12:46 +08:00
Minoricew
ca5d94ebd8 [🚧 Fix] <PLS & FS> Improve PLS download logic & UX
1. [+] 增加了 PLS 下载操作的取消功能
2. [/] 修复了 FS IPC 中 `downloadFile` 时, 过早地从 downloadTasks 中删除任务的逻辑错误。
3. [↑] 改进了 PLS IPC 中 `handlePLSDownload` 获取版本信息时的逻辑, 现在该函数会从全局 API 信息中逐个尝试 API 域名。减少了极端网络环境下, 版本信息获取失败的可能性。
4. [/] 修复了下载失败后, 下载按钮依然保持灰显的问题。
5. [+] 为 PLS 下载增加了进度条显示。
6. [/] 优化了 `plsConnectionManager` 中一些不必要的 IPC 状态同步 (有些时候还会导致逻辑错误)。
2025-06-13 11:49:22 +08:00
Minoricew
a9d3772b51 [Fix] <PLS> More verbose logging & Change API domain 2025-06-12 20:30:13 +08:00
Minoricew
9e63a9374f [Feat] Log file auto cleanup (#15) & Improve logger experience
Co-authored-by: TianMiao <tianmiao.work@foxmail.com>
2025-06-11 17:59:57 +08:00
Minoricew
c3a70ece88 [Fix] IPC plsStats not sync 2025-06-11 17:29:28 +08:00
19 changed files with 891 additions and 190 deletions

View File

@@ -64,9 +64,12 @@ const buildIpcMain = (electron) => {
} else { } else {
const isWindowValid = global.__HUGO_AURA__.hookedWindows.has(windowKey); const isWindowValid = global.__HUGO_AURA__.hookedWindows.has(windowKey);
if (!isWindowValid) { if (!isWindowValid) {
throw new Error( console.warn(
`[HugoAura / Main / IPC / ERROR] Unknown windowKey: ${windowKey}` `[HugoAura / Main / IPC / WARN] Unknown windowKey: ${windowKey}, window may not have started yet.`
); );
return {
success: false,
};
} }
sendDataToWebContents(windowKey, channel, data); sendDataToWebContents(windowKey, channel, data);

View File

@@ -38,10 +38,13 @@ const composableFunctions = {
progressCallback(failedTemplate); progressCallback(failedTemplate);
return false; return false;
} }
if (!fs.existsSync(path.dirname(targetPath))) {
failedTemplate.message = "Path not exists"; const dirName = path.dirname(targetPath);
progressCallback(failedTemplate);
if (!fs.existsSync(dirName)) {
fs.mkdirSync(dirName, { recursive: true });
} }
const httpModuleIns = url.startsWith("https") ? nodeHttps : nodeHttp; const httpModuleIns = url.startsWith("https") ? nodeHttps : nodeHttp;
global.__HUGO_AURA__.fsTasks?.downloadTasks.set(taskId, { global.__HUGO_AURA__.fsTasks?.downloadTasks.set(taskId, {
@@ -49,6 +52,14 @@ const composableFunctions = {
cancelReq: null, cancelReq: null,
}); });
progressCallback({
id: taskId,
progress: 0,
status: "waiting",
dlUrl: url,
savePath: targetPath,
});
const fsStream = fs.createWriteStream(targetPath); const fsStream = fs.createWriteStream(targetPath);
const dlReq = httpModuleIns.get(url, (response) => { const dlReq = httpModuleIns.get(url, (response) => {
@@ -64,9 +75,12 @@ const composableFunctions = {
const totalBytes = parseInt(contentLength, 10) || 0; // No error handling 😆 const totalBytes = parseInt(contentLength, 10) || 0; // No error handling 😆
let curRecvBytes = 0; let curRecvBytes = 0;
let hasCancelled = false;
global.__HUGO_AURA__.fsTasks?.downloadTasks.set(taskId, { global.__HUGO_AURA__.fsTasks?.downloadTasks.set(taskId, {
status: "progressing", status: "progressing",
cancelReq: () => { cancelReq: () => {
hasCancelled = true;
dlReq.destroy(); dlReq.destroy();
fsStream.close(); fsStream.close();
fs.unlink(targetPath, () => {}); fs.unlink(targetPath, () => {});
@@ -102,6 +116,9 @@ const composableFunctions = {
fsStream.on("finish", () => { fsStream.on("finish", () => {
fsStream.close(); fsStream.close();
if (hasCancelled) {
return;
}
progressCallback({ progressCallback({
id: taskId, id: taskId,
progress: (100).toFixed(2), progress: (100).toFixed(2),
@@ -111,9 +128,9 @@ const composableFunctions = {
dlUrl: url, dlUrl: url,
savePath: targetPath, savePath: targetPath,
}); });
global.__HUGO_AURA__.fsTasks?.downloadTasks.delete(taskId);
}); });
global.__HUGO_AURA__.fsTasks?.downloadTasks.delete(taskId);
return true; return true;
}); });
@@ -123,6 +140,10 @@ const composableFunctions = {
failedTemplate.message = failedTemplate.message =
"Request error: Unexpected error while downloading file"; "Request error: Unexpected error while downloading file";
failedTemplate.errorObj = e; failedTemplate.errorObj = e;
console.error(
`[HugoAura / IPC / FS / ERROR] Error downloading file from ${url}, errorObj:`,
e
);
progressCallback(failedTemplate); progressCallback(failedTemplate);
global.__HUGO_AURA__.fsTasks?.downloadTasks.delete(taskId); global.__HUGO_AURA__.fsTasks?.downloadTasks.delete(taskId);
return false; return false;

View File

@@ -71,34 +71,92 @@ const functions = {
handlePLSDownload: async (channel, callbackFn, binPath) => { handlePLSDownload: async (channel, callbackFn, binPath) => {
// TODO: Channel selection // TODO: Channel selection
const apiInfo = global.__HUGO_AURA_API__; const apiInfo = global.__HUGO_AURA_API__;
let plsVersionInfo = {};
const getVerPromise = new Promise((resolve) => { const getVerPromise = new Promise(async (resolveGetVerReq) => {
// ↓ 目前 channel param 没有什么用处 // ↓ 目前 channel param 没有什么用处
nodeHttps for (const apiDomain of apiInfo.domains) {
.get( const reqPromise = new Promise((resolveHttpRequest) => {
`${apiInfo.baseUrl}${apiInfo.plsUpdate}?channel=${channel}`, nodeHttps
(rep) => { .get(
let dataChunk = ""; `${apiDomain}${apiInfo.plsUpdate}?channel=${channel}`,
rep.on("data", (chunk) => { (rep) => {
dataChunk += chunk; let dataChunk = "";
}); rep.on("data", (chunk) => {
dataChunk += chunk;
});
rep.on("end", () => { rep.on("end", () => {
resolve({ let parsedData = {};
success: true, try {
data: dataChunk, parsedData = JSON.parse(dataChunk);
} catch (e) {
callbackFn({
id: "",
progress: 0,
status: "struggling",
dlUrl: null,
savePath: null,
message: `数据解析失败, 正在尝试 API 域名 ${
apiInfo.domains[apiInfo.domains.indexOf(apiDomain) + 1]
} ...`,
errorObj: e,
});
setTimeout(() => {
resolveHttpRequest({
success: false,
errorObj: e,
});
}, 1000);
return;
}
resolveHttpRequest({
success: true,
data: parsedData,
});
return;
});
}
)
.on("error", (e) => {
callbackFn({
id: "",
progress: 0,
status: "struggling",
dlUrl: null,
savePath: null,
message: `连接失败, 正在尝试 API 域名 ${
apiInfo.domains[apiInfo.domains.indexOf(apiDomain) + 1]
} ...`,
errorObj: e,
}); });
setTimeout(() => {
resolveHttpRequest({
success: false,
errorObj: e,
});
}, 1000);
}); });
}
)
.on("error", (e) => {
resolve({
success: false,
data: null,
errorObj: e,
});
}); });
const requestResult = await reqPromise;
if (requestResult.success) {
resolveGetVerReq({
success: true,
data: requestResult.data,
});
break;
} else {
continue;
}
}
resolveGetVerReq({
success: false,
data: null,
});
}); });
const rawResInfo = await getVerPromise; const rawResInfo = await getVerPromise;
@@ -109,30 +167,12 @@ const functions = {
status: "failed", status: "failed",
dlUrl: null, dlUrl: null,
savePath: null, savePath: null,
message: "未能获取 PLS 版本信息", message: "未能获取 PLS 版本信息, 所有 API 域名均无法连接",
errorObj: rawResInfo.errorObj ? rawResInfo.errorObj : null,
}); });
return false; return false;
} }
try { const plsVersionInfo = rawResInfo.data;
plsVersionInfo = JSON.parse(rawResInfo.data);
} catch (e) {
callbackFn({
id: "",
progress: 0,
status: "failed",
dlUrl: null,
savePath: null,
message: "PLS 版本信息解析失败",
errorObj: e,
});
console.error(
"[HugoAura / IPC / PLS] Error querying PLS version info:",
e
);
return false;
}
let deviceArch = process.env.PROCESSOR_ARCHITEW6432 let deviceArch = process.env.PROCESSOR_ARCHITEW6432
? process.env.PROCESSOR_ARCHITEW6432 ? process.env.PROCESSOR_ARCHITEW6432
@@ -155,7 +195,16 @@ const functions = {
fsComposables.downloadFile( fsComposables.downloadFile(
plsVersionInfo.data.downloadUrl[deviceArch], plsVersionInfo.data.downloadUrl[deviceArch],
binPath, binPath,
callbackFn (...args) => {
if (args[0].status === "done") {
if (global.__HUGO_AURA__.plsStats) {
global.__HUGO_AURA__.plsStats.installed = true;
global.__HUGO_AURA__.plsStats.status = "dead";
}
}
callbackFn(...args);
}
); );
}, },
}; };
@@ -192,11 +241,18 @@ const applyPlsIpcHandler = (ipcMain) => {
(_event, _arg) => { (_event, _arg) => {
try { try {
const result = fs.existsSync(PLS_BIN_PATH); const result = fs.existsSync(PLS_BIN_PATH);
if (global.__HUGO_AURA__.plsStats?.status === "notInstalled") {
global.__HUGO_AURA__.plsStats.status = "dead";
}
return { return {
success: true, success: true,
data: { isExists: result }, data: { isExists: result },
}; };
} catch (e) { } catch (e) {
// @ts-expect-error
global.__HUGO_AURA__.plsStats.status = "notInstalled";
return { return {
success: false, success: false,
data: { isExists: false }, data: { isExists: false },
@@ -227,7 +283,7 @@ const applyPlsIpcHandler = (ipcMain) => {
} }
try { try {
fs.mkdirSync(PLS_INSTALL_DIR); fs.mkdirSync(PLS_INSTALL_DIR, { recursive: true });
return { return {
success: true, success: true,
data: { data: {
@@ -427,10 +483,6 @@ const applyPlsIpcHandler = (ipcMain) => {
async (_event, arg) => { async (_event, arg) => {
const logHeader = "[HugoAura / IPC / PLS] <plsLifecycleControl>"; const logHeader = "[HugoAura / IPC / PLS] <plsLifecycleControl>";
if (!global.__HUGO_AURA__.plsStats?.installed) {
return { success: false, errorObj: new Error("PLS not installed") };
}
switch (arg.target) { switch (arg.target) {
case "instSvc": case "instSvc":
return await functions.execCommand( return await functions.execCommand(
@@ -452,6 +504,10 @@ const applyPlsIpcHandler = (ipcMain) => {
success: false, success: false,
errorObj: error, errorObj: error,
}); });
console.error(
`${logHeader} Failed to remove PLS bin, error:`,
error
);
return false; return false;
} }

View File

@@ -0,0 +1,111 @@
const path = require("path");
const fs = require("fs");
const os = require("os");
const util = require("util");
/**
*
* @param {import("../aura/types/main/core").WindowName} windowName
*/
const initLogger = (windowName) => {
const logDir = path.join(os.homedir(), "Documents", "HugoAura", "logs");
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir, { recursive: true });
}
cleanupOldLogs(logDir);
const logFile = getLogFileName(logDir);
const logStream = fs.createWriteStream(logFile, { flags: "a" });
const timestamp = new Date().toISOString();
const startupMsg = `\n=== [${timestamp}] HugoAura 窗口启动: ${windowName} ===\n\n`;
logStream.write(startupMsg);
const originalConsole = {
log: console.log,
error: console.error,
warn: console.warn,
info: console.info,
debug: console.debug,
};
console.log = function (...args) {
const msg = util.format(`[LOG] <${windowName}>`, ...args) + "\n";
logStream.write(msg);
originalConsole.log.apply(console, args);
};
console.error = function (...args) {
const msg = util.format(`[ERROR] <${windowName}>`, ...args) + "\n";
logStream.write(msg);
originalConsole.error.apply(console, args);
};
console.warn = function (...args) {
const msg = util.format(`[WARN] <${windowName}>`, ...args) + "\n";
logStream.write(msg);
originalConsole.warn.apply(console, args);
};
console.info = function (...args) {
const msg = util.format(`[INFO] <${windowName}>`, ...args) + "\n";
logStream.write(msg);
originalConsole.info.apply(console, args);
};
console.debug = function (...args) {
if (!process.argv.includes("--aura-debug")) return;
const msg = util.format(`[DEBUG] <${windowName}>`, ...args) + "\n";
logStream.write(msg);
originalConsole.debug.apply(console, args);
};
process.on("uncaughtException", (err) => {
console.error("[CRITICAL] UNCAUGHT EXCEPTION:", err);
});
console.log(
"[HugoAura / Logger] Logger initialized. Log file:",
logFile
);
};
const cleanupOldLogs = (logDir) => {
try {
const files = fs.readdirSync(logDir);
const now = new Date();
const sevenDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
files.forEach((file) => {
if (file.endsWith(".log")) {
const filePath = path.join(logDir, file);
const stats = fs.statSync(filePath);
// 如果文件创建时间超过 30 天, 则删除
if (stats.birthtime < sevenDaysAgo) {
fs.unlinkSync(filePath);
console.log(
`[HugoAura / Logger / Cleanup] Cleaned log file: ${file}`
);
}
}
});
} catch (error) {
console.error("[HugoAura / Logger / Cleanup] Unexpected error occurred cleaning log file:", error);
}
};
/**
* 生成每日 Log 文件路径
* @param {string} logDir 日志目录路径
* @param {string} _windowName 窗口名称 (暂时无用)
* @returns {string} 日志文件路径
*/
const getLogFileName = (logDir, _windowName) => {
const today = new Date();
const dateStr = today.toISOString().split("T")[0]; // YYYY-MM-DD 格式
const logFileName = `HugoAura-SSA-${dateStr}.log`;
return path.join(logDir, logFileName);
};
module.exports = { initLogger };

View File

@@ -30,7 +30,14 @@
"settingsPasswordEnabled": false, "settingsPasswordEnabled": false,
"settingsPasswordWithSalt": "32703D292460CC9A3B867494D6AD9A8E4A3ADF0FAA4D6867BC4D412CC3927D02E47C6D0B1763BB53E57B2241C6193433561CDA09D7C48CA03983072B876F0965", "settingsPasswordWithSalt": "32703D292460CC9A3B867494D6AD9A8E4A3ADF0FAA4D6867BC4D412CC3927D02E47C6D0B1763BB53E57B2241C6193433561CDA09D7C48CA03983072B876F0965",
"encryptConfig": false, "encryptConfig": false,
"appearance": {} "appearance": {},
"uiAccessMethod": {
"showEntryIcon": true,
"fallbackAccessMethods": {
"hotkey": false,
"touch": false
}
}
}, },
"devTools": false "devTools": false
} }

View File

@@ -1,5 +1,5 @@
type DownloadTaskID = string; type DownloadTaskID = string;
type DownloadTaskStatus = "waiting" | "progressing" | "done" | "failed" | "cancelled"; type DownloadTaskStatus = "waiting" | "progressing" | "done" | "failed" | "cancelled" | "struggling";
interface DownloadTask { interface DownloadTask {
id: DownloadTaskID; id: DownloadTaskID;

View File

@@ -24,7 +24,7 @@ interface GlobalHugoAuraInfo {
} }
interface GlobalHugoAuraApiInfo { interface GlobalHugoAuraApiInfo {
baseUrl: string; domains: string[];
plsUpdate: string; plsUpdate: string;
auraUpdate: string; auraUpdate: string;
} }

View File

@@ -1,15 +1,28 @@
import { RendererProcessOnlyVal } from "../global"; import { RendererProcessOnlyVal } from "../global";
type PLSStatusDesc =
| "dead"
| "running"
| "notReady"
| "downloading"
| "notInstalled";
interface PLSStatus { interface PLSStatus {
installed: boolean; installed: boolean;
detached: boolean; detached: boolean;
connected: boolean; connected: boolean;
launched: boolean; launched: boolean;
status: string; status: PLSStatusDesc;
version: string; version: string;
authToken: string; authToken: string;
} }
type PLSLifecycleType = "isDetached" | "isSvcInstalled" | "isSvcStart"; type PLSLifecycleType = "isDetached" | "isSvcInstalled" | "isSvcStart";
type PLSLifecycleControlType = "instSvc" | "rmSvc" | "startSvc" | "stopSvc" | "rmBin" | "dlBin"; type PLSLifecycleControlType =
| "instSvc"
| "rmSvc"
| "startSvc"
| "stopSvc"
| "rmBin"
| "dlBin";

View File

@@ -45,6 +45,28 @@ const showToast = (entry) => {
*/ */
}; };
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);
const tooltipIns = bootstrap.Tooltip.getOrCreateInstance(el);
tooltipIns.enable();
}
} else {
el.setAttribute("data-bs-toggle", "tooltip");
el.setAttribute("data-bs-placement", "top");
el.setAttribute("data-bs-title", "None");
el.classList.remove("ase-operation-area-disabled");
const tooltipIns = bootstrap.Tooltip.getInstance(el);
if (tooltipIns) {
tooltipIns.dispose();
}
}
};
const insertOrRemoveEl = (parent, child, isInsert = true) => { const insertOrRemoveEl = (parent, child, isInsert = true) => {
if (Array.isArray(child)) { if (Array.isArray(child)) {
for (const perEl of child) { for (const perEl of child) {
@@ -71,7 +93,12 @@ const renderInputArea = (entry, operationArea, descriptionArea) => {
switchEl.checked = elValue; switchEl.checked = elValue;
switchEl.addEventListener("change", async (event) => { switchEl.addEventListener("change", async (event) => {
showToast(entry); showToast(entry);
await entry.callbackFn(event.target.checked); await entry.callbackFn(
event.target.checked,
switchEl,
operationArea,
descriptionArea
);
}); });
operationArea.classList.add("form-check", "form-switch"); operationArea.classList.add("form-check", "form-switch");
return switchEl; return switchEl;
@@ -92,7 +119,12 @@ const renderInputArea = (entry, operationArea, descriptionArea) => {
radioEl.addEventListener("change", async (event) => { radioEl.addEventListener("change", async (event) => {
if (event.target.checked) { if (event.target.checked) {
showToast(entry); showToast(entry);
await entry.callbackFn(event.target.value); await entry.callbackFn(
event.target.value,
radioEl,
operationArea,
descriptionArea
);
} }
}); });
inlineContainerEl.appendChild(radioEl); inlineContainerEl.appendChild(radioEl);
@@ -114,7 +146,12 @@ const renderInputArea = (entry, operationArea, descriptionArea) => {
inputEl.placeholder = entry.placeHolder; inputEl.placeholder = entry.placeHolder;
inputEl.id = entry.id; inputEl.id = entry.id;
inputEl.addEventListener("change", async (event) => { inputEl.addEventListener("change", async (event) => {
const result = await entry.callbackFn(event.target.value); const result = await entry.callbackFn(
event.target.value,
inputEl,
operationArea,
descriptionArea
);
const success = result.valid; const success = result.valid;
if (success) { if (success) {
showToast(entry); showToast(entry);
@@ -250,22 +287,6 @@ const renderNormalSettingsItem = (entry, formEl) => {
// createOnLeaveEvtListener(channel, evtListener); // createOnLeaveEvtListener(channel, evtListener);
} }
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 (entry.PLSRequired) {
if (!global.__HUGO_AURA__.plsStats.connected) { if (!global.__HUGO_AURA__.plsStats.connected) {
setDisableStatus(entryOperationArea, true, "连接至 PLS 以继续"); setDisableStatus(entryOperationArea, true, "连接至 PLS 以继续");
@@ -285,6 +306,19 @@ const renderNormalSettingsItem = (entry, formEl) => {
const isShow = entry.auraIf(); const isShow = entry.auraIf();
if (!isShow) entryContainerEl.classList.add("aura-settings-entry-hidden"); if (!isShow) entryContainerEl.classList.add("aura-settings-entry-hidden");
const updateDisableStatus = () => {
const isDisabledRet = entry.auraDisable();
setDisableStatus(
entryOperationArea,
isDisabledRet.value,
isDisabledRet.tooltip
);
};
if (entry.auraDisable) {
updateDisableStatus();
}
if (entry.associateVal) { if (entry.associateVal) {
const evtListener = (event) => { const evtListener = (event) => {
if (!entry.associateVal.includes(event.detail.path.join("."))) return; if (!entry.associateVal.includes(event.detail.path.join("."))) return;
@@ -293,6 +327,10 @@ const renderNormalSettingsItem = (entry, formEl) => {
isShow isShow
? cls.remove("aura-settings-entry-hidden") ? cls.remove("aura-settings-entry-hidden")
: cls.add("aura-settings-entry-hidden"); : cls.add("aura-settings-entry-hidden");
if (entry.auraDisable) {
updateDisableStatus();
}
}; };
const channel = entry.PLSRequired const channel = entry.PLSRequired
? "onPLSConfigUpdate" ? "onPLSConfigUpdate"
@@ -378,7 +416,9 @@ const settingsRenderer = (pendingEl, settingsObj) => {
} }
pendingEl.appendChild(formEl); pendingEl.appendChild(formEl);
global.__HUGO_AURA_GLOBAL__.utils.refreshBsTooltip(); global.__HUGO_AURA_GLOBAL__.utils.refreshBsTooltip(
".aura-settings-entry-property-icon"
);
}; };
module.exports = { settingsRenderer }; module.exports = { settingsRenderer };

View File

@@ -4,16 +4,14 @@
/* Util: BootStrap Tooltip Ctrl */ /* Util: BootStrap Tooltip Ctrl */
let tooltipTriggerCache = null; let tooltipTriggerCache = null;
const refreshBsTooltip = () => { const refreshBsTooltip = (selector = '[data-bs-toggle="tooltip"]') => {
if (tooltipTriggerCache) { if (tooltipTriggerCache) {
[...tooltipTriggerCache].map((el) => [...tooltipTriggerCache].map((el) =>
bootstrap.Tooltip.getInstance(el).disable() bootstrap.Tooltip.getInstance(el).disable()
); );
} }
const tooltipTriggerList = document.querySelectorAll( const tooltipTriggerList = document.querySelectorAll(selector);
'[data-bs-toggle="tooltip"]'
);
tooltipTriggerCache = tooltipTriggerList; tooltipTriggerCache = tooltipTriggerList;
[...tooltipTriggerList].map( [...tooltipTriggerList].map(
(tooltipTriggerEl) => new bootstrap.Tooltip(tooltipTriggerEl) (tooltipTriggerEl) => new bootstrap.Tooltip(tooltipTriggerEl)

View File

@@ -6,7 +6,7 @@
detached: false, detached: false,
connected: false, connected: false,
launched: false, launched: false,
status: "unknown", status: "dead",
version: "未知", version: "未知",
authToken: "", authToken: "",
}; };
@@ -259,7 +259,10 @@
`${IPC_METHOD_BASE}.getPlsStats` `${IPC_METHOD_BASE}.getPlsStats`
); );
let updatedPlsStats = {}; let updatedPlsStats = {};
if (curPlsStats === null || !curPlsStats.success) { if (
(curPlsStats === null || !curPlsStats.success) &&
curPlsStats.status !== "downloading"
) {
updatedPlsStats = { updatedPlsStats = {
installed: false, installed: false,
launched: false, launched: false,
@@ -277,7 +280,6 @@
await global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.getPlsBinExists`) await global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.getPlsBinExists`)
).data.isExists; ).data.isExists;
updatedPlsStats.installed = isPlsFolderExists; updatedPlsStats.installed = isPlsFolderExists;
// @ts-expect-error // @ts-expect-error
global.__HUGO_AURA__.plsStats = updatedPlsStats; global.__HUGO_AURA__.plsStats = updatedPlsStats;
console.debug( console.debug(
@@ -326,5 +328,7 @@
); );
}; };
onSetup(); setTimeout(() => {
onSetup();
}, 1500);
})(); })();

View File

@@ -33,6 +33,10 @@
margin-bottom: 1rem; margin-bottom: 1rem;
} }
.acs-bc-psp-operations-container.acs-bc-psp-oper-ctnr-hidden {
display: none;
}
.acs-bc-psp-operation-btn { .acs-bc-psp-operation-btn {
--svg-color: rgb(17, 140, 255); --svg-color: rgb(17, 140, 255);
@@ -85,6 +89,50 @@
opacity: 0.3; opacity: 0.3;
} }
.acs-bc-psp-download-progress-area {
display: flex;
flex-direction: column;
width: 80%;
justify-content: center;
align-items: center;
}
.acs-bc-psp-download-progress-area.acs-bc-psp-dl-pbar-hidden {
display: none;
}
.acs-bc-psp-download-progress-area .progress {
height: 2px;
width: 80%;
margin-bottom: 0.6rem;
}
.acs-bc-psp-download-progress-area .progress-bar {
transition: all 0.15s;
}
.acs-bc-psp-download-progress-area #acsBcPspDownloadPbarDesc {
opacity: 0.6;
margin-bottom: 0.25rem;
}
.acs-bc-psp-download-progress-info-area {
display: flex;
}
.acs-bc-psp-download-progress-info-area .acs-bc-psp-operation-btn {
margin-left: 1rem;
margin-bottom: 0.25rem;
}
.acs-bc-psp-download-progress-info-area .acs-bc-psp-operation-btn.hidden {
display: none;
}
.acs-bc-psp-download-progress-info-area .acs-bc-psp-operation-btn svg {
margin-top: 1px;
}
.acs-bc-pls-status-page-status-el { .acs-bc-pls-status-page-status-el {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@@ -124,6 +124,37 @@
</div> </div>
</div> </div>
<div class="acs-bc-psp-download-progress-area acs-bc-psp-dl-pbar-hidden">
<div class="progress" role="progressbar">
<div class="progress-bar" id="acsBcPspDownloadPbarEl"></div>
</div>
<div class="acs-bc-psp-download-progress-info-area">
<p id="acsBcPspDownloadPbarDesc">等待中...</p>
<div
class="acs-bc-psp-operation-btn hidden"
id="acsBcPspDownloadPbarCancelBtn"
onclick="global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.cancelDownloadTask()"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="32"
height="32"
viewBox="0 0 32 32"
>
<path
fill="var(--svg-color)"
d="M9 10.555L10.555 9L23 21.444L21.444 23z"
/>
<path
fill="var(--svg-color)"
d="M16 2A13.914 13.914 0 0 0 2 16a13.914 13.914 0 0 0 14 14a13.914 13.914 0 0 0 14-14A13.914 13.914 0 0 0 16 2m0 26a12 12 0 1 1 12-12a12.035 12.035 0 0 1-12 12"
/>
</svg>
<p>取消操作</p>
</div>
</div>
</div>
<div class="acs-bc-pls-status-page-status-el"> <div class="acs-bc-pls-status-page-status-el">
<p>安装状态</p> <p>安装状态</p>
<div <div
@@ -165,7 +196,11 @@
</div> </div>
<div class="toast-container position-fixed bottom-0 end-0 p-3"> <div class="toast-container position-fixed bottom-0 end-0 p-3">
<div id="plsStatusNotifyToast" class="acs-bc-psp-toast toast" data-bs-autohide="false"> <div
id="plsStatusNotifyToast"
class="acs-bc-psp-toast toast"
data-bs-autohide="false"
>
<div class="toast-header"> <div class="toast-header">
<strong class="me-auto" id="plsStatusNotifyToastTitle"></strong> <strong class="me-auto" id="plsStatusNotifyToastTitle"></strong>
<button <button

View File

@@ -17,6 +17,7 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig)
global.__HUGO_AURA_UI_REACTIVES__.subConfig.plsStatus = { global.__HUGO_AURA_UI_REACTIVES__.subConfig.plsStatus = {
toastAutoHideTimeout: null, toastAutoHideTimeout: null,
curDlTaskId: null,
}; };
global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus = { global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus = {
@@ -135,7 +136,7 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig)
global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast(
"error", "error",
"服务安装失败", "服务安装失败",
"<p>检查日志以获取详细信息</p>", `<p>${ret.errorObj}</p>`,
true, true,
false, false,
null null
@@ -166,6 +167,13 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig)
if (ret.success) { if (ret.success) {
lifecycleStatus.installed = false; lifecycleStatus.installed = false;
lifecycleStatus.svcInstalled = false; lifecycleStatus.svcInstalled = false;
global.__HUGO_AURA__.plsStats.installed = false;
global.__HUGO_AURA__.plsStats.connected = false;
global.__HUGO_AURA__.plsStats.launched = false;
ipcRenderer.invoke(
`${IPC_METHOD_BASE}.updatePlsStats`,
global.__HUGO_AURA__.plsStats
);
global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast(
"success", "success",
"内核已删除", "内核已删除",
@@ -178,7 +186,9 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig)
global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast(
"error", "error",
"内核删除失败", "内核删除失败",
"<p>检查日志以获取详细信息</p>", `<p>
${ret.errorObj ? ret.errorObj : "检查日志以获取详细信息"}
</p>`,
true, true,
false, false,
null null
@@ -211,7 +221,14 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig)
global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast( global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast(
"error", "error",
"服务卸载失败: 无法停止服务", "服务卸载失败: 无法停止服务",
"<p>检查日志以获取详细信息</p><p>您可以尝试手动停止 PLS 服务</p>", `<p>${
stopRet.errorObj
? stopRet.errorObj
: "检查日志以获取详细信息"
}</p>
<p>
您可以尝试手动停止 PLS 服务
</p>`,
true, true,
false, false,
null null
@@ -345,6 +362,10 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig)
updateStatusContent: async () => { updateStatusContent: async () => {
const curPlsStats = await updatePlsStatusFromLocal(); const curPlsStats = await updatePlsStatusFromLocal();
if (curPlsStats.status === "downloading") {
GLOBAL_FUNCTIONS.downloadPLSBin(true);
}
const acIdInst = "acs-bc-psp-installStatus-container"; const acIdInst = "acs-bc-psp-installStatus-container";
const atIdInst = "acs-bc-psp-installStatus-text"; const atIdInst = "acs-bc-psp-installStatus-text";
switch (lifecycleStatus.installed) { switch (lifecycleStatus.installed) {
@@ -435,8 +456,18 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig)
); );
if (binExistsRet.success && binExistsRet.data.isExists) { if (binExistsRet.success && binExistsRet.data.isExists) {
lifecycleStatus.installed = true; lifecycleStatus.installed = true;
global.__HUGO_AURA__.plsStats.installed = true;
ipcRenderer.invoke(
`${IPC_METHOD_BASE}.updatePlsStats`,
global.__HUGO_AURA__.plsStats
);
} else { } else {
lifecycleStatus.installed = false; 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( global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast(
"error", "error",
"请下载 PLS 内核以继续", "请下载 PLS 内核以继续",
@@ -523,22 +554,101 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig)
} }
}, },
downloadPLSBin: async () => { /**
*
* @param {boolean} isShow
*/
switchPBarShowStatus: (isShow) => {
const operAreaEl = document.getElementsByClassName(
"acs-bc-psp-operations-container"
)[0];
const pBarAreaEl = document.getElementsByClassName(
"acs-bc-psp-download-progress-area"
)[0];
const pBarDescEl = document.getElementById("acsBcPspDownloadPbarDesc");
const pBarSelfEl = document.getElementById("acsBcPspDownloadPbarEl");
if (isShow) {
pBarAreaEl.classList.remove("acs-bc-psp-dl-pbar-hidden");
operAreaEl.classList.add("acs-bc-psp-oper-ctnr-hidden");
pBarDescEl.textContent = "等待中...";
pBarSelfEl.style["width"] = "0";
} else {
pBarAreaEl.classList.add("acs-bc-psp-dl-pbar-hidden");
operAreaEl.classList.remove("acs-bc-psp-oper-ctnr-hidden");
}
return true;
},
updatePBarStatus: async (
progress = null,
desc = null,
type = null,
isCancelShown = null
) => {
const pBarDescEl = document.getElementById("acsBcPspDownloadPbarDesc");
const pBarSelfEl = document.getElementById("acsBcPspDownloadPbarEl");
const pBarBtnEl = document.getElementById(
"acsBcPspDownloadPbarCancelBtn"
);
if (progress) {
pBarSelfEl.style["width"] = `${progress}%`;
}
if (type) {
pBarSelfEl.classList.remove("bg-success");
pBarSelfEl.classList.remove("bg-warning");
pBarSelfEl.classList.remove("bg-danger");
if (type !== "normal") {
pBarSelfEl.classList.add(`bg-${type}`);
}
}
if (desc) {
pBarDescEl.innerHTML = desc;
}
if (isCancelShown !== null) {
if (isCancelShown) {
pBarBtnEl.classList.remove("hidden");
} else {
pBarBtnEl.classList.add("hidden");
}
}
},
downloadPLSBin: async (retrieveMode = false) => {
const GLOBAL_FUNCTIONS = const GLOBAL_FUNCTIONS =
global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus; global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus;
GLOBAL_FUNCTIONS.updateOperationBtnStatus("Download", true, "正在检查");
GLOBAL_FUNCTIONS.updateOperationBtnStatus("Refresh", true);
const CUR_CHANNEL = `${IPC_METHOD_BASE}.post.reportPlsDownloadStatus`; const CUR_CHANNEL = `${IPC_METHOD_BASE}.post.reportPlsDownloadStatus`;
await ipcRenderer.invoke(`${IPC_METHOD_BASE}.ensurePlsInstallDir`);
GLOBAL_FUNCTIONS.updateToast( if (!retrieveMode) {
"info", GLOBAL_FUNCTIONS.updateOperationBtnStatus("Download", true, "正在检查");
"准备开始下载...", GLOBAL_FUNCTIONS.updateOperationBtnStatus("Refresh", true);
null, await ipcRenderer.invoke(`${IPC_METHOD_BASE}.ensurePlsInstallDir`);
true, GLOBAL_FUNCTIONS.updateToast(
true, "info",
2000 "准备开始下载...",
); null,
GLOBAL_FUNCTIONS.updateOperationBtnStatus("Download", true, "等待下载"); true,
true,
2000
);
GLOBAL_FUNCTIONS.updateOperationBtnStatus("Download", true);
} else {
GLOBAL_FUNCTIONS.updateToast(
"info",
"正在恢复下载状态",
null,
true,
true,
2000
);
}
GLOBAL_FUNCTIONS.switchPBarShowStatus(true);
GLOBAL_FUNCTIONS.updatePBarStatus(0, "等待中...", "normal", false);
const callbackFn = (_evt, info) => { const callbackFn = (_evt, info) => {
switch (info.status) { switch (info.status) {
@@ -548,13 +658,31 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig)
"下载失败", "下载失败",
`<p>${ `<p>${
info.message ? info.message : "检查日志以获取错误信息" info.message ? info.message : "检查日志以获取错误信息"
}</p>`, }</p><p>
${info.errorObj ? info.errorObj : ""}
</p>`,
true, true,
true, true,
5000 5000
); );
GLOBAL_FUNCTIONS.updatePBarStatus(
100,
"下载时发生错误",
"danger",
false
);
setTimeout(() => {
GLOBAL_FUNCTIONS.switchPBarShowStatus(false);
}, 1000);
ipcRenderer.off(CUR_CHANNEL, callbackFn); ipcRenderer.off(CUR_CHANNEL, callbackFn);
GLOBAL_FUNCTIONS.updateOperationBtnStatus("Refresh", false); GLOBAL_FUNCTIONS.updateOperationBtnStatus("Refresh", false);
GLOBAL_FUNCTIONS.updateOperationBtnStatus(
"Download",
false,
"下载内核"
);
break; break;
case "done": case "done":
GLOBAL_FUNCTIONS.updateToast( GLOBAL_FUNCTIONS.updateToast(
@@ -565,6 +693,17 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig)
true, true,
2500 2500
); );
GLOBAL_FUNCTIONS.updatePBarStatus(
100,
"下载成功",
"success",
false
);
setTimeout(() => {
GLOBAL_FUNCTIONS.switchPBarShowStatus(false);
}, 1000);
ipcRenderer.off(CUR_CHANNEL, callbackFn); ipcRenderer.off(CUR_CHANNEL, callbackFn);
GLOBAL_FUNCTIONS.updateOperationBtnStatus("Refresh", false); GLOBAL_FUNCTIONS.updateOperationBtnStatus("Refresh", false);
GLOBAL_FUNCTIONS.updateOperationBtnStatus( GLOBAL_FUNCTIONS.updateOperationBtnStatus(
@@ -573,20 +712,49 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig)
"下载内核" "下载内核"
); );
lifecycleStatus.installed = true; lifecycleStatus.installed = true;
global.__HUGO_AURA__.plsStats.installed = true;
ipcRenderer.invoke(
`${IPC_METHOD_BASE}.updatePlsStats`,
global.__HUGO_AURA__.plsStats
);
GLOBAL_FUNCTIONS.updateStatusContent(); GLOBAL_FUNCTIONS.updateStatusContent();
break; break;
case "waiting": case "waiting":
GLOBAL_FUNCTIONS.updateOperationBtnStatus( GLOBAL_FUNCTIONS.updatePBarStatus(0, "正在连接", "normal");
"Download", if (
true, !global.__HUGO_AURA_UI_REACTIVES__.subConfig.plsStatus
"等待中..." .curDlTaskId ||
); global.__HUGO_AURA_UI_REACTIVES__.subConfig.plsStatus
.curDlTaskId !== info.id
) {
global.__HUGO_AURA_UI_REACTIVES__.subConfig.plsStatus.curDlTaskId =
info.id;
}
break; break;
case "progressing": case "progressing":
const roundProgress = Math.round(info.progress);
GLOBAL_FUNCTIONS.updatePBarStatus(
roundProgress,
`正在下载中... ${roundProgress}% (${(
info.curBytes /
1024 /
1024
).toFixed(2)}MB / ${(info.totalBytes / 1024 / 1024).toFixed(
2
)}MB)`, // POWERED BY PRETTIER
"normal",
true
);
break;
case "struggling":
GLOBAL_FUNCTIONS.updatePBarStatus(100, info.message, "warning");
break;
case "cancelled":
GLOBAL_FUNCTIONS.updateOperationBtnStatus("Refresh", false);
GLOBAL_FUNCTIONS.updateOperationBtnStatus( GLOBAL_FUNCTIONS.updateOperationBtnStatus(
"Download", "Download",
true, false,
`下载 ${Math.round(info.progress)}%` "下载内核"
); );
break; break;
} }
@@ -594,11 +762,56 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig)
ipcRenderer.on(CUR_CHANNEL, callbackFn); ipcRenderer.on(CUR_CHANNEL, callbackFn);
ipcRenderer.invoke(`$aura.pls.downloadPls`, { ipcRenderer.invoke(`${IPC_METHOD_BASE}.downloadPls`, {
channel: "stable", channel: "stable",
reportTo: "assistant", reportTo: "assistant",
}); });
}, },
cancelDownloadTask: async () => {
const taskId =
global.__HUGO_AURA_UI_REACTIVES__.subConfig.plsStatus.curDlTaskId;
if (!taskId) {
GLOBAL_FUNCTIONS.updateToast(
"error",
"操作取消失败",
"<p>未能获取当前的下载任务 ID</p>",
true,
true,
3000
);
return false;
}
const result = await ipcRenderer.invoke(
"$aura.fs.dl.cancelDownloadTask",
{ targetTaskId: taskId }
);
if (result.success) {
GLOBAL_FUNCTIONS.updateToast(
"success",
"操作取消成功",
null,
true,
true,
2000
);
GLOBAL_FUNCTIONS.switchPBarShowStatus(false);
return true;
} else {
GLOBAL_FUNCTIONS.updateToast(
"error",
"操作取消失败",
`<p>错误代码: ${result.error}</p>`,
true,
true,
3000
);
return false;
}
},
}; };
const GLOBAL_FUNCTIONS = const GLOBAL_FUNCTIONS =

View File

@@ -32,6 +32,14 @@
} }
) )
.then(async (response) => { .then(async (response) => {
if (response.status !== 200) {
resolve({
success: true,
data: null,
status: response.status
})
}
const parsedData = await response.json(); const parsedData = await response.json();
resolve({ resolve({

View File

@@ -155,6 +155,27 @@ const functions = {
return await handleExit(); return await handleExit();
}, },
getCurAccessMethodCount: () => {
const fallbackMethods =
global.__HUGO_AURA_CONFIG__.auraSettings.uiAccessMethod
.fallbackAccessMethods;
const fallbackMethodsKeys = Object.keys(fallbackMethods);
let enabledCount = 0;
for (const method of fallbackMethodsKeys) {
if (fallbackMethods[method]) {
enabledCount += 1;
}
}
if (global.__HUGO_AURA_CONFIG__.auraSettings.uiAccessMethod.showEntryIcon) {
enabledCount += 1;
}
return enabledCount;
},
}; };
const auraSettings = [ const auraSettings = [
@@ -170,8 +191,6 @@ const auraSettings = [
description: "启用后, Aura 设置 UI 需要输入密码才可访问", description: "启用后, Aura 设置 UI 需要输入密码才可访问",
restart: false, restart: false,
reload: false, reload: false,
tip: true,
tipTitle: "启用访问密码将自动加密配置文件",
associateVal: null, associateVal: null,
auraIf: () => true, auraIf: () => true,
defaultValue: false, defaultValue: false,
@@ -288,8 +307,142 @@ const auraSettings = [
}, },
{ {
id: 1, id: 1,
categoryName: "外观", categoryName: "访问方式",
child: [], child: [
{
index: 0,
id: "showEntryIcon",
type: "switch",
name: "显示 HugoAura 设置图标",
description: "控制 HugoAura 设置入口图标在管家首页的显示状态",
restart: false,
reload: true,
tip: true,
tipTitle: "禁用后, HugoAura 图标将不会出现在主页右上角",
associateVal: [
"auraSettings.uiAccessMethod.fallbackAccessMethods.hotkey",
"auraSettings.uiAccessMethod.fallbackAccessMethods.touch",
],
auraIf: () => {
return true;
},
auraDisable: () => {
const fallbackMethods =
global.__HUGO_AURA_CONFIG__.auraSettings.uiAccessMethod
.fallbackAccessMethods;
const fallbackMethodsKeys = Object.keys(fallbackMethods);
let anyEnabled = false;
for (const method of fallbackMethodsKeys) {
if (fallbackMethods[method]) {
anyEnabled = true;
break;
}
}
return {
value: !anyEnabled,
tooltip: !anyEnabled ? "至少启用一个备选访问方式" : "",
};
},
defaultValue: false,
valueGetter: () => {
return global.__HUGO_AURA_CONFIG__.auraSettings.uiAccessMethod
.showEntryIcon;
},
callbackFn: async (newVal) => {
if (typeof newVal !== "boolean") return;
global.__HUGO_AURA_CONFIG__.auraSettings.uiAccessMethod.showEntryIcon =
newVal;
},
},
{
index: 1,
id: "allowHotkeyAccess",
type: "switch",
name: "使用快捷键打开 HugoAura 设置 UI",
description:
"启用后, 在管家首页按下 Ctrl + Shift + A 以打开 HugoAura 设置",
restart: false,
reload: true,
associateVal: [
"auraSettings.uiAccessMethod.showEntryIcon",
"auraSettings.uiAccessMethod.fallbackAccessMethods.hotkey",
"auraSettings.uiAccessMethod.fallbackAccessMethods.touch",
],
auraIf: () => {
return true;
},
auraDisable: () => {
const enableCount = functions.getCurAccessMethodCount();
if (
enableCount < 2 &&
!global.__HUGO_AURA_CONFIG__.auraSettings.uiAccessMethod
.showEntryIcon &&
global.__HUGO_AURA_CONFIG__.auraSettings.uiAccessMethod
.fallbackAccessMethods.hotkey
) {
return { value: true, tooltip: "无法禁用所有访问方式" };
} else {
return { value: false };
}
},
defaultValue: false,
valueGetter: () => {
return global.__HUGO_AURA_CONFIG__.auraSettings.uiAccessMethod
.fallbackAccessMethods.hotkey;
},
callbackFn: async (newVal) => {
if (typeof newVal !== "boolean") return;
global.__HUGO_AURA_CONFIG__.auraSettings.uiAccessMethod.fallbackAccessMethods.hotkey =
newVal;
},
},
{
index: 2,
id: "allowTouchAccess",
type: "switch",
name: "使用触摸手势打开 HugoAura 设置 UI",
description:
"启用后, 在管家首页连击 7 次右上角信息栏 ( i ) 中的版本号区域以打开 HugoAura 设置",
restart: false,
reload: true,
tip: true,
tipTitle: "请在 10 秒钟内完成连击操作, 否则计时器将被重置",
associateVal: [
"auraSettings.uiAccessMethod.showEntryIcon",
"auraSettings.uiAccessMethod.fallbackAccessMethods.hotkey",
"auraSettings.uiAccessMethod.fallbackAccessMethods.touch",
],
auraIf: () => {
return true;
},
auraDisable: () => {
const enableCount = functions.getCurAccessMethodCount();
if (
enableCount < 2 &&
!global.__HUGO_AURA_CONFIG__.auraSettings.uiAccessMethod
.showEntryIcon &&
global.__HUGO_AURA_CONFIG__.auraSettings.uiAccessMethod
.fallbackAccessMethods.touch
) {
return { value: true, tooltip: "无法禁用所有访问方式" };
} else {
return { value: false };
}
},
defaultValue: false,
valueGetter: () => {
return global.__HUGO_AURA_CONFIG__.auraSettings.uiAccessMethod
.fallbackAccessMethods.touch;
},
callbackFn: async (newVal) => {
if (typeof newVal !== "boolean") return;
global.__HUGO_AURA_CONFIG__.auraSettings.uiAccessMethod.fallbackAccessMethods.touch =
newVal;
},
},
],
}, },
]; ];

View File

@@ -7,6 +7,10 @@
transition: opacity 0.25s; transition: opacity 0.25s;
} }
.aura-header-icon.aura-header-icon-hidden {
display: none;
}
.aura-header-icon:hover { .aura-header-icon:hover {
opacity: 0.75; opacity: 0.75;
} }

View File

@@ -1,5 +1,54 @@
global.__HUGO_AURA_UI_FUNCTIONS__.headerIcon = { global.__HUGO_AURA_UI_FUNCTIONS__.headerIcon = {
showAuraConfig: () => { showAuraConfig: () => {
window.__HUGO_AURA_LOADER__["Aura.UI.Assistant.Config"].active = true; if (global.__HUGO_AURA_LOADER__["Aura.UI.Assistant.Config"].active) return;
global.__HUGO_AURA_LOADER__["Aura.UI.Assistant.Config"].active = true;
}, },
}; };
(() => {
let clickCounter = 0;
let clickTimeout = null;
const onMounted = () => {
if (!global.__HUGO_AURA_CONFIG__.auraSettings.uiAccessMethod.showEntryIcon) {
const iconEl = document.getElementsByClassName("aura-header-icon")[0];
iconEl.classList.add("aura-header-icon-hidden");
}
if (
global.__HUGO_AURA_CONFIG__.auraSettings.uiAccessMethod
.fallbackAccessMethods.hotkey
) {
document.addEventListener("keydown", (event) => {
if (event.ctrlKey && event.shiftKey && event.key === "A") {
global.__HUGO_AURA_UI_FUNCTIONS__.headerIcon.showAuraConfig();
}
});
}
if (
global.__HUGO_AURA_CONFIG__.auraSettings.uiAccessMethod
.fallbackAccessMethods.touch
) {
const mesModelEl = document.getElementsByClassName(
"index__mes-modal__2hRouc6M"
)[0];
const verEl = mesModelEl.children[0];
verEl.onclick = () => {
clickCounter += 1;
if (clickCounter >= 7) {
global.__HUGO_AURA_UI_FUNCTIONS__.headerIcon.showAuraConfig();
clickCounter = 0;
if (clickTimeout) {
clearTimeout(clickTimeout);
}
}
clickTimeout = setTimeout(() => {
clickCounter = 0;
}, 10000);
};
}
};
onMounted();
})();

View File

@@ -19,9 +19,15 @@ if (!global.__HUGO_AURA__) {
if (!global.__HUGO_AURA_API__) { if (!global.__HUGO_AURA_API__) {
/** @type {import("../aura/types/shared/global").GlobalHugoAuraApiInfo} */ /** @type {import("../aura/types/shared/global").GlobalHugoAuraApiInfo} */
const __HUGO_AURA_API__ = { const __HUGO_AURA_API__ = {
baseUrl: "https://api-aura.xwx.li", domains: [
plsUpdate: "/api/v1/getPLSLatestVersion", "https://api-aura-projekts.delta.ooo",
auraUpdate: "/api/v1/getAuraLatestVersion", "https://api-aura.asaka.site",
"https://api.hugoaura.dpdns.org",
"https://api-aura-projekts.minorice.moe",
"https://api.aura.vim.moe"
],
plsUpdate: "/api/getPLSLatestVersion",
auraUpdate: "/api/getAuraLatestVersion",
}; };
global.__HUGO_AURA_API__ = __HUGO_AURA_API__; global.__HUGO_AURA_API__ = __HUGO_AURA_API__;
} }
@@ -30,11 +36,6 @@ if (!global.__HUGO_AURA_CONFIG__) {
global.__HUGO_AURA_CONFIG__ = {}; global.__HUGO_AURA_CONFIG__ = {};
} }
const fs = require("fs");
const util = require("util");
const path = require("path");
const os = require("os");
const MainProcessHooksManager = require("../aura/init/main/windowHooksManager"); const MainProcessHooksManager = require("../aura/init/main/windowHooksManager");
const RendererHooksManager = require("../aura/init/rendererHook/uiHooksManager"); const RendererHooksManager = require("../aura/init/rendererHook/uiHooksManager");
const EventBus = require("../aura/utils/eventBus"); const EventBus = require("../aura/utils/eventBus");
@@ -42,70 +43,7 @@ const NetworkHook = require("../aura/init/rendererHook/networkHook");
const ConfigManager = require("../aura/init/shared/configManager"); const ConfigManager = require("../aura/init/shared/configManager");
const { buildIpcMain } = require("../aura/init/main/ipcHandler"); const { buildIpcMain } = require("../aura/init/main/ipcHandler");
/** const { initLogger } = require("../aura/init/main/logger");
*
* @param {import("../aura/types/main/core").WindowName} windowName
*/
const initLogger = (windowName) => {
const logDir = path.join(os.homedir(), "Documents", "HugoAura", "logs");
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir, { recursive: true });
}
const logFile = path.join(
logDir,
`main-${windowName}-${new Date().toISOString().replace(/:/g, "-")}.log`
);
const logStream = fs.createWriteStream(logFile, { flags: "a" });
const originalConsole = {
log: console.log,
error: console.error,
warn: console.warn,
info: console.info,
debug: console.debug,
};
console.log = function (...args) {
const msg = util.format("[LOG] ", ...args) + "\n";
logStream.write(msg);
originalConsole.log.apply(console, args);
};
console.error = function (...args) {
const msg = util.format("[ERROR] ", ...args) + "\n";
logStream.write(msg);
originalConsole.error.apply(console, args);
};
console.warn = function (...args) {
const msg = util.format("[WARN] ", ...args) + "\n";
logStream.write(msg);
originalConsole.warn.apply(console, args);
};
console.info = function (...args) {
const msg = util.format("[INFO] ", ...args) + "\n";
logStream.write(msg);
originalConsole.info.apply(console, args);
};
console.debug = function (...args) {
if (!process.argv.includes("--aura-debug")) return;
const msg = util.format("[DEBUG] ", ...args) + "\n";
logStream.write(msg);
originalConsole.debug.apply(console, args);
};
process.on("uncaughtException", (err) => {
console.error("UNCAUGHT EXCEPTION:", err);
});
console.log(
"[HugoAura / Init / Logger] Logger initialized. Log file:",
logFile
);
};
/** /**
* *