Show Space Engineers build ID and last update time in detail view
All checks were successful
Deploy GSM / deploy (push) Successful in 23s

Reads the SteamCMD appmanifest_298740.acf via SSH and exposes
buildid + LastUpdated through a new /api/servers/:id/version endpoint.
The overview tab now renders a "Server Version" card and surfaces a
pending update hint when TargetBuildID differs from the installed build.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-10 20:02:40 +02:00
parent 7bc93f3b70
commit bb48f75b5d
4 changed files with 161 additions and 1 deletions

View File

@@ -0,0 +1,75 @@
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 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;
}