Show Space Engineers build ID and last update time in detail view
All checks were successful
Deploy GSM / deploy (push) Successful in 23s
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:
75
gsm-backend/services/serverVersions.js
Normal file
75
gsm-backend/services/serverVersions.js
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user