Files

69 lines
2.6 KiB
JavaScript

import { spawn } from 'node:child_process';
import { existsSync, readFileSync } from 'node:fs';
import { join } from 'node:path';
import { serverInstallDir } from './paths.js';
const STEAMCMD_PATH = process.env.STEAMCMD_PATH || '/opt/steamcmd/steamcmd.sh';
const WINDROSE_APP_ID = Number(process.env.WINDROSE_APP_ID || '4129620');
function getSteamLoginArgs() {
const username = process.env.STEAM_USERNAME;
const password = process.env.STEAM_PASSWORD;
const gslt = process.env.STEAM_GSLT;
if (!username) {
throw new Error("STEAM_USERNAME is required but not set.");
}
// Prefer GSLT if provided (safer for headless servers)
if (gslt) {
return ['+login', username, gslt];
}
if (!password) {
throw new Error("STEAM_PASSWORD is required but not set (or provide STEAM_GSLT).");
}
return ['+login', username, password];
}
export function runSteamCmd(args) {
// === ENV DEBUG START ===
console.log("=== ENV DUMP START ===");
console.log("STEAM_USERNAME =", process.env.STEAM_USERNAME);
console.log("STEAM_PASSWORD =", process.env.STEAM_PASSWORD);
console.log("STEAM_GSLT =", process.env.STEAM_GSLT);
console.log("=== ENV DUMP END ===");
// === ENV DEBUG END ===
return new Promise((resolve, reject) => {
const child = spawn(STEAMCMD_PATH, args, {
env: process.env,
});
child.stdout.on('data', (d) => process.stdout.write(d));
child.stderr.on('data', (d) => process.stderr.write(d));
child.on('exit', (code) => {
if (code === 0)
resolve();
else
reject(new Error(`SteamCMD exited with code ${code}`));
});
child.on('error', reject);
});
}
export async function installOrUpdateServer(id, appId) {
const installDir = serverInstallDir(id);
const steamArgs = [
'+force_install_dir', installDir,
...getSteamLoginArgs(),
'+app_update', String(appId), 'validate',
'+quit',
];
await runSteamCmd(steamArgs);
}
export async function readInstalledVersion(id) {
const installDir = serverInstallDir(id);
const manifestPath = join(installDir, 'steamapps', `appmanifest_${WINDROSE_APP_ID}.acf`);
if (!existsSync(manifestPath))
return null;
const raw = readFileSync(manifestPath, 'utf-8');
const buildIdMatch = raw.match(/"buildid"\s+"(\d+)"/);
const timeUpdatedMatch = raw.match(/"LastUpdated"\s+"(\d+)"/);
return {
buildId: buildIdMatch ? Number(buildIdMatch[1]) : null,
lastUpdated: timeUpdatedMatch ? Number(timeUpdatedMatch[1]) : null,
};
}