@myassis/gateway 1.0.48 → 1.0.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +3 -0
- package/dist/services/ServiceManager.js +69 -3
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -250,6 +250,9 @@ else {
|
|
|
250
250
|
schedulerStarted = true;
|
|
251
251
|
}
|
|
252
252
|
logger.info(`我的助手 Gateway Service running on port ${port}`);
|
|
253
|
+
// 启动自愈:检查开机自启 Run key 是否健康,不健康则自动 rewrite。
|
|
254
|
+
// 异步执行,失败不影响主流程。
|
|
255
|
+
(0, ServiceManager_js_1.ensureAutoStartHealthy)().catch(() => { });
|
|
253
256
|
});
|
|
254
257
|
};
|
|
255
258
|
startServer(configuredPort);
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.execAsUser = exports.isHelperReady = exports.stopHelper = exports.updateService = exports.checkForUpdates = exports.restartService = exports.stopService = exports.startService = exports.uninstallService = exports.installService = exports.getServiceInfo = exports.SERVICE_DISPLAY_NAME = exports.SERVICE_NAME = void 0;
|
|
6
|
+
exports.execAsUser = exports.isHelperReady = exports.stopHelper = exports.updateService = exports.checkForUpdates = exports.restartService = exports.stopService = exports.startService = exports.uninstallService = exports.installService = exports.ensureAutoStartHealthy = exports.getServiceInfo = exports.SERVICE_DISPLAY_NAME = exports.SERVICE_NAME = void 0;
|
|
7
7
|
const child_process_1 = require("child_process");
|
|
8
8
|
const util_1 = require("util");
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
@@ -173,6 +173,11 @@ function writeGatewayLauncherScript(exePath, scriptPath, workDir) {
|
|
|
173
173
|
" $proc.WaitForExit()",
|
|
174
174
|
"}",
|
|
175
175
|
].join('\r\n');
|
|
176
|
+
// 确保目标目录存在(%LOCALAPPDATA%\我的助手 首次启动时可能不存在)
|
|
177
|
+
try {
|
|
178
|
+
fs_1.default.mkdirSync(path_1.default.dirname(scriptPath), { recursive: true });
|
|
179
|
+
}
|
|
180
|
+
catch { /* ignore */ }
|
|
176
181
|
fs_1.default.writeFileSync(scriptPath, '\uFEFF' + content, 'utf8');
|
|
177
182
|
}
|
|
178
183
|
/**
|
|
@@ -193,7 +198,15 @@ function isRegisteredInRunKey() {
|
|
|
193
198
|
* 写入注册表 Run key(开机自启)
|
|
194
199
|
*/
|
|
195
200
|
async function registerRunKey(scriptPath) {
|
|
196
|
-
|
|
201
|
+
// Run key 的 value 必须是一条完整的命令行,Windows 登录时不会按 .ps1 关联去执行;
|
|
202
|
+
// 因此这里把 powershell.exe 的完整调用串(含执行策略与隐藏窗口参数)作为 value 写入。
|
|
203
|
+
const powershellExe = path_1.default.join(process.env.SystemRoot || 'C:\\Windows', 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe');
|
|
204
|
+
// 最终写入注册表的字符串形如:
|
|
205
|
+
// "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File "<scriptPath>"
|
|
206
|
+
const runValue = `"${powershellExe}" -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File "${scriptPath}"`;
|
|
207
|
+
// PowerShell 单引号字符串里的单引号需要用两个单引号转义
|
|
208
|
+
const runValueForPs = runValue.replace(/'/g, "''");
|
|
209
|
+
const regCmd = `powershell -NoProfile -Command "Set-ItemProperty -Path 'HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Run' -Name '${exports.SERVICE_NAME}' -Value '${runValueForPs}' -Type String"`;
|
|
197
210
|
await execAsync(regCmd, { timeout: 10000, windowsHide: true });
|
|
198
211
|
}
|
|
199
212
|
/**
|
|
@@ -402,6 +415,57 @@ async function getServiceInfo() {
|
|
|
402
415
|
};
|
|
403
416
|
}
|
|
404
417
|
exports.getServiceInfo = getServiceInfo;
|
|
418
|
+
/**
|
|
419
|
+
* 启动自愈:检查 Run key 值是否健康,不健康则自动 rewrite。
|
|
420
|
+
*
|
|
421
|
+
* 历史版本把 launcher 存到了 %TEMP%,且 Run key 里直接写的是 .ps1 裸路径(Windows 登录时不会当脚本执行)。
|
|
422
|
+
* 本函数在 gateway 启动时无侵入地修复这一情况:
|
|
423
|
+
* - 仅 Windows 平台生效
|
|
424
|
+
* - 若 Run key 未注册(说明从未走过 install 流程,例如开发机)→ 直接跳过
|
|
425
|
+
* - 若已注册但值不含 powershell.exe,或 launcher 不在新路径 → rewrite
|
|
426
|
+
* - 顺手清理 %TEMP% 里的旧 launcher 残留
|
|
427
|
+
* 失败不抛异常,仅记录日志,避免影响主流程。
|
|
428
|
+
*/
|
|
429
|
+
async function ensureAutoStartHealthy() {
|
|
430
|
+
if (process.platform !== 'win32')
|
|
431
|
+
return;
|
|
432
|
+
try {
|
|
433
|
+
// 1) 读取当前 Run key 值
|
|
434
|
+
const readCmd = `powershell -NoProfile -Command "try { (Get-ItemProperty -Path 'HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Run' -Name '${exports.SERVICE_NAME}' -ErrorAction Stop).'${exports.SERVICE_NAME}' } catch { '' }"`;
|
|
435
|
+
const { stdout } = await execAsync(readCmd, { timeout: 5000, windowsHide: true });
|
|
436
|
+
const currentValue = stdout.toString().trim();
|
|
437
|
+
// 2) 未注册→开发机或从未安装,不做任何事
|
|
438
|
+
if (!currentValue)
|
|
439
|
+
return;
|
|
440
|
+
// 3) 评估健康度
|
|
441
|
+
const lower = currentValue.toLowerCase();
|
|
442
|
+
const hasPowershell = lower.includes('powershell.exe');
|
|
443
|
+
const pointsToNewPath = lower.includes(GATEWAY_LAUNCHER_FILE.toLowerCase());
|
|
444
|
+
if (hasPowershell && pointsToNewPath)
|
|
445
|
+
return; // 已健康
|
|
446
|
+
logger.warn(`检测到 Run key 不健康,自动修复。current='${currentValue}'`);
|
|
447
|
+
// 4) 重写 launcher 脚本到新路径
|
|
448
|
+
const exe = getGatewayExePath();
|
|
449
|
+
const workDir = path_1.default.dirname(exe);
|
|
450
|
+
writeGatewayLauncherScript(exe, GATEWAY_LAUNCHER_FILE, workDir);
|
|
451
|
+
// 5) 重新注册完整 powershell 命令行
|
|
452
|
+
await registerRunKey(GATEWAY_LAUNCHER_FILE);
|
|
453
|
+
// 6) 清理 %TEMP% 旧 launcher 残留
|
|
454
|
+
try {
|
|
455
|
+
const legacyPath = path_1.default.join(os_1.default.tmpdir(), 'myassis-gateway-launcher.ps1');
|
|
456
|
+
if (fs_1.default.existsSync(legacyPath) && legacyPath.toLowerCase() !== GATEWAY_LAUNCHER_FILE.toLowerCase()) {
|
|
457
|
+
fs_1.default.unlinkSync(legacyPath);
|
|
458
|
+
logger.info(`已清理旧 launcher: ${legacyPath}`);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
catch { /* ignore */ }
|
|
462
|
+
logger.info(`Run key 修复完成 → ${GATEWAY_LAUNCHER_FILE}`);
|
|
463
|
+
}
|
|
464
|
+
catch (err) {
|
|
465
|
+
logger.warn(`ensureAutoStartHealthy 失败(忽略): ${err?.message || err}`);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
exports.ensureAutoStartHealthy = ensureAutoStartHealthy;
|
|
405
469
|
async function installService() {
|
|
406
470
|
const platform = process.platform;
|
|
407
471
|
if (platform === 'win32')
|
|
@@ -739,8 +803,10 @@ const HELPER_PORT = 19630;
|
|
|
739
803
|
const HELPER_TIMEOUT_MS = 60000;
|
|
740
804
|
/** Gateway PID 文件路径(用户级进程跟踪) */
|
|
741
805
|
const GATEWAY_PID_FILE = path_1.default.join(os_1.default.tmpdir(), 'myassis-gateway-pid.txt');
|
|
806
|
+
/** Gateway 启动脚本存放目录(用户级持久化目录,避免被 %TEMP% 清理策略删除) */
|
|
807
|
+
const GATEWAY_DATA_DIR = path_1.default.join(process.env.LOCALAPPDATA || path_1.default.join(os_1.default.homedir(), 'AppData', 'Local'), '我的助手');
|
|
742
808
|
/** Gateway 启动脚本路径 */
|
|
743
|
-
const GATEWAY_LAUNCHER_FILE = path_1.default.join(
|
|
809
|
+
const GATEWAY_LAUNCHER_FILE = path_1.default.join(GATEWAY_DATA_DIR, 'gateway-launcher.ps1');
|
|
744
810
|
/** 当前活跃的 Helper 进程 */
|
|
745
811
|
let helperProcess = null;
|
|
746
812
|
/** Helper 连接 socket */
|