b455db0db8
- default-launcher.json files: only Wow-patched.exe from release. - config-store: strip deprecated patch-Z.MPQ from merged files; rewrite launcher.json on load if user still had that entry. - Docs/scripts examples updated; version 1.0.4. Co-authored-by: Cursor <cursoragent@cursor.com>
113 lines
4.2 KiB
JavaScript
113 lines
4.2 KiB
JavaScript
'use strict';
|
|
|
|
const path = require('path');
|
|
const fs = require('fs').promises;
|
|
|
|
/** Sources no longer shipped; drop from merged files so old launcher.json does not keep fetching them. */
|
|
const DEPRECATED_FILE_SOURCES = new Set(['patch-Z.MPQ']);
|
|
|
|
function mergeFilesList(defaults, user) {
|
|
const raw =
|
|
Array.isArray(user.files) && user.files.length ? user.files.map((e) => ({ ...e })) : defaults.files.map((e) => ({ ...e }));
|
|
const filtered = raw.filter((e) => !DEPRECATED_FILE_SOURCES.has(String(e && e.source ? e.source : '').trim()));
|
|
if (filtered.length) return filtered;
|
|
return defaults.files.map((e) => ({ ...e }));
|
|
}
|
|
|
|
function userFilesContainDeprecated(user) {
|
|
const files = user && user.files;
|
|
if (!Array.isArray(files)) return false;
|
|
return files.some((e) => DEPRECATED_FILE_SOURCES.has(String(e && e.source ? e.source : '').trim()));
|
|
}
|
|
|
|
function mergeConfig(defaults, user) {
|
|
return {
|
|
...defaults,
|
|
...user,
|
|
update_feed_url:
|
|
user.update_feed_url != null && user.update_feed_url !== ''
|
|
? user.update_feed_url
|
|
: defaults.update_feed_url,
|
|
launcher_updates_from_github:
|
|
user.launcher_updates_from_github != null
|
|
? user.launcher_updates_from_github
|
|
: defaults.launcher_updates_from_github,
|
|
github: { ...defaults.github, ...(user.github || {}) },
|
|
gitea: { ...defaults.gitea, ...(user.gitea || {}) },
|
|
patch_manifest: { ...defaults.patch_manifest, ...(user.patch_manifest || {}) },
|
|
launch: { ...defaults.launch, ...(user.launch || {}) },
|
|
auth: user.auth != null ? { ...defaults.auth, ...user.auth } : defaults.auth,
|
|
realmlist: user.realmlist != null ? { ...defaults.realmlist, ...user.realmlist } : defaults.realmlist,
|
|
files: mergeFilesList(defaults, user),
|
|
};
|
|
}
|
|
|
|
/** Hardcoded Gitea host/repo (see lib/baked-gitea-channel.js). Non-empty baked values win. */
|
|
function applyBakedGitea(cfg) {
|
|
let baked;
|
|
try {
|
|
baked = require('./baked-gitea-channel');
|
|
} catch {
|
|
return cfg;
|
|
}
|
|
if (!baked || typeof baked !== 'object') return cfg;
|
|
cfg.gitea = { ...(cfg.gitea || {}) };
|
|
for (const k of ['base_url', 'owner', 'repo', 'release_tag']) {
|
|
const v = baked[k];
|
|
if (v != null && String(v).trim() !== '') cfg.gitea[k] = String(v).trim();
|
|
}
|
|
return cfg;
|
|
}
|
|
|
|
function getConfigPath(app) {
|
|
if (process.env.FRACTURED_LAUNCHER_CONFIG) return process.env.FRACTURED_LAUNCHER_CONFIG;
|
|
if (app && app.isPackaged) {
|
|
// AppImage (and macOS .app) run from a read-only mount — cannot write beside execPath.
|
|
if (process.platform === 'linux' || process.platform === 'darwin') {
|
|
return path.join(app.getPath('userData'), 'launcher.json');
|
|
}
|
|
return path.join(path.dirname(process.execPath), 'launcher.json');
|
|
}
|
|
return path.join(__dirname, '..', 'launcher.json');
|
|
}
|
|
|
|
async function loadConfig(app) {
|
|
const p = getConfigPath(app);
|
|
const defPath = path.join(__dirname, '..', 'default-launcher.json');
|
|
const defaults = JSON.parse(await fs.readFile(defPath, 'utf8'));
|
|
try {
|
|
const user = JSON.parse(await fs.readFile(p, 'utf8'));
|
|
const config = applyBakedGitea(mergeConfig(defaults, user));
|
|
if (userFilesContainDeprecated(user)) {
|
|
await fs.writeFile(p, JSON.stringify(config, null, 2), 'utf8');
|
|
}
|
|
return { configPath: p, config };
|
|
} catch (e) {
|
|
if (e.code === 'ENOENT') {
|
|
const initial = applyBakedGitea(mergeConfig(defaults, {}));
|
|
await fs.writeFile(p, JSON.stringify(initial, null, 2), 'utf8');
|
|
return { configPath: p, config: JSON.parse(JSON.stringify(initial)) };
|
|
}
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
async function saveGameDir(configPath, gameDir) {
|
|
const defPath = path.join(__dirname, '..', 'default-launcher.json');
|
|
const defaults = JSON.parse(await fs.readFile(defPath, 'utf8'));
|
|
const user = JSON.parse(await fs.readFile(configPath, 'utf8'));
|
|
user.game_dir = gameDir;
|
|
const merged = applyBakedGitea(mergeConfig(defaults, user));
|
|
await fs.writeFile(configPath, JSON.stringify(merged, null, 2), 'utf8');
|
|
return merged;
|
|
}
|
|
|
|
function resolveGameDir(cfg, configPath) {
|
|
const gd = cfg.game_dir;
|
|
if (!gd) return '';
|
|
if (path.isAbsolute(gd)) return path.normalize(gd);
|
|
return path.normalize(path.join(path.dirname(configPath), gd));
|
|
}
|
|
|
|
module.exports = { getConfigPath, loadConfig, saveGameDir, resolveGameDir, mergeConfig, applyBakedGitea };
|