All checks were successful
Deploy GSM / deploy (push) Successful in 21s
The mmmaxwwwell SE image calls steamcmd with +login before +force_install_dir,
which Steam rejects ("Please use force_install_dir before logon!"), so container
restarts never actually update the game. The new handler runs SteamCMD in a
sibling one-shot container with the correct argument order, mounting the same
volumes as the live container, then leaves the server stopped for the operator
to start. The version cache is invalidated after a successful update so the UI
shows the new build immediately.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
80 lines
2.3 KiB
JavaScript
80 lines
2.3 KiB
JavaScript
import { NodeSSH } from "node-ssh";
|
|
|
|
const SSH_TIMEOUT = 15000;
|
|
const sshConnections = new Map();
|
|
|
|
async function getConnection(host, username = "root") {
|
|
const key = username + "@" + host;
|
|
if (sshConnections.has(key)) {
|
|
const conn = sshConnections.get(key);
|
|
if (conn.isConnected()) return conn;
|
|
sshConnections.delete(key);
|
|
}
|
|
const ssh = new NodeSSH();
|
|
await ssh.connect({
|
|
host,
|
|
username,
|
|
privateKeyPath: "/root/.ssh/id_ed25519",
|
|
readyTimeout: SSH_TIMEOUT
|
|
});
|
|
sshConnections.set(key, ssh);
|
|
return ssh;
|
|
}
|
|
|
|
const SE_APPMANIFEST = "/opt/spaceengineers/appdata/space-engineers/bins/SpaceEngineersDedicated/steamapps/appmanifest_298740.acf";
|
|
|
|
async function getSpaceEngineersVersion(server) {
|
|
const ssh = await getConnection(server.host, server.sshUser);
|
|
const result = await ssh.execCommand(`cat ${SE_APPMANIFEST} 2>/dev/null`);
|
|
const text = result.stdout || "";
|
|
if (!text) return null;
|
|
|
|
const buildidMatch = text.match(/"buildid"\s*"([^"]+)"/);
|
|
const lastUpdatedMatch = text.match(/"LastUpdated"\s*"([^"]+)"/);
|
|
const targetBuildMatch = text.match(/"TargetBuildID"\s*"([^"]+)"/);
|
|
|
|
const buildid = buildidMatch ? buildidMatch[1] : null;
|
|
const lastUpdatedUnix = lastUpdatedMatch ? parseInt(lastUpdatedMatch[1], 10) : null;
|
|
const targetBuild = targetBuildMatch ? targetBuildMatch[1] : null;
|
|
|
|
if (!buildid) return null;
|
|
|
|
return {
|
|
version: buildid,
|
|
lastUpdated: lastUpdatedUnix ? new Date(lastUpdatedUnix * 1000).toISOString() : null,
|
|
updatePending: targetBuild && targetBuild !== "0" && targetBuild !== buildid ? targetBuild : null,
|
|
source: "steam-appmanifest"
|
|
};
|
|
}
|
|
|
|
const versionHandlers = {
|
|
spaceengineers: getSpaceEngineersVersion
|
|
};
|
|
|
|
const versionCache = new Map();
|
|
const CACHE_TTL_MS = 60_000;
|
|
|
|
export function supportsVersionInfo(serverType) {
|
|
return !!versionHandlers[serverType];
|
|
}
|
|
|
|
export function invalidateVersionCache(serverId) {
|
|
versionCache.delete(serverId);
|
|
}
|
|
|
|
export async function getVersionInfo(server) {
|
|
const handler = versionHandlers[server.type];
|
|
if (!handler) return null;
|
|
|
|
const cached = versionCache.get(server.id);
|
|
if (cached && Date.now() - cached.fetchedAt < CACHE_TTL_MS) {
|
|
return cached.data;
|
|
}
|
|
|
|
const data = await handler(server);
|
|
if (data) {
|
|
versionCache.set(server.id, { data, fetchedAt: Date.now() });
|
|
}
|
|
return data;
|
|
}
|