17 Commits

Author SHA1 Message Date
Minoricew
b8f27d9f7c [ Feat / 🛠️ Fix] Auto hide desktopAssistant & Fix #26
1. [/] 修改了 Header Icon 的隐藏方式, 尝试修复 #26
2. [+] 现在可以隐藏管家助手 (桌面右下角小窗) 了
3. [⇡] Bump version to v0.1.1-beta
2025-06-20 00:45:11 +08:00
Minoricew
807ac913da [🤯 Refactor] Use standalone window for WebSocket connections
1. [-] 删除了对于 desktopAssistant 的 Hook 逻辑
2. [/] 现在不再使用 desktopAssistant 保活 WS 连接, 而是用一个单独的不可见窗口处理 WS (#25)
2025-06-17 18:14:58 +08:00
Minoricew
f6a30351fd [🛠️ Fix] Change the logic of determining isEncConfig
1. [/] 修正了识别配置文件加密状态时的逻辑错误
2025-06-17 00:50:54 +08:00
Minoricew
0494394fd8 [🛠️ Fix] Emergency fix for invalid config read logic
1. [/] 紧急修复了上个 commit 中引入的错误路径获取逻辑
2025-06-17 00:16:43 +08:00
Minoricew
6be31652f9 [🛠️ Fix] 不好意思脑子抽了 2025-06-16 21:41:07 +08:00
Minoricew
a638a29cc6 [🛠️ Fix] Invalid log dir path (#24) & Remove PLS trust token
1. [-] 删除了 PLS 的 Trust token 认证机制
2. [+] 现在可以在 `偏好设置` - `调试选项` 中直接打开日志文件夹了
3. [/] 日志目录不再使用 `%USERPROFILE%\Documents\HugoAura\logs` 为基准, 而是从注册表获取值
4. [/] 配置文件目录同理, 旧版配置文件将会自动迁移到新位置
2025-06-16 21:32:15 +08:00
Minoricew
dae0f033a5 [🔁 Chore] Add forum links into README & issue template 2025-06-16 01:02:40 +08:00
Minoricew
bd2f2e4154 [ Feat] Add AppBar buttons pos customize options
1. [+] 允许用户自定义应用栏上操作类按钮的位置
2025-06-14 18:44:34 +08:00
Minoricew
290cbfed53 [🔁 Chore] Auto upload release for workflow 2025-06-14 17:01:51 +08:00
Minoricew
9a2a335742 [ Feat] {#21} Add AppBar window oper icons
1. [+] {#21} 增加了应用栏 (顶栏) 上的窗口操作按钮
2. [-] 删掉了几个调试时留下的 console.debug
2025-06-14 16:07:10 +08:00
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
43 changed files with 1593 additions and 226 deletions

View File

@@ -16,5 +16,5 @@ body:
attributes:
label: 提交前请确认 / Confirm before submit
options:
- label: 请勿利用此 Issue 类型进行灌水 / 闲聊, 如果您有相关需求, 可留意后续 HugoAura 的论坛 / 用户讨论群开放情况
- label: 请勿利用此 Issue 类型进行闲聊 / 灌水, 如需闲聊, 可移步至 HugoAura 社区 (forum.aurax.cc)
required: true

View File

@@ -7,6 +7,8 @@ on:
branches: [dev, stable, main, master]
workflow_dispatch:
permissions: write-all
jobs:
pack:
name: Patch & Pack
@@ -123,6 +125,33 @@ jobs:
echo "[DEBUG] Files in <Working DIR>/Artifacts directory:"
ls -la Artifacts/
- name: Get commit hash & build time
run: |
cd ./HugoAura-Code
SHORT_HASH=$(git rev-parse --short=7 HEAD)
FULL_HASH=$(git rev-parse HEAD)
echo "SHORT_HASH=$SHORT_HASH" >> $GITHUB_ENV
echo "FULL_HASH=$FULL_HASH" >> $GITHUB_ENV
echo "BUILDTIME=$(TZ=Asia/Shanghai date)" >> $GITHUB_ENV
- name: Create release content
run: |
cat > rel_msg.txt << 'EOF'
## 这是 HugoAura 的 CI 自动构建版本
### 版本类型: 🔁 自动构建版
### 版本号: `vAutoBuild-${{ env.SHORT_HASH }}`
### 对应 Commit: [`${{ env.SHORT_HASH }}`](https://github.com/HugoAura/Seewo-HugoAura/commit/${{ env.FULL_HASH }})
---
### ⚠ 注意: CI 自动构建版本可能不稳定 / 存在较多 Bug, 更新时请留意
#### 🕘 构建时间: ${{ env.BUILDTIME }}
EOF
- name: Upload patched ASAR
uses: actions/upload-artifact@v4
with:
@@ -134,3 +163,16 @@ jobs:
with:
name: aura-code
path: Artifacts/aura.zip
- name: Upload release
uses: softprops/action-gh-release@v2
with:
tag_name: vAutoBuild
name: "[CI] HugoAura Auto Build Release"
body_path: rel_msg.txt
prerelease: true
generate_release_notes: false
token: ${{ secrets.GITHUB_TOKEN }}
files: |
Artifacts/app-patched.asar
Artifacts/aura.zip

View File

@@ -3,7 +3,7 @@
<h1 align="center">HugoAura</h1>
<h4 align="center">下一代希沃管家注入式修改方案</h4>
<div align="center">
<a href="https://github.com/HugoAura/HugoAura">首页</a> · <a href="https://hugoaura.org/about">关于</a> · <a href="https://github.com/HugoAura/HugoAura/wiki">文档</a> · <a href="https://github.com/HugoAura/HugoAura/issues">反馈</a>
<a href="https://github.com/HugoAura/HugoAura">首页</a> · <a href="https://hugo.aurax.cc/about">关于</a> · <a href="https://github.com/HugoAura/HugoAura/wiki">文档</a> · <a href="https://github.com/HugoAura/HugoAura/issues">反馈</a> · <a href="https://forum.aurax.cc/">社区</a>
</div>
<br />

View File

@@ -1,6 +1,6 @@
{
"name": "HugoAura",
"version": "0.1.1-pre-IV",
"version": "0.1.1-beta",
"description": "Aura for SeewoHugo",
"main": "app.asar/main.js",
"dependencies": {},

View File

@@ -64,15 +64,20 @@ const buildIpcMain = (electron) => {
} else {
const isWindowValid = global.__HUGO_AURA__.hookedWindows.has(windowKey);
if (!isWindowValid) {
throw new Error(
`[HugoAura / Main / IPC / ERROR] Unknown windowKey: ${windowKey}`
console.warn(
`[HugoAura / Main / IPC / WARN] Unknown windowKey: ${windowKey}, window may not have started yet.`
);
return {
success: false,
};
}
sendDataToWebContents(windowKey, channel, data);
}
};
const { applyBaseIpcHandler } = require("./ipcModules/baseIpcHandler");
const { applyDebugIpcHandler } = require("./ipcModules/debugIpcHandler");
const { applyConfigIpcHandler } = require("./ipcModules/configIpcHandler");
const { applyFsIpcHandler } = require("./ipcModules/fsIpcHandler");
const { applyPlsIpcHandler } = require("./ipcModules/plsIpcHandler");
@@ -82,6 +87,8 @@ const buildIpcMain = (electron) => {
app.exit(0);
});
applyBaseIpcHandler(ipcMain);
applyDebugIpcHandler(ipcMain);
applyConfigIpcHandler(ipcMain);
applyFsIpcHandler(ipcMain);
applyPlsIpcHandler(ipcMain);

View File

@@ -0,0 +1,73 @@
// @ts-check
const { BrowserWindow } = require("electron");
const composables = {
getBrowserWindowInstance: (windowKey) => {
if (!global.__HUGO_AURA__.hookedWindows) return null;
const hookedWindowIns = global.__HUGO_AURA__.hookedWindows.get(windowKey);
if (!hookedWindowIns) return undefined;
const browserWindowIns = BrowserWindow.fromWebContents(
hookedWindowIns.webContents
);
return browserWindowIns;
},
};
/**
*
* @param {import("electron").IpcMain} ipcMain
*/
const applyBaseIpcHandler = (ipcMain) => {
const methodBase = "$aura.base";
ipcMain.on(
`${methodBase}.minimizeWindow`,
/**
*
* @param {import("electron").IpcMainEvent} _event
* @param {{ targetWindowKey: string }} arg
*/
(_event, arg) => {
const browserWindowIns = composables.getBrowserWindowInstance(
arg.targetWindowKey
);
if (!browserWindowIns) return;
browserWindowIns.minimize();
}
);
ipcMain.on(
`${methodBase}.closeWindow`,
/**
*
* @param {import("electron").IpcMainEvent} _event
* @param {{ targetWindowKey: string }} arg
*/
(_event, arg) => {
const browserWindowIns = composables.getBrowserWindowInstance(
arg.targetWindowKey
);
if (!browserWindowIns) return;
browserWindowIns.close();
}
);
ipcMain.handle(`${methodBase}.getAuraDirAsync`, (_evt, _arg) => {
return {
success: true,
data: global.__HUGO_AURA__.auraDir,
};
});
ipcMain.on(`${methodBase}.getAuraDirSync`, (event, _arg) => {
event.returnValue = {
success: true,
data: global.__HUGO_AURA__.auraDir,
};
});
};
module.exports = { applyBaseIpcHandler };

View File

@@ -0,0 +1,13 @@
// @ts-check
const __SCOPE = "main";
/**
*
* @param {import("electron").IpcMain} ipcMain
*/
const applyDebugIpcHandler = (ipcMain) => {
const methodBase = "$aura.debug";
};
module.exports = { applyDebugIpcHandler };

View File

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

View File

@@ -71,34 +71,92 @@ const functions = {
handlePLSDownload: async (channel, callbackFn, binPath) => {
// TODO: Channel selection
const apiInfo = global.__HUGO_AURA_API__;
let plsVersionInfo = {};
const getVerPromise = new Promise((resolve) => {
const getVerPromise = new Promise(async (resolveGetVerReq) => {
// ↓ 目前 channel param 没有什么用处
nodeHttps
.get(
`${apiInfo.baseUrl}${apiInfo.plsUpdate}?channel=${channel}`,
(rep) => {
let dataChunk = "";
rep.on("data", (chunk) => {
dataChunk += chunk;
});
for (const apiDomain of apiInfo.domains) {
const reqPromise = new Promise((resolveHttpRequest) => {
nodeHttps
.get(
`${apiDomain}${apiInfo.plsUpdate}?channel=${channel}`,
(rep) => {
let dataChunk = "";
rep.on("data", (chunk) => {
dataChunk += chunk;
});
rep.on("end", () => {
resolve({
success: true,
data: dataChunk,
rep.on("end", () => {
let parsedData = {};
try {
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;
@@ -109,30 +167,12 @@ const functions = {
status: "failed",
dlUrl: null,
savePath: null,
message: "未能获取 PLS 版本信息",
errorObj: rawResInfo.errorObj ? rawResInfo.errorObj : null,
message: "未能获取 PLS 版本信息, 所有 API 域名均无法连接",
});
return false;
}
try {
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;
}
const plsVersionInfo = rawResInfo.data;
let deviceArch = process.env.PROCESSOR_ARCHITEW6432
? process.env.PROCESSOR_ARCHITEW6432
@@ -155,7 +195,16 @@ const functions = {
fsComposables.downloadFile(
plsVersionInfo.data.downloadUrl[deviceArch],
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) => {
try {
const result = fs.existsSync(PLS_BIN_PATH);
if (global.__HUGO_AURA__.plsStats?.status === "notInstalled") {
global.__HUGO_AURA__.plsStats.status = "dead";
}
return {
success: true,
data: { isExists: result },
};
} catch (e) {
// @ts-expect-error
global.__HUGO_AURA__.plsStats.status = "notInstalled";
return {
success: false,
data: { isExists: false },
@@ -227,7 +283,7 @@ const applyPlsIpcHandler = (ipcMain) => {
}
try {
fs.mkdirSync(PLS_INSTALL_DIR);
fs.mkdirSync(PLS_INSTALL_DIR, { recursive: true });
return {
success: true,
data: {
@@ -362,7 +418,7 @@ const applyPlsIpcHandler = (ipcMain) => {
*/
(_event, arg) => {
ipcMain.send(
"desktopAssistant",
"auraWsKeepAlive",
`${methodBase}.ws.post.onReqSendMsg`,
arg
);
@@ -427,10 +483,6 @@ const applyPlsIpcHandler = (ipcMain) => {
async (_event, arg) => {
const logHeader = "[HugoAura / IPC / PLS] <plsLifecycleControl>";
if (!global.__HUGO_AURA__.plsStats?.installed) {
return { success: false, errorObj: new Error("PLS not installed") };
}
switch (arg.target) {
case "instSvc":
return await functions.execCommand(
@@ -452,6 +504,10 @@ const applyPlsIpcHandler = (ipcMain) => {
success: false,
errorObj: error,
});
console.error(
`${logHeader} Failed to remove PLS bin, error:`,
error
);
return false;
}
@@ -512,7 +568,7 @@ const applyPlsIpcHandler = (ipcMain) => {
status: "Already",
};
} else {
ipcMain.send("desktopAssistant", `${methodBase}.retryPlsConnect`, arg);
ipcMain.send("auraWsKeepAlive", `${methodBase}.retryPlsConnect`, arg);
return {
success: true,

View File

@@ -0,0 +1,114 @@
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(global.__HUGO_AURA__.auraDir, "logs");
global.__HUGO_AURA__.logDir = logDir;
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 daysAgo = new Date(now.getTime() - 15 * 24 * 60 * 60 * 1000);
files.forEach((file) => {
if (file.endsWith(".log")) {
const filePath = path.join(logDir, file);
const stats = fs.statSync(filePath);
// 如果文件创建时间超过两周, 则删除
if (stats.birthtime < daysAgo) {
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

@@ -14,7 +14,7 @@ class WindowHooksManager {
const hooksPath = path.join(__dirname, "../../../aura/mainProcess/hooks");
/** @type {import("../../types/main/core").HooksMap} */
/** @type {import("../../types/main/core").UIHooksMap} */
const hooks = new Map();
try {
@@ -55,6 +55,9 @@ class WindowHooksManager {
browserWindowInstance
) {
const stripWindowName = windowName.split("_")[0];
if (!global.__HUGO_AURA__.windowHooks) return;
if (!global.__HUGO_AURA__.windowHooks.has(stripWindowName)) {
console.log(
`[HugoAura / Init / WDH] Window ${windowName} has no corresponding main process hooks, ignoring...`

View File

@@ -69,7 +69,7 @@ const deepMerge = (target, source) => {
class ConfigManager {
constructor() {
this.configDir = path.join(os.homedir(), "Documents", "HugoAura");
this.configDir = global.__HUGO_AURA__.auraDir;
this.configPath = path.join(this.configDir, "config.json");
this.encConfigPath = path.join(this.configDir, ".cache_2eafc8d0.dat"); // (雾
/* ↑ 不使用 .tmp 扩展名, 不然容易真被清理了 */
@@ -78,10 +78,10 @@ class ConfigManager {
this.isConfigReadFailed = false;
this.side = "unknown";
if (fs.existsSync(this.configPath)) {
this.useEncConfig = false;
} else {
if (fs.existsSync(this.encConfigPath)) {
this.useEncConfig = true;
} else {
this.useEncConfig = false;
}
if (global.__HUGO_AURA_EVENT_BUS__) {
@@ -95,6 +95,38 @@ class ConfigManager {
}
}
migrateOldConfigFile() {
if (this.configDir === path.join(os.homedir(), "Documents", "HugoAura")) {
return;
}
const oldConfigPath = path.join(
os.homedir(),
"Documents",
"HugoAura",
"config.json"
);
const oldEncConfigPath = path.join(
os.homedir(),
"Documents",
"HugoAura",
".cache_2eafc8d0.dat"
);
if (fs.existsSync(oldConfigPath)) {
fs.copyFileSync(oldConfigPath, this.configPath);
fs.unlinkSync(oldConfigPath);
} else if (fs.existsSync(oldEncConfigPath)) {
fs.copyFileSync(oldEncConfigPath, this.encConfigPath);
fs.unlinkSync(oldEncConfigPath);
this.useEncConfig = true;
}
console.log(
`[HugoAura / Config] Moved old config file to ${this.configDir}`
);
}
getHugoAuraConfigPath() {
return path.dirname(
this.useEncConfig ? this.encConfigPath : this.configPath

View File

@@ -26,11 +26,30 @@
"enabled": true
}
},
"ssa": {
"ux": {
"easiAssistant": {
"autoHide": false,
"notDisplay": false
}
}
},
"auraSettings": {
"settingsPasswordEnabled": false,
"settingsPasswordWithSalt": "32703D292460CC9A3B867494D6AD9A8E4A3ADF0FAA4D6867BC4D412CC3927D02E47C6D0B1763BB53E57B2241C6193433561CDA09D7C48CA03983072B876F0965",
"encryptConfig": false,
"appearance": {}
"appearance": {
"appBar": {
"actionBtnsOnRight": false
}
},
"uiAccessMethod": {
"showEntryIcon": true,
"fallbackAccessMethods": {
"hotkey": false,
"touch": false
}
}
},
"devTools": false
}

View File

@@ -6,7 +6,12 @@ const { exec, execSync } = require("child_process");
const LOG_PREFIX = "[HugoAura / Init / Reg";
const LOG_PREFIX_FUNC = "[HugoAura / Reg";
const AURA_REGISTRY_PATH = ["HKEY_USERS", ".DEFAULT", "SOFTWARE", "HugoAura"].join("\\");
const AURA_REGISTRY_PATH = [
"HKEY_USERS",
".DEFAULT",
"SOFTWARE",
"HugoAura",
].join("\\");
class RegistryManager {
/**
@@ -341,19 +346,27 @@ class RegistryManager {
}
/**
* @param {string} relativePath
* @param {string} keyPath
* @param {string} keyName
* @param {boolean | undefined} silent
* @param {boolean} absolute
* @param {any} regex
* @returns {Promise<{ success: boolean, data: string | null, error: Error | null }>}
*/
async readRegKey(relativePath, keyName, silent = false) {
async readRegKey(
keyPath,
keyName,
silent = false,
absolute = false,
regex = null
) {
try {
const { stdout } = await new Promise((resolve, reject) => {
exec(
[
"reg",
"query",
[AURA_REGISTRY_PATH, relativePath].join("\\"),
absolute ? keyPath : [AURA_REGISTRY_PATH, keyPath].join("\\"),
"/v",
`\"${keyName}\"`,
].join(" "),
@@ -367,12 +380,12 @@ class RegistryManager {
if (!silent) {
console.debug(
`${LOG_PREFIX_FUNC} / SUCCESS] Successfully read reg key ${relativePath}/${keyName}, stdout:`,
`${LOG_PREFIX_FUNC} / SUCCESS] Successfully read reg key ${keyPath}/${keyName}, stdout:`,
stdout
);
}
const match = stdout.match(/REG_SZ\s+(.+)/);
const match = regex ? stdout.match(regex) : stdout.match(/REG_SZ\s+(.+)/);
if (!match) {
console.warn(`${LOG_PREFIX} / WARN] Data not found in stdout`);
@@ -390,10 +403,7 @@ class RegistryManager {
error: null,
};
} catch (e) {
console.error(
`${LOG_PREFIX} / ERROR] Failed to read reg key, error:`,
e
);
console.error(`${LOG_PREFIX} / ERROR] Failed to read reg key, error:`, e);
return {
success: false,
data: null,
@@ -403,18 +413,26 @@ class RegistryManager {
}
/**
* @param {string} relativePath
* @param {string} keyPath
* @param {string} keyName
* @param {boolean | undefined} silent
* @param {boolean} absolute
* @param {any} regex
* @returns {{ success: boolean, data: string | null, error: Error | null }}
*/
readRegKeySync(relativePath, keyName, silent = false) {
readRegKeySync(
keyPath,
keyName,
silent = false,
absolute = false,
regex = null
) {
try {
const readResult = execSync(
[
"reg",
"query",
[AURA_REGISTRY_PATH, relativePath].join("\\"),
absolute ? keyPath : [AURA_REGISTRY_PATH, keyPath].join("\\"),
"/v",
`\"${keyName}\"`,
].join(" "),
@@ -424,11 +442,13 @@ class RegistryManager {
if (readResult) {
if (!silent) {
console.debug(
`${LOG_PREFIX_FUNC} / SUCCESS] Successfully read reg key ${relativePath}/${keyName}, stdout:`,
`${LOG_PREFIX_FUNC} / SUCCESS] Successfully read reg key ${keyPath}/${keyName}, stdout:`,
readResult
);
}
const match = readResult.match(/REG_SZ\s+(.+)/);
const match = regex
? readResult.match(regex)
: readResult.match(/REG_SZ\s+(.+)/);
if (!match) {
console.warn(`${LOG_PREFIX} / WARN] Data not found in stdout`);

View File

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

View File

@@ -8,7 +8,7 @@ interface AssistantHugoAuraGlobal extends HugoAuraGlobal {
plsSettings: Record<any, any>;
}
interface DesktopAssistantHugoAuraGlobal extends HugoAuraGlobal {
interface AuraWSKeepAliveWindowHugoAuraGlobal extends HugoAuraGlobal {
plsWs: WebSocket | null;
plsStats: PLSStatus;
}

View File

@@ -14,6 +14,7 @@ interface GlobalHugoAuraInfo {
fsTasks?: MainProcessOnlyVal<FSTasks>;
hookedWindows?: MainProcessOnlyVal<HookedWindowsMap>;
ipcInit?: MainProcessOnlyVal<boolean>;
auraDir: MainProcessOnlyVal<string>;
plsRules?: Record<any, any> | null;
plsSettings?: Record<any, any> | null;
plsStats?: PLSStatus | null;
@@ -24,7 +25,7 @@ interface GlobalHugoAuraInfo {
}
interface GlobalHugoAuraApiInfo {
baseUrl: string;
domains: string[];
plsUpdate: string;
auraUpdate: string;
}

View File

@@ -1,15 +1,28 @@
import { RendererProcessOnlyVal } from "../global";
type PLSStatusDesc =
| "dead"
| "running"
| "notReady"
| "downloading"
| "notInstalled";
interface PLSStatus {
installed: boolean;
detached: boolean;
connected: boolean;
launched: boolean;
status: string;
status: PLSStatusDesc;
version: string;
authToken: string;
}
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) => {
if (Array.isArray(child)) {
for (const perEl of child) {
@@ -71,7 +93,12 @@ const renderInputArea = (entry, operationArea, descriptionArea) => {
switchEl.checked = elValue;
switchEl.addEventListener("change", async (event) => {
showToast(entry);
await entry.callbackFn(event.target.checked);
await entry.callbackFn(
event.target.checked,
switchEl,
operationArea,
descriptionArea
);
});
operationArea.classList.add("form-check", "form-switch");
return switchEl;
@@ -92,7 +119,12 @@ const renderInputArea = (entry, operationArea, descriptionArea) => {
radioEl.addEventListener("change", async (event) => {
if (event.target.checked) {
showToast(entry);
await entry.callbackFn(event.target.value);
await entry.callbackFn(
event.target.value,
radioEl,
operationArea,
descriptionArea
);
}
});
inlineContainerEl.appendChild(radioEl);
@@ -114,7 +146,12 @@ const renderInputArea = (entry, operationArea, descriptionArea) => {
inputEl.placeholder = entry.placeHolder;
inputEl.id = entry.id;
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;
if (success) {
showToast(entry);
@@ -133,6 +170,23 @@ const renderInputArea = (entry, operationArea, descriptionArea) => {
operationArea.classList.add("ase-operation-area-expanded");
return inputEl;
}
case "button": {
const btnEl = document.createElement("button");
btnEl.type = "button";
btnEl.classList.add("btn");
switch (entry.style) {
case "outline":
default:
btnEl.classList.add("btn-outline-primary");
break;
}
btnEl.innerHTML = entry.buttonContent;
btnEl.onclick = entry.callbackFn;
(async () => {
descriptionArea.innerHTML = await entry.valueGetter();
})();
return btnEl;
}
default:
break;
}
@@ -250,22 +304,6 @@ const renderNormalSettingsItem = (entry, formEl) => {
// 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 (!global.__HUGO_AURA__.plsStats.connected) {
setDisableStatus(entryOperationArea, true, "连接至 PLS 以继续");
@@ -285,6 +323,19 @@ const renderNormalSettingsItem = (entry, formEl) => {
const isShow = entry.auraIf();
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) {
const evtListener = (event) => {
if (!entry.associateVal.includes(event.detail.path.join("."))) return;
@@ -293,6 +344,10 @@ const renderNormalSettingsItem = (entry, formEl) => {
isShow
? cls.remove("aura-settings-entry-hidden")
: cls.add("aura-settings-entry-hidden");
if (entry.auraDisable) {
updateDisableStatus();
}
};
const channel = entry.PLSRequired
? "onPLSConfigUpdate"
@@ -378,7 +433,9 @@ const settingsRenderer = (pendingEl, settingsObj) => {
}
pendingEl.appendChild(formEl);
global.__HUGO_AURA_GLOBAL__.utils.refreshBsTooltip();
global.__HUGO_AURA_GLOBAL__.utils.refreshBsTooltip(
".aura-settings-entry-property-icon"
);
};
module.exports = { settingsRenderer };

2
src/aura/ui/hookDefinitions/desktopAssistant.js Executable file → Normal file
View File

@@ -6,7 +6,7 @@
const def = {
targets: {},
globalStyles: ["ui/css/global.css"],
globalJS: ["ui/js/global.js", "ui/js/plsConnectionManager.js"],
globalJS: ["ui/js/global.js", "ui/js/pageGlobal/desktopAssistant.js"],
onLoaded: `
console.log('[HugoAura / UI / Hooks / Desktop Assistant] Page loaded.');
`,

View File

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

View File

@@ -0,0 +1,23 @@
// @ts-check
(() => {
const applyHideSettings = () => {
if (global.__HUGO_AURA_CONFIG__.ssa.ux.easiAssistant.autoHide) {
const minimizeBtnEl = document.getElementsByClassName(
"index__button2__2mhwC3oY"
)[0].children[0];
// @ts-expect-error
minimizeBtnEl.click();
} else if (global.__HUGO_AURA_CONFIG__.ssa.ux.easiAssistant.notDisplay) {
const rootEl = document.getElementById("root");
// @ts-expect-error
rootEl.style["display"] = "none";
}
};
const onMounted = () => {
applyHideSettings();
};
onMounted();
})();

View File

@@ -1,19 +1,26 @@
// @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: "unknown",
status: "dead",
version: "未知",
authToken: "",
};
const IPC_METHOD_BASE = "$aura.pls";
const REQUIRE_BASE = "../../aura/ui";
const __SCOPE = "desktopAssistant";
const REQUIRE_BASE = "../../..";
const __SCOPE = "auraWsKeepAlive";
const PLS_REG_PATH = "ProxyLayerServices";
@@ -45,8 +52,7 @@
};
const calcFullAuthToken = (/** @type {string} */ authToken) => {
const trustToken = window._ACCEPT_DATA.getData("deviceId");
const conjToken = authToken + "AuraXAuth" + trustToken + "NeverEnds";
const conjToken = authToken + "AuraXAuth 0xFFFFFF NeverEnds";
const crypto = require("crypto");
return crypto.createHash("sha512").update(conjToken).digest("hex");
};
@@ -259,7 +265,10 @@
`${IPC_METHOD_BASE}.getPlsStats`
);
let updatedPlsStats = {};
if (curPlsStats === null || !curPlsStats.success) {
if (
(curPlsStats === null || !curPlsStats.success) &&
curPlsStats.status !== "downloading"
) {
updatedPlsStats = {
installed: false,
launched: false,
@@ -277,7 +286,6 @@
await global.ipcRenderer.invoke(`${IPC_METHOD_BASE}.getPlsBinExists`)
).data.isExists;
updatedPlsStats.installed = isPlsFolderExists;
// @ts-expect-error
global.__HUGO_AURA__.plsStats = updatedPlsStats;
console.debug(
@@ -311,7 +319,7 @@
const onSetup = () => {
if (!global.ipcRenderer) {
// @ts-ignore
global.ipcRenderer = require("electron").global.ipcRenderer;
global.ipcRenderer = require("electron").ipcRenderer;
}
initPlsConnection();
@@ -326,5 +334,7 @@
);
};
onSetup();
setTimeout(() => {
onSetup();
}, 1500);
})();

View File

@@ -7,11 +7,54 @@
<div class="aura-config-page-app-bar" style="-webkit-app-region: drag">
<div
onclick="global.__HUGO_AURA_UI_FUNCTIONS__.config.handleNavBack()"
style="-webkit-app-region: no-drag; z-index: 2000"
style="-webkit-app-region: no-drag; z-index: 2000; margin-right: 0.1rem"
>
<i class="iconfont"></i>
<!-- Chevron Left Icon -->
</div>
<p>雨光之环</p>
<div class="aura-config-page-app-bar-hr-vertical" id="auraConfigPageAppBarVerticalHr"></div>
<div class="aura-config-page-app-bar-spacer space-none"></div>
<div
onclick="global.__HUGO_AURA_UI_FUNCTIONS__.config.handleNavHome()"
style="
-webkit-app-region: no-drag;
z-index: 2000;
margin-left: 6px;
margin-right: 0.5rem;
"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="22"
height="22"
viewBox="0 0 24 24"
class="iconfont"
style="margin-top: -1.35px"
>
<path
fill="currentColor"
d="M6 19h3.692v-5.884h4.616V19H18v-9l-6-4.538L6 10zm-1 1V9.5l7-5.288L19 9.5V20h-5.692v-5.884h-2.616V20zm7-7.77"
stroke-width="0.5"
stroke="currentColor"
/>
</svg>
</div>
<div class="aura-config-page-app-bar-spacer"></div>
<div
onclick="global.__HUGO_AURA_UI_FUNCTIONS__.config.minimizeWindow()"
style="-webkit-app-region: no-drag; z-index: 2000"
>
<i class="iconfont"></i>
<!-- Minimize Icon -->
</div>
<div
onclick="global.__HUGO_AURA_UI_FUNCTIONS__.config.closeWindow()"
style="-webkit-app-region: no-drag; z-index: 2000; margin-left: 0.5rem"
>
<i class="iconfont"></i>
<!-- Failed / Cancel Icon -->
</div>
</div>
</div>
@@ -99,8 +142,8 @@
<div class="aura-config-page-operation-body">
<img src="../../aura/ui/static/config/no_limitations.svg" />
<div>
<p class="config-operation-title">限制解除</p>
<p class="config-operation-description">禁用密码、关闭功能</p>
<p class="config-operation-title">行为改写</p>
<p class="config-operation-description">覆写密码、禁用能力</p>
</div>
</div>
</div>
@@ -112,7 +155,7 @@
<div class="aura-config-page-operation-body">
<img src="../../aura/ui/static/config/behaviour_mon.svg" />
<div>
<p class="config-operation-title">行为管控</p>
<p class="config-operation-title">操作管控</p>
<p class="config-operation-description">窥屏提醒、数据欺骗</p>
</div>
</div>

View File

@@ -6,6 +6,22 @@ global.__HUGO_AURA_UI_REACTIVES__.config = {
};
global.__HUGO_AURA_UI_FUNCTIONS__.config = {
closeWindow: async () => {
if (global.__HUGO_AURA_UI_REACTIVES__.config.isConfigPendingWrite) {
await global.__HUGO_AURA_UI_FUNCTIONS__.config.handleSaveConfig();
}
global.ipcRenderer.send("$aura.base.closeWindow", {
targetWindowKey: "assistant",
});
},
minimizeWindow: () => {
global.ipcRenderer.send("$aura.base.minimizeWindow", {
targetWindowKey: "assistant",
});
},
handleNavBack: () => {
if (global.__HUGO_AURA_UI_REACTIVES__.config.isInSubPage) {
const acsDialogAreaEl = document.getElementsByClassName(
@@ -30,6 +46,19 @@ global.__HUGO_AURA_UI_FUNCTIONS__.config = {
}
},
handleNavHome: async () => {
if (global.__HUGO_AURA_UI_REACTIVES__.config.isConfigPendingWrite) {
global.__HUGO_AURA_UI_FUNCTIONS__.config.handleSaveConfig();
}
global.__HUGO_AURA_UI_FUNCTIONS__.config.hideConfigPage();
setTimeout(() => {
const onLeaveEvent = new CustomEvent("onCurConfigPageLeave");
document.dispatchEvent(onLeaveEvent);
}, 500);
},
hideConfigPage: async () => {
const defaultHeader = document.getElementsByClassName(
"index__header__16DmR2a5"
@@ -265,6 +294,27 @@ global.__HUGO_AURA_UI_FUNCTIONS__.config = {
// TODO: Error handling
}
},
initCustomUIProps: async (refresh = false) => {
const verticalHrEl = document.getElementById(
"auraConfigPageAppBarVerticalHr"
);
const spacerElArr = document.getElementsByClassName(
"aura-config-page-app-bar-spacer"
);
if (
global.__HUGO_AURA_CONFIG__.auraSettings.appearance.appBar
.actionBtnsOnRight
) {
verticalHrEl.classList.add("hidden");
spacerElArr[0].classList.remove("space-none");
spacerElArr[1].classList.add("space-none");
} else if (refresh) {
verticalHrEl.classList.remove("hidden");
spacerElArr[0].classList.add("space-none");
spacerElArr[1].classList.remove("space-none");
}
},
};
(() => {
@@ -362,6 +412,7 @@ global.__HUGO_AURA_UI_FUNCTIONS__.config = {
};
const onMounted = () => {
global.__HUGO_AURA_UI_FUNCTIONS__.config.initCustomUIProps();
applyVersionInfo();
showAnimation();

View File

@@ -19,6 +19,11 @@
color: rgba(0, 0, 0, 0.8);
}
.aura-config-page-header-area.color-reverse
.aura-config-page-app-bar-hr-vertical {
background: rgba(0, 0, 0, 0.5);
}
.aura-config-page-header-area .iconfont {
font-size: 24px;
}
@@ -33,7 +38,7 @@
}
.aura-config-page-header-area p {
margin-top: -1px;
margin-top: -2px;
}
.aura-config-page-header-area.header-collapsed {
@@ -48,3 +53,24 @@
align-items: center;
width: 100%;
}
.aura-config-page-app-bar-spacer {
flex-grow: 1;
}
.aura-config-page-app-bar-spacer.space-none {
flex-grow: 0;
}
.aura-config-page-app-bar-hr-vertical {
position: relative;
margin-left: 8px;
width: 1px;
background: rgba(255, 255, 255, 0.5);
height: 12px;
transition: background 0.5s;
}
.aura-config-page-app-bar-hr-vertical.hidden {
display: none;
}

View File

@@ -33,6 +33,10 @@
margin-bottom: 1rem;
}
.acs-bc-psp-operations-container.acs-bc-psp-oper-ctnr-hidden {
display: none;
}
.acs-bc-psp-operation-btn {
--svg-color: rgb(17, 140, 255);
@@ -85,6 +89,50 @@
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 {
display: flex;
align-items: center;

View File

@@ -124,6 +124,37 @@
</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">
<p>安装状态</p>
<div
@@ -165,7 +196,11 @@
</div>
<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">
<strong class="me-auto" id="plsStatusNotifyToastTitle"></strong>
<button

View File

@@ -17,6 +17,7 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig)
global.__HUGO_AURA_UI_REACTIVES__.subConfig.plsStatus = {
toastAutoHideTimeout: null,
curDlTaskId: null,
};
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(
"error",
"服务安装失败",
"<p>检查日志以获取详细信息</p>",
`<p>${ret.errorObj}</p>`,
true,
false,
null
@@ -166,6 +167,13 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig)
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;
ipcRenderer.invoke(
`${IPC_METHOD_BASE}.updatePlsStats`,
global.__HUGO_AURA__.plsStats
);
global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast(
"success",
"内核已删除",
@@ -178,7 +186,9 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig)
global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast(
"error",
"内核删除失败",
"<p>检查日志以获取详细信息</p>",
`<p>
${ret.errorObj ? ret.errorObj : "检查日志以获取详细信息"}
</p>`,
true,
false,
null
@@ -211,7 +221,14 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig)
global.__HUGO_AURA_UI_FUNCTIONS__.subConfig.plsStatus.updateToast(
"error",
"服务卸载失败: 无法停止服务",
"<p>检查日志以获取详细信息</p><p>您可以尝试手动停止 PLS 服务</p>",
`<p>${
stopRet.errorObj
? stopRet.errorObj
: "检查日志以获取详细信息"
}</p>
<p>
您可以尝试手动停止 PLS 服务
</p>`,
true,
false,
null
@@ -345,6 +362,10 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig)
updateStatusContent: async () => {
const curPlsStats = await updatePlsStatusFromLocal();
if (curPlsStats.status === "downloading") {
GLOBAL_FUNCTIONS.downloadPLSBin(true);
}
const acIdInst = "acs-bc-psp-installStatus-container";
const atIdInst = "acs-bc-psp-installStatus-text";
switch (lifecycleStatus.installed) {
@@ -435,8 +456,18 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig)
);
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 内核以继续",
@@ -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 =
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`;
await ipcRenderer.invoke(`${IPC_METHOD_BASE}.ensurePlsInstallDir`);
GLOBAL_FUNCTIONS.updateToast(
"info",
"准备开始下载...",
null,
true,
true,
2000
);
GLOBAL_FUNCTIONS.updateOperationBtnStatus("Download", true, "等待下载");
if (!retrieveMode) {
GLOBAL_FUNCTIONS.updateOperationBtnStatus("Download", true, "正在检查");
GLOBAL_FUNCTIONS.updateOperationBtnStatus("Refresh", true);
await ipcRenderer.invoke(`${IPC_METHOD_BASE}.ensurePlsInstallDir`);
GLOBAL_FUNCTIONS.updateToast(
"info",
"准备开始下载...",
null,
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) => {
switch (info.status) {
@@ -548,13 +658,31 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig)
"下载失败",
`<p>${
info.message ? info.message : "检查日志以获取错误信息"
}</p>`,
}</p><p>
${info.errorObj ? info.errorObj : ""}
</p>`,
true,
true,
5000
);
GLOBAL_FUNCTIONS.updatePBarStatus(
100,
"下载时发生错误",
"danger",
false
);
setTimeout(() => {
GLOBAL_FUNCTIONS.switchPBarShowStatus(false);
}, 1000);
ipcRenderer.off(CUR_CHANNEL, callbackFn);
GLOBAL_FUNCTIONS.updateOperationBtnStatus("Refresh", false);
GLOBAL_FUNCTIONS.updateOperationBtnStatus(
"Download",
false,
"下载内核"
);
break;
case "done":
GLOBAL_FUNCTIONS.updateToast(
@@ -565,6 +693,17 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig)
true,
2500
);
GLOBAL_FUNCTIONS.updatePBarStatus(
100,
"下载成功",
"success",
false
);
setTimeout(() => {
GLOBAL_FUNCTIONS.switchPBarShowStatus(false);
}, 1000);
ipcRenderer.off(CUR_CHANNEL, callbackFn);
GLOBAL_FUNCTIONS.updateOperationBtnStatus("Refresh", false);
GLOBAL_FUNCTIONS.updateOperationBtnStatus(
@@ -573,20 +712,49 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig)
"下载内核"
);
lifecycleStatus.installed = true;
global.__HUGO_AURA__.plsStats.installed = true;
ipcRenderer.invoke(
`${IPC_METHOD_BASE}.updatePlsStats`,
global.__HUGO_AURA__.plsStats
);
GLOBAL_FUNCTIONS.updateStatusContent();
break;
case "waiting":
GLOBAL_FUNCTIONS.updateOperationBtnStatus(
"Download",
true,
"等待中..."
);
GLOBAL_FUNCTIONS.updatePBarStatus(0, "正在连接", "normal");
if (
!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;
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(
"Download",
true,
`下载 ${Math.round(info.progress)}%`
false,
"下载内核"
);
break;
}
@@ -594,11 +762,56 @@ if (!global.__HUGO_AURA_UI_REACTIVES__.subConfig)
ipcRenderer.on(CUR_CHANNEL, callbackFn);
ipcRenderer.invoke(`$aura.pls.downloadPls`, {
ipcRenderer.invoke(`${IPC_METHOD_BASE}.downloadPls`, {
channel: "stable",
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 =

View File

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

View File

@@ -31,6 +31,20 @@
上报屏蔽
</button>
</li>
<li class="nav-item" role="presentation">
<button
class="nav-link"
id="appearance-ctl-tab"
data-bs-toggle="pill"
data-bs-target="#appearance-ctl-subpage"
type="button"
role="tab"
aria-controls="appearance-ctl-subpage"
aria-selected="false"
>
外观与体验
</button>
</li>
</ul>
<div class="tab-content">
<div
@@ -45,5 +59,11 @@
role="tabpanel"
aria-labelledby="disable-audit-tab"
></div>
<div
class="tab-pane fade"
id="appearance-ctl-subpage"
role="tabpanel"
aria-labelledby="appearance-ctl-tab"
></div>
</div>
</div>

View File

@@ -7,6 +7,7 @@
} = require("../../aura/ui/composables/settingsRenderer");
const { authSettings } = require(`${pathBase}/auth`);
const { banAuditSettings } = require(`${pathBase}/audit`);
const { uxAndAppearanceSettings } = require(`${pathBase}/uxAppearance`);
const initAuthSubPage = () => {
const authSubPageEl = document.getElementById("auth-subpage");
@@ -18,9 +19,17 @@
settingsRenderer(banAuditSubPageEl, banAuditSettings);
};
const initUxAndAppearanceSubPage = () => {
const uxAndAppearancePageEl = document.getElementById(
"appearance-ctl-subpage"
);
settingsRenderer(uxAndAppearancePageEl, uxAndAppearanceSettings);
};
const onMounted = () => {
initAuthSubPage();
initBanAuditSubPage();
initUxAndAppearanceSubPage();
const rootEl = document.getElementById("acs-disable-limit-root-el");
setTimeout(() => {

View File

@@ -0,0 +1,62 @@
const uxAndAppearanceSettings = [
{
id: 0,
categoryName: "管家助手",
child: [
{
index: 0,
id: "autoHideEasiAssistant",
type: "switch",
name: "自动最小化管家助手",
description: "管家启动后, 自动将桌面右下角管家助手最小化至 Fab 形态",
restart: true,
reload: false,
associateVal: ["ssa.ux.easiAssistant.notDisplay"],
auraIf: () => true,
defaultValue: false,
auraDisable: () => {
if (global.__HUGO_AURA_CONFIG__.ssa.ux.easiAssistant.notDisplay) {
return { value: true, tooltip: '禁用 "隐藏管家助手" 以继续' };
} else {
return { value: false };
}
},
valueGetter: () => {
return global.__HUGO_AURA_CONFIG__.ssa.ux.easiAssistant.autoHide;
},
callbackFn: (newVal) => {
if (typeof newVal !== "boolean") return;
global.__HUGO_AURA_CONFIG__.ssa.ux.easiAssistant.autoHide = newVal;
},
},
{
index: 1,
id: "notDisplayEasiAssistant",
type: "switch",
name: "隐藏管家助手",
description: "管家启动后, 管家助手窗口将不再显示",
restart: true,
reload: false,
associateVal: ["ssa.ux.easiAssistant.autoHide"],
auraIf: () => true,
defaultValue: false,
auraDisable: () => {
if (global.__HUGO_AURA_CONFIG__.ssa.ux.easiAssistant.autoHide) {
return { value: true, tooltip: '禁用 "自动最小化管家助手" 以继续' };
} else {
return { value: false };
}
},
valueGetter: () => {
return global.__HUGO_AURA_CONFIG__.ssa.ux.easiAssistant.notDisplay;
},
callbackFn: (newVal) => {
if (typeof newVal !== "boolean") return;
global.__HUGO_AURA_CONFIG__.ssa.ux.easiAssistant.notDisplay = newVal;
},
},
],
},
];
module.exports = { uxAndAppearanceSettings };

View File

@@ -17,6 +17,20 @@
Aura 设置
</button>
</li>
<li class="nav-item" role="presentation">
<button
class="nav-link"
id="debug-subpage-tab"
data-bs-toggle="pill"
data-bs-target="#debug-subpage"
type="button"
role="tab"
aria-controls="debug-subpage"
aria-selected="false"
>
调试选项
</button>
</li>
<li class="nav-item" role="presentation">
<button
class="nav-link"
@@ -26,7 +40,7 @@
type="button"
role="tab"
aria-controls="about-subpage"
aria-selected="true"
aria-selected="false"
>
关于项目
</button>
@@ -39,6 +53,12 @@
role="tabpanel"
aria-labelledby="aura-subpage-tab"
></div>
<div
class="tab-pane fade"
id="debug-subpage"
role="tabpanel"
aria-labelledby="debug-subpage-tab"
></div>
<div
class="tab-pane fade"
id="about-subpage"

View File

@@ -5,13 +5,21 @@
settingsRenderer,
} = require("../../aura/ui/composables/settingsRenderer");
const { auraSettings } = require(`${pathBase}/aura`);
const { debugSettings } = require(`${pathBase}/debug`);
const initAuraSubPage = () => {
const auraSettingsSubPageEl = document.getElementById("aura-subpage");
settingsRenderer(auraSettingsSubPageEl, auraSettings);
};
const initDebugSubPage = () => {
const debugSubPageEl = document.getElementById("debug-subpage");
settingsRenderer(debugSubPageEl, debugSettings);
};
const onMounted = () => {
initAuraSubPage();
initDebugSubPage();
const rootEl = document.getElementById("acs-preferences-root-el");
setTimeout(() => {

View File

@@ -96,12 +96,9 @@ const functions = {
const handleExit = async () => {
const result = await awaitCompletePromise;
console.debug(result);
if (result) {
console.debug("ret true");
return { valid: true };
} else {
console.debug("ret false");
const inputEl = document.getElementById("auraSettingsPasswd");
// @ts-expect-error
inputEl.value = "";
@@ -155,6 +152,27 @@ const functions = {
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 = [
@@ -170,8 +188,6 @@ const auraSettings = [
description: "启用后, Aura 设置 UI 需要输入密码才可访问",
restart: false,
reload: false,
tip: true,
tipTitle: "启用访问密码将自动加密配置文件",
associateVal: null,
auraIf: () => true,
defaultValue: false,
@@ -288,8 +304,171 @@ const auraSettings = [
},
{
id: 1,
categoryName: "访问方式",
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;
},
},
],
},
{
id: 2,
categoryName: "外观",
child: [],
child: [
{
index: 0,
id: "actionBtnsOnRight",
type: "switch",
name: "顶栏操作类按钮右置",
description: "启用后, 顶栏的<b>返回首页按钮</b>将靠右放置",
restart: false,
reload: false,
auraIf: () => {
return true;
},
defaultValue: false,
valueGetter: () => {
return global.__HUGO_AURA_CONFIG__.auraSettings.appearance.appBar
.actionBtnsOnRight;
},
callbackFn: async (newVal) => {
if (typeof newVal !== "boolean") return;
global.__HUGO_AURA_CONFIG__.auraSettings.appearance.appBar.actionBtnsOnRight =
newVal;
global.__HUGO_AURA_UI_FUNCTIONS__.config.initCustomUIProps(true);
},
},
],
},
];

View File

@@ -0,0 +1,45 @@
const IPC_METHOD_BASE = "$aura.debug";
const path = require("path");
const debugSettings = [
{
id: 0,
categoryName: "日志与输出",
child: [
{
index: 0,
id: "openHugoAuraLogDir",
type: "button",
style: "outline",
name: "HugoAura 日志目录",
description: "",
restart: false,
reload: false,
associateVal: null,
auraIf: () => true,
buttonContent: "打开",
valueGetter: async () => {
if (
global.__HUGO_AURA__.auraDir &&
global.__HUGO_AURA__.auraDir !== ""
) {
return (
"目录位置: " + path.join(global.__HUGO_AURA__.auraDir, "logs")
);
} else {
return "未能获取日志目录位置";
}
},
callbackFn: async (event) => {
const childProc = require("child_process");
childProc.spawn(`explorer.exe`, [
`${path.join(global.__HUGO_AURA__.auraDir, "logs")}`,
]);
},
},
],
},
];
module.exports = { debugSettings };

View File

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

View File

@@ -1,5 +1,56 @@
global.__HUGO_AURA_UI_FUNCTIONS__.headerIcon = {
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 rootEl = document.getElementById("root");
rootEl.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

@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>Aura WebSocket KeepAlive Window</title>
<style>
:root {
opacity: 0;
}
</style>
<script>
let global = window;
</script>
<script src="../../../js/plsConnectionManager.js"></script>
</head>
<body></body>
</html>

39
src/aura/utils/pls.js Normal file
View File

@@ -0,0 +1,39 @@
// @ts-check
/**
* @param {Electron} electron
*/
const createWsWindow = (electron) => {
const path = require("path");
const { BrowserWindow } = electron;
const window = new BrowserWindow({
width: 0,
height: 0,
frame: false,
skipTaskbar: true,
transparent: true,
alwaysOnTop: true,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
devTools: true,
},
});
window.setIgnoreMouseEvents(true);
window.loadFile(
path.join(
__dirname,
"..",
"ui",
"pages",
"windows",
"auraWsKeepAlive",
"index.html"
)
);
return window;
};
module.exports = { createWsWindow };

View File

@@ -6,6 +6,7 @@ if (!global.__HUGO_AURA__) {
configInit: false,
central: () => {},
ipcInit: false,
auraDir: "",
plsStats: null,
plsSettings: null,
plsRules: null,
@@ -19,9 +20,15 @@ if (!global.__HUGO_AURA__) {
if (!global.__HUGO_AURA_API__) {
/** @type {import("../aura/types/shared/global").GlobalHugoAuraApiInfo} */
const __HUGO_AURA_API__ = {
baseUrl: "https://api-aura.xwx.li",
plsUpdate: "/api/v1/getPLSLatestVersion",
auraUpdate: "/api/v1/getAuraLatestVersion",
domains: [
"https://api-aura-projekts.delta.ooo",
"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__;
}
@@ -30,8 +37,6 @@ if (!global.__HUGO_AURA_CONFIG__) {
global.__HUGO_AURA_CONFIG__ = {};
}
const fs = require("fs");
const util = require("util");
const path = require("path");
const os = require("os");
@@ -40,71 +45,36 @@ const RendererHooksManager = require("../aura/init/rendererHook/uiHooksManager")
const EventBus = require("../aura/utils/eventBus");
const NetworkHook = require("../aura/init/rendererHook/networkHook");
const ConfigManager = require("../aura/init/shared/configManager");
const RegistryManager = require("../aura/init/shared/registryManager");
const { buildIpcMain } = require("../aura/init/main/ipcHandler");
const plsUtils = require("../aura/utils/pls");
/**
*
* @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 { initLogger } = require("../aura/init/main/logger");
const getUserDocumentsDirPath = () => {
const registryManager = new RegistryManager();
const pathInfo = registryManager.readRegKeySync(
'"HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders"',
"Personal",
false,
true,
/REG_EXPAND_SZ\s+(.+)/
);
if (pathInfo.success && pathInfo.data) {
const resolvedPath = pathInfo.data.replace(
/%([^%]+)%/g,
(match, varName) => {
return process.env[varName] || match;
}
);
return resolvedPath;
} else {
console.error(
"[HugoAura / Init / Logger] Failed to get the path of documents dir, using default val."
);
return path.join(os.homedir(), "Documents");
}
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
);
};
/**
@@ -128,6 +98,11 @@ const launcher = ({ central, windowName, config }) => {
app.exit(0);
};
global.__HUGO_AURA__.auraDir = path.join(
getUserDocumentsDirPath(),
"HugoAura"
);
// >>> Init Logger <<< //
initLogger(windowName);
@@ -141,6 +116,7 @@ const launcher = ({ central, windowName, config }) => {
// >>> Init Config <<< //
const configManager = new ConfigManager();
configManager.side = "main";
configManager.migrateOldConfigFile();
configManager.ensureConfigExists();
const loadedConfig = configManager.loadConfig();
if (!global.__HUGO_AURA__.configInit) global.__HUGO_AURA__.configInit = true;
@@ -174,6 +150,13 @@ const launcher = ({ central, windowName, config }) => {
config.canOpenDevTool = true;
}
// >>> Create WebSocket KeepAlive Window <<< //
if (!global.__HUGO_AURA__.hookedWindows?.has("auraWsKeepAlive")) {
const wsKaWin = plsUtils.createWsWindow(electron);
// @ts-expect-error
global.__HUGO_AURA__.hookedWindows.set("auraWsKeepAlive", wsKaWin);
}
// >>> Listeners <<< //
/**

View File

@@ -1,13 +1,18 @@
// @ts-check
const __AURA_VERSION__ = "0.1.1-pre-IV";
const __AURA_VERSION__ = "0.1.1-beta";
(() => {
if (require.main) return; // 如果只是导入 Aura Version, 不运行闭包逻辑
const auraDir = require("electron").ipcRenderer.sendSync(
"$aura.base.getAuraDirSync"
);
// >>> Init Global Vars <<< //
if (!global.__HUGO_AURA__) {
global.__HUGO_AURA__ = {
auraDir: auraDir.data,
configInit: true, // preload 始终比 hook 晚, 默认 config 已初始化
// ↑ 保留此参数的目的 -> 用于 configManager 中, configManager 的行为在 Renderer 和 Main 中是一致的
version: __AURA_VERSION__,