90 lines
2.5 KiB
JavaScript
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}`);
|
|
});
|