Files
2026-08-27 08:57:14 +02:00

90 lines
2.5 KiB
JavaScript

const express = require("express");
const fs = require("fs");
const path = require("path");
const { exec } = require("child_process");
const crypto = require("crypto");
const PORT = process.env.PORT || 3000;
const DATA_FILE = path.join(__dirname, "commands.json");
const CEC_TIMEOUT_MS = 15000;
const app = express();
app.use(express.json());
app.use(express.static(path.join(__dirname, "public")));
function loadCommands() {
try {
return JSON.parse(fs.readFileSync(DATA_FILE, "utf8"));
} catch {
return [];
}
}
function saveCommands(commands) {
fs.writeFileSync(DATA_FILE, JSON.stringify(commands, null, 2) + "\n");
}
// Alle gespeicherten Befehle
app.get("/api/commands", (req, res) => {
res.json(loadCommands());
});
// Neuen Befehl anlegen
app.post("/api/commands", (req, res) => {
const name = (req.body.name || "").trim();
const command = (req.body.command || "").trim();
if (!name || !command) {
return res.status(400).json({ error: "Name und Command dürfen nicht leer sein." });
}
const commands = loadCommands();
const entry = { id: crypto.randomUUID(), name, command };
commands.push(entry);
saveCommands(commands);
res.status(201).json(entry);
});
// Befehl löschen
app.delete("/api/commands/:id", (req, res) => {
const commands = loadCommands();
const remaining = commands.filter((c) => c.id !== req.params.id);
if (remaining.length === commands.length) {
return res.status(404).json({ error: "Befehl nicht gefunden." });
}
saveCommands(remaining);
res.json({ ok: true });
});
// Befehl als Shell-Kommando ausführen
app.post("/api/commands/:id/run", (req, res) => {
const entry = loadCommands().find((c) => c.id === req.params.id);
if (!entry) {
return res.status(404).json({ error: "Befehl nicht gefunden." });
}
exec(entry.command, { timeout: CEC_TIMEOUT_MS }, (error, stdout, stderr) => {
const output = (stdout + stderr).trim();
if (error?.killed) {
return res.status(504).json({
error: `Befehl wurde nach ${CEC_TIMEOUT_MS / 1000}s abgebrochen (${error.signal}).`,
command: entry.command,
output,
});
}
if (error && typeof error.code !== "number") {
return res.status(500).json({
error: `Befehl konnte nicht ausgeführt werden: ${error.message}`,
command: entry.command,
});
}
const exitCode = error ? error.code : 0;
res.json({ ok: exitCode === 0, exitCode, command: entry.command, output });
});
});
app.listen(PORT, () => {
console.log(`CEC-Tool läuft auf http://localhost:${PORT}`);
});