feat(platform): Console 支持 Linux(arm64),Windows 行为逐字不变;版本 dev_0.5.10
需求:让积分榜能在飞腾 D2000(ARM64)的 Linux 上跑起来,**同时不破坏 Windows**。
## 一、Go 服务端:交叉编译即可(**已实测**)
- SQLite 用的是 `modernc.org/sqlite`(纯 Go 驱动),全项目**没有一处 `import "C"`** → `CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build` 直接出;
- 产物是**静态链接**(`ELF 64-bit LSB executable, ARM aarch64, statically linked`)→ **不依赖 glibc 版本**,对国产系统友好;
- 本机(arm64)**实际启动验证**:数据目录、局域网地址探测、数据库迁移(0001/0002/0003)全部正常;
- 产物:`debug/服务端-arm64/scoreboard`(29 MB,`-s -w`)。
## 二、Console(Electron 宿主):平台差异收口到一个新文件
- **新增 `console/main/platform.js`**:平台差异集中在这 45 行里,其余代码不写平台判断。
⚠️ **`platform` 参数缺省按 Windows 解析** —— 漏传参数走的就是改动前那条老路(这比"改了再小心"更保守:**默认行为不变,新行为必须显式传参**)。
- `userpaths.js` / `datadir.js`:Windows 分支 `%LOCALAPPDATA%\ScoreboardConsole\` **逐字保留**;Linux 分支按 XDG(`$XDG_DATA_HOME`,缺省 `~/.local/share`)。两平台各自的"拿不到用户目录"提示文案分开写(免得现场去设一个本平台不存在的环境变量)。
- `config.js`:服务端文件名按平台取(Windows `scoreboard.exe` / Linux `scoreboard`)。
- **新增 `console/main/autostart.js`**:Linux 用 `~/.config/autostart/*.desktop`(开=写文件、关=删文件;Linux 没有"已注册但未启用"这个中间态)。
- 托盘与窗口行为:Linux 的通知区多数不派发 double-click,因此按平台分支成单击。
## 三、怎么保证没弄坏 Windows
1. **设计上**:平台差异集中 + 缺省值就是 Windows(见上);
2. **逐行核对 diff**:Windows 分支那几行原样未动;
3. **测试**:Console 由 **68 → 96 例**,新增全是平台分支用例,**既有断言一条没改**;
4. **真机验证**:构建机重打 Windows 包并跑(这一道才算收口)。
## 四、自检
全量自检两轮**全绿、`EXIT=0`**:服务端 14 包 / 前端 **944 例** / Console **96 例**。
## 版本
`dev_0.5.9` → **`dev_0.5.10`**;安装器素材同步重生成(照例只动 `brand.bmp` 两张)。
This commit is contained in:
1 parent
55051fd633
commit
efa049c827
19 files changed
+665
-58
No files matched your search
@@ -197,3 +197,71 @@ test('-config 的值换成解析出的绝对路径,其余参数原样保留',
|
||||
assert.deepEqual(withConfigArg(['-config', 'config.yaml'], null), ['-config', 'config.yaml'])
|
||||
assert.deepEqual(withConfigArg(null, '/u/config.yaml'), ['-config', '/u/config.yaml'])
|
||||
})
|
||||
|
||||
// —— 以下是 Linux 分支:用户根从 %LOCALAPPDATA% 换成 XDG 的数据目录,
|
||||
// 目录名与三项的落点(console/config.json、config.yaml、rules)一个字不变。
|
||||
test('Linux 打包态三项都落到 $XDG_DATA_HOME/ScoreboardConsole 下', () => {
|
||||
const xdg = path.resolve('/xdg/data')
|
||||
const userRoot = resolveUserRoot({ XDG_DATA_HOME: xdg }, 'linux')
|
||||
const plan = planUserPaths({ installDir: INSTALL, userRoot, isPackaged: true, platform: 'linux' })
|
||||
|
||||
assert.equal(plan.mode, 'user')
|
||||
assert.equal(plan.root, path.join(xdg, 'ScoreboardConsole'))
|
||||
assert.equal(plan.items.consoleConfig.target, path.join(xdg, 'ScoreboardConsole', 'console', 'config.json'))
|
||||
assert.equal(plan.items.serverConfig.target, path.join(xdg, 'ScoreboardConsole', 'config.yaml'))
|
||||
assert.equal(plan.items.rulesDir.target, path.join(xdg, 'ScoreboardConsole', 'rules'))
|
||||
})
|
||||
|
||||
test('Linux 没设 $XDG_DATA_HOME 时用户根落在 ~/.local/share/ScoreboardConsole', () => {
|
||||
const home = path.resolve('/home/operator')
|
||||
assert.equal(resolveUserRoot({ HOME: home }, 'linux'), path.join(home, '.local', 'share', 'ScoreboardConsole'))
|
||||
})
|
||||
|
||||
test('Linux 拿不到用户根时回落安装目录,提示文案点名 XDG 变量', () => {
|
||||
const plan = planUserPaths({
|
||||
installDir: INSTALL,
|
||||
userRoot: resolveUserRoot({}, 'linux'),
|
||||
isPackaged: true,
|
||||
platform: 'linux'
|
||||
})
|
||||
assert.equal(plan.mode, 'install')
|
||||
assert.equal(plan.reason, 'no-user-root')
|
||||
|
||||
const lines = []
|
||||
const paths = prepareUserPaths({ plan, log: (line) => lines.push(line) })
|
||||
assert.equal(paths.consoleConfig, path.join(INSTALL, 'config.json'))
|
||||
assert.equal(paths.serverConfig, null)
|
||||
assert.match(lines.join('\n'), /\$XDG_DATA_HOME/)
|
||||
assert.match(lines.join('\n'), /\$HOME/)
|
||||
})
|
||||
|
||||
test('Linux 开发态不接管,三项都指向安装目录里随包的那份', () => {
|
||||
const home = path.resolve('/home/operator')
|
||||
const plan = planUserPaths({
|
||||
installDir: INSTALL,
|
||||
userRoot: resolveUserRoot({ HOME: home }, 'linux'),
|
||||
isPackaged: false,
|
||||
platform: 'linux'
|
||||
})
|
||||
assert.equal(plan.mode, 'install')
|
||||
assert.equal(plan.reason, 'dev')
|
||||
assert.equal(plan.items.rulesDir.target, path.join(INSTALL, 'rules'))
|
||||
})
|
||||
|
||||
test('Linux 首次运行同样把随包的三项复制到用户目录', (t) => {
|
||||
const root = makeRoot(t)
|
||||
const installDir = path.join(root, 'install')
|
||||
const userRoot = path.join(root, 'xdg', 'ScoreboardConsole')
|
||||
writeFile(path.join(installDir, 'config.json'), '{"server":{"port":19541}}')
|
||||
writeFile(path.join(installDir, 'config.yaml'), 'server:\n port: 19541\n')
|
||||
writeFile(path.join(installDir, 'rules', 'cup.yaml'), 'format: scoreboard-rules\n')
|
||||
|
||||
const paths = prepareUserPaths({
|
||||
plan: planUserPaths({ installDir, userRoot, isPackaged: true, platform: 'linux' }),
|
||||
log: () => {}
|
||||
})
|
||||
|
||||
assert.equal(paths.consoleConfig, path.join(userRoot, 'console', 'config.json'))
|
||||
assert.equal(readFile(paths.serverConfig), 'server:\n port: 19541\n')
|
||||
assert.equal(readFile(path.join(userRoot, 'rules', 'cup.yaml')), 'format: scoreboard-rules\n')
|
||||
})
|
||||
Reference in new issue
Block a user