mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-02 04:52:50 +08:00
fix(setup): 按 Node ABI 校验并自动修复原生模块
换过 Node 大版本之后安装就废了,而且安装脚本还会报告成功。原生模块只能在 编译它的那个 Node ABI 上加载(Node 20 = 115、22 = 127、24 = 137),而 better-sqlite3 的 .node 放在与 ABI 无关的固定路径下,旧的 download-binaries 只检查「文件存在且大于 500KB」,于是给 Node 24 编译的 1.9MB 文件在 Node 22 下原样保留,跳过重新下载,机器人启动时死在 NODE_MODULE_VERSION 上。 (@discordjs/opus 的目录名里带 ABI,反而歪打正着没这个问题。) download-binaries.mjs 现在不看文件大小,而是在子进程里真的把每个包 load 一遍 ——子进程是必须的,Windows 上父进程加载过的 .node 会一直被映射,系统随后拒绝 删除或覆盖它。注意 better-sqlite3 的 addon 是在 Database 构造函数里惰性加载的, 所以光 require 这个包探测不出问题,得真的开一个内存库。 失败就按当前 ABI 重新安装,整个替换过程是先把旧文件挪到 node_modules/ .tsmusicbot-backup、下载解压到暂存目录、原子 rename 就位、再探测一次,任何 一步失败都把原文件还原回去——删掉不匹配的二进制却下载不下来,比原来的版本 更糟。备份特意放在包的 build/ 之外,因为源码编译回退会调 node-gyp 把 build/ 清空。被中断(比如下载到一半 Ctrl+C)遗留的备份,下一次运行会自动认领回来。 其他一并修掉的问题: - 版本号原本硬编码 12.8.0,实际锁的是 12.11.1,一旦真的触发下载就会 404; 改为从 node_modules 里读。 - 三个模块原本用 Promise.all 并发。源码编译走的是 execSync,会把事件循环整个 卡住几分钟,而 download() 的 120 秒超时是挂在同一个循环上的 socket 静默计时 器——循环一恢复,还在传输中的连接就会被判超时。这不是小概率竞态:npmmirror 上没有 ABI 137 的 opus,也没有 ABI 115 的 better-sqlite3,所以在 Node 24 和 Node 20 上必定有一个模块在 100ms 内 404 并开始编译,而 ffmpeg 的 80MB 下载 正在进行。ffmpeg 是可选模块,于是它被误杀后只记一条 WARN,脚本照样 exit 0, setup 打印「Setup Complete」,用户装完却没有 ffmpeg,放什么都放不出来。 改成严格串行执行。 - 必需模块(opus / better-sqlite3)失败才返回非零;ffmpeg 有系统 ffmpeg 兜底, 只警告。setup.bat 里原本形同虚设的 FAILED 标志接上了,必需模块失败会中止安装, 不再是「装完才发现」。 - 4b 步骤原本把全部输出重定向进 setup.log,用户盯着不动的窗口以为卡死;现在 进度走 stderr 实时显示,完整记录仍进日志。 新增 scripts/check-native.mjs:启动前预检,直接说清楚哪个模块对不上、分别是哪 个 ABI、怎么修,而不是抛一串 NODE_MODULE_VERSION 堆栈。scripts\start.bat、根目 录 start.bat(现在改为委托给前者,并且会先切到项目目录)和 npm start 的 prestart 都会跑它。Docker 运行镜像也补上这个文件,否则容器里执行 npm start 会因为找不到 脚本而失败。 Node 版本要求改为按依赖的真实下限判断(@honeybbq/teamspeak-client 要 >=20.19、 @sansenjian/qq-music-api 要 >=20.17/22.9,21 和 23 被 better-sqlite3 与 vitest 排除),package.json 补上对应的 engines;比 20/22 LTS 更新的大版本不阻止,只提 示可能要源码编译。README 相应更新,并补一条 NODE_MODULE_VERSION 的常见问题。 注意:批处理里新增的行全部保持纯 ASCII —— cmd.exe 在括号块里遇到多字节 UTF-8 会算错文件偏移,开始吃掉后续行的 echo 前缀,中文提示一律交给 Node 脚本输出。 Closes #140 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
4e4354282d
commit
03ffd09d36
9 files changed
+968
-135
No files matched your search
+62
-10
@@ -10,8 +10,11 @@ title TSMusicBot Setup
|
||||
:: - 自动修复 PowerShell 环境变量
|
||||
:: ============================================================
|
||||
|
||||
set "SCRIPT_VERSION=2.1"
|
||||
set "SCRIPT_VERSION=2.2"
|
||||
set "MIN_NODE_MAJOR=20"
|
||||
:: Newest Node major this project is regularly tested against. Anything above
|
||||
:: still works, it just may have no prebuilt addons and fall back to a source build.
|
||||
set "TESTED_NODE_MAJOR=22"
|
||||
set "LOG_FILE=%~dp0..\setup.log"
|
||||
set "FAILED=0"
|
||||
|
||||
@@ -64,13 +67,38 @@ for /f "tokens=1 delims=v." %%a in ("%NODE_VER%") do set "NODE_MAJOR=%%a"
|
||||
call :log "Node.js version: %NODE_VER%"
|
||||
echo [OK] Node.js found: %NODE_VER%
|
||||
|
||||
if %NODE_MAJOR% LSS %MIN_NODE_MAJOR% (
|
||||
call :error "Node.js version too old. Need %MIN_NODE_MAJOR%+, found %NODE_VER%."
|
||||
:: The supported floor is not just a major version, so let node decide:
|
||||
:: @honeybbq/teamspeak-client needs >=20.19, @sansenjian/qq-music-api needs
|
||||
:: >=20.17 / >=22.9, and the odd majors (21 / 23) are excluded by
|
||||
:: better-sqlite3 and vitest. Keep this in sync with "engines" in package.json.
|
||||
node -e "const v=process.versions.node.split('.').map(Number); process.exit((v[0]===20&&v[1]>=19)||(v[0]===22&&v[1]>=12)||v[0]>=24?0:1)"
|
||||
if errorlevel 1 (
|
||||
call :error "Node.js %NODE_VER% is not supported. Use Node 20.19+ LTS or Node 22.12+ LTS."
|
||||
echo Download: https://nodejs.org/ or https://nodejs.cn/
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
:: Not fatal: setup now rebuilds the native modules for whatever ABI you run,
|
||||
:: so newer Node majors work - they are just slower to install.
|
||||
:: NOTE: keep every line inside these parenthesised blocks pure ASCII.
|
||||
:: cmd.exe mis-tracks its file offset when a block contains multi-byte UTF-8
|
||||
:: characters and starts eating the "echo " prefix of following lines.
|
||||
:: Bilingual guidance lives in the Node scripts, which print UTF-8 reliably.
|
||||
if %NODE_MAJOR% GTR %TESTED_NODE_MAJOR% (
|
||||
echo [WARN] Node %NODE_VER% is newer than the tested LTS line, Node 20 / Node 22.
|
||||
echo Newer Node majors may have no prebuilt opus / better-sqlite3,
|
||||
echo so setup falls back to a source build - slower, needs C++ build tools.
|
||||
echo Recommended: Node 20 LTS or Node 22 LTS - https://nodejs.org/ or https://nodejs.cn/
|
||||
echo This is only a warning; setup still builds the binaries for %NODE_VER%.
|
||||
call :log "[WARN] Node major %NODE_MAJOR% is newer than tested LTS %TESTED_NODE_MAJOR%"
|
||||
)
|
||||
echo.
|
||||
|
||||
:: Native addons are tied to one Node ABI. If node_modules was built by a
|
||||
:: different Node major, step 4b below detects it and repairs it.
|
||||
call :log "Node ABI for this install: see node_modules\.tsmusicbot-abi after step 4b"
|
||||
|
||||
:: ============================================================
|
||||
:: Step 2: Check npm
|
||||
:: ============================================================
|
||||
@@ -143,16 +171,40 @@ echo [OK] Backend dependencies installed.
|
||||
echo.
|
||||
|
||||
:: ============================================================
|
||||
:: Step 4b: Download native binaries from CDN
|
||||
:: Step 4b: Verify / download / repair native binaries (ABI aware)
|
||||
:: ============================================================
|
||||
call :step "4b/7" "Downloading native binaries"
|
||||
call :step "4b/7" "Checking native binaries"
|
||||
|
||||
node scripts/download-binaries.mjs %CDN_MIRROR% >>"%LOG_FILE%" 2>&1
|
||||
if errorlevel 1 (
|
||||
echo [WARN] Binary download had issues. Check %LOG_FILE% for details.
|
||||
) else (
|
||||
echo [OK] Native binaries installed.
|
||||
echo Verifying native modules for %NODE_VER% and downloading whatever is missing.
|
||||
echo Progress is shown below; the full transcript goes to the log file.
|
||||
echo.
|
||||
|
||||
:: The .mjs writes progress to stderr and - with TSMB_BINARY_LOG_STDOUT=1 - the
|
||||
:: same lines to stdout. Redirecting only stdout therefore keeps the log complete
|
||||
:: while the user still sees live progress instead of a frozen window.
|
||||
set "TSMB_BINARY_LOG_STDOUT=1"
|
||||
node scripts\download-binaries.mjs %CDN_MIRROR% >>"%LOG_FILE%"
|
||||
set "BIN_RESULT=!errorlevel!"
|
||||
set "TSMB_BINARY_LOG_STDOUT="
|
||||
|
||||
:: ASCII only inside these blocks - see the note near the Node version check.
|
||||
if not "!BIN_RESULT!"=="0" (
|
||||
set "FAILED=1"
|
||||
call :error "A required native module is unusable - see the [binary] lines above."
|
||||
echo Required: @discordjs/opus and better-sqlite3.
|
||||
echo Full log: %LOG_FILE%
|
||||
)
|
||||
|
||||
if "!FAILED!"=="1" (
|
||||
echo.
|
||||
echo Setup aborted. Fix the problem above and run this script again.
|
||||
call :log "Setup aborted at step 4b"
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [OK] Native binaries ready for %NODE_VER%.
|
||||
echo ABI recorded in node_modules\.tsmusicbot-abi
|
||||
echo.
|
||||
|
||||
:: ============================================================
|
||||
|
||||
Reference in new issue
Block a user