Cleanup repo, add Gitea CI/CD workflow, improve error handling
All checks were successful
Deploy GSM / deploy (push) Successful in 1m25s
All checks were successful
Deploy GSM / deploy (push) Successful in 1m25s
- Remove temp files and reorganize docs - Add .gitea/workflows/deploy.yml for automated deployment - Add unreachable host checks to server routes (/:id, logs, start/stop/restart) - Add unreachable checks to config routes (zomboid, terraria, openttd) - Return HTTP 503 with unreachable flag instead of crashing Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -200,9 +200,16 @@ router.get("/zomboid/config", authenticateToken, requireRole("moderator"), async
|
||||
const server = config.servers.find(s => s.type === "zomboid");
|
||||
if (!server) return res.status(404).json({ error: "Zomboid server not configured" });
|
||||
|
||||
if (isHostFailed(server.host, server.sshUser)) {
|
||||
return res.status(503).json({ error: "Server host is unreachable", unreachable: true });
|
||||
}
|
||||
|
||||
const files = await listZomboidConfigs(server);
|
||||
res.json({ files });
|
||||
} catch (err) {
|
||||
if (err.message.includes('unreachable') || err.message.includes('ECONNREFUSED') || err.message.includes('ETIMEDOUT')) {
|
||||
return res.status(503).json({ error: 'Server host is unreachable', unreachable: true });
|
||||
}
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
@@ -419,10 +426,18 @@ router.get("/terraria/config", authenticateToken, requireRole("moderator"), asyn
|
||||
const config = loadConfig();
|
||||
const server = config.servers.find(s => s.id === "terraria");
|
||||
if (!server) return res.status(404).json({ error: "Server not found" });
|
||||
|
||||
if (isHostFailed(server.host, server.sshUser)) {
|
||||
return res.status(503).json({ error: "Server host is unreachable", unreachable: true });
|
||||
}
|
||||
|
||||
const content = await readTerrariaConfig(server);
|
||||
res.json({ content });
|
||||
} catch (error) {
|
||||
console.error("Error reading Terraria config:", error);
|
||||
if (error.message.includes('unreachable') || error.message.includes('ECONNREFUSED') || error.message.includes('ETIMEDOUT')) {
|
||||
return res.status(503).json({ error: 'Server host is unreachable', unreachable: true });
|
||||
}
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
@@ -452,10 +467,18 @@ router.get("/openttd/config", authenticateToken, requireRole("moderator"), async
|
||||
const config = loadConfig();
|
||||
const server = config.servers.find(s => s.id === "openttd");
|
||||
if (!server) return res.status(404).json({ error: "Server not found" });
|
||||
|
||||
if (isHostFailed(server.host, server.sshUser)) {
|
||||
return res.status(503).json({ error: "Server host is unreachable", unreachable: true });
|
||||
}
|
||||
|
||||
const content = await readOpenTTDConfig(server);
|
||||
res.json({ content });
|
||||
} catch (error) {
|
||||
console.error("Error reading OpenTTD config:", error);
|
||||
if (error.message.includes('unreachable') || error.message.includes('ECONNREFUSED') || error.message.includes('ETIMEDOUT')) {
|
||||
return res.status(503).json({ error: 'Server host is unreachable', unreachable: true });
|
||||
}
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
@@ -487,11 +510,41 @@ router.get('/:id', optionalAuth, async (req, res) => {
|
||||
}
|
||||
|
||||
try {
|
||||
// Check if host is unreachable
|
||||
const hostUnreachable = isHostFailed(server.host, server.sshUser);
|
||||
if (hostUnreachable) {
|
||||
const metrics = await getCurrentMetrics(server.id).catch(() => ({
|
||||
cpu: 0, cpuCores: 1, memory: 0, memoryUsed: 0, memoryTotal: 0, uptime: 0
|
||||
}));
|
||||
const memTotal = formatBytes(metrics.memoryTotal);
|
||||
const memUsed = formatBytes(metrics.memoryUsed, memTotal.unit);
|
||||
return res.json({
|
||||
id: server.id,
|
||||
name: server.name,
|
||||
type: server.type,
|
||||
status: "unreachable",
|
||||
running: false,
|
||||
metrics: {
|
||||
cpu: metrics.cpu,
|
||||
cpuCores: metrics.cpuCores,
|
||||
memory: metrics.memory,
|
||||
memoryUsed: memUsed.value,
|
||||
memoryTotal: memTotal.value,
|
||||
memoryUnit: memTotal.unit,
|
||||
uptime: 0
|
||||
},
|
||||
players: { online: 0, max: null, list: [] },
|
||||
hasRcon: !!server.rconPassword
|
||||
});
|
||||
}
|
||||
|
||||
const [status, metrics, players, playerList, processUptime] = await Promise.all([
|
||||
getServerStatus(server),
|
||||
getCurrentMetrics(server.id),
|
||||
server.rconPassword ? getPlayers(server) : { online: 0, max: null },
|
||||
server.rconPassword ? getPlayerList(server) : { players: [] },
|
||||
getCurrentMetrics(server.id).catch(() => ({
|
||||
cpu: 0, cpuCores: 1, memory: 0, memoryUsed: 0, memoryTotal: 0, uptime: 0
|
||||
})),
|
||||
server.rconPassword ? getPlayers(server).catch(() => ({ online: 0, max: null })) : { online: 0, max: null },
|
||||
server.rconPassword ? getPlayerList(server).catch(() => ({ players: [] })) : { players: [] },
|
||||
getProcessUptime(server).catch(() => 0)
|
||||
]);
|
||||
|
||||
@@ -520,6 +573,7 @@ router.get('/:id', optionalAuth, async (req, res) => {
|
||||
hasRcon: !!server.rconPassword
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(`Error fetching server ${req.params.id}:`, err.message);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
@@ -571,11 +625,18 @@ router.get('/:id/logs', authenticateToken, requireRole('moderator'), async (req,
|
||||
const server = config.servers.find(s => s.id === req.params.id);
|
||||
if (!server) return res.status(404).json({ error: 'Server not found' });
|
||||
|
||||
if (isHostFailed(server.host, server.sshUser)) {
|
||||
return res.status(503).json({ error: 'Server host is unreachable', unreachable: true });
|
||||
}
|
||||
|
||||
try {
|
||||
const lines = parseInt(req.query.lines) || 100;
|
||||
const logs = await getConsoleLog(server, lines);
|
||||
res.json({ logs });
|
||||
} catch (err) {
|
||||
if (err.message.includes('unreachable') || err.message.includes('ECONNREFUSED') || err.message.includes('ETIMEDOUT')) {
|
||||
return res.status(503).json({ error: 'Server host is unreachable', unreachable: true });
|
||||
}
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
@@ -586,12 +647,19 @@ router.post('/:id/start', authenticateToken, requireRole('moderator'), async (re
|
||||
const server = config.servers.find(s => s.id === req.params.id);
|
||||
if (!server) return res.status(404).json({ error: 'Server not found' });
|
||||
|
||||
if (isHostFailed(server.host, server.sshUser)) {
|
||||
return res.status(503).json({ error: 'Server host is unreachable', unreachable: true });
|
||||
}
|
||||
|
||||
try {
|
||||
const { save } = req.body || {};
|
||||
await startServer(server, { save });
|
||||
logActivity(req.user.id, req.user.username, 'server_start', server.id, save ? 'Save: ' + save : null, req.user.discordId, req.user.avatar);
|
||||
res.json({ message: 'Server starting' });
|
||||
} catch (err) {
|
||||
if (err.message.includes('unreachable') || err.message.includes('ECONNREFUSED') || err.message.includes('ETIMEDOUT')) {
|
||||
return res.status(503).json({ error: 'Server host is unreachable', unreachable: true });
|
||||
}
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
@@ -601,11 +669,18 @@ router.post('/:id/stop', authenticateToken, requireRole('moderator'), async (req
|
||||
const server = config.servers.find(s => s.id === req.params.id);
|
||||
if (!server) return res.status(404).json({ error: 'Server not found' });
|
||||
|
||||
if (isHostFailed(server.host, server.sshUser)) {
|
||||
return res.status(503).json({ error: 'Server host is unreachable', unreachable: true });
|
||||
}
|
||||
|
||||
try {
|
||||
await stopServer(server);
|
||||
logActivity(req.user.id, req.user.username, 'server_stop', server.id, null, req.user.discordId, req.user.avatar);
|
||||
res.json({ message: 'Server stopping' });
|
||||
} catch (err) {
|
||||
if (err.message.includes('unreachable') || err.message.includes('ECONNREFUSED') || err.message.includes('ETIMEDOUT')) {
|
||||
return res.status(503).json({ error: 'Server host is unreachable', unreachable: true });
|
||||
}
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
@@ -615,11 +690,18 @@ router.post('/:id/restart', authenticateToken, requireRole('moderator'), async (
|
||||
const server = config.servers.find(s => s.id === req.params.id);
|
||||
if (!server) return res.status(404).json({ error: 'Server not found' });
|
||||
|
||||
if (isHostFailed(server.host, server.sshUser)) {
|
||||
return res.status(503).json({ error: 'Server host is unreachable', unreachable: true });
|
||||
}
|
||||
|
||||
try {
|
||||
await restartServer(server);
|
||||
logActivity(req.user.id, req.user.username, 'server_restart', server.id, null, req.user.discordId, req.user.avatar);
|
||||
res.json({ message: 'Server restarting' });
|
||||
} catch (err) {
|
||||
if (err.message.includes('unreachable') || err.message.includes('ECONNREFUSED') || err.message.includes('ETIMEDOUT')) {
|
||||
return res.status(503).json({ error: 'Server host is unreachable', unreachable: true });
|
||||
}
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user