initialize generic rms-software repository
Add the reusable RMS core application (server, web UI, plugins, tests, tools) with generic defaults, GPL licensing, and maintainer context documentation so deployments can consume this repo as software source independent of station-specific overlays.
This commit is contained in:
122
plugins/rms.station.shell/index.js
Normal file
122
plugins/rms.station.shell/index.js
Normal file
@@ -0,0 +1,122 @@
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
|
||||
async function createPlugin(ctx) {
|
||||
return {
|
||||
async execute(action, input) {
|
||||
if (action === "activate") {
|
||||
return runConfigured(ctx, "SCRIPT_ACTIVATE", input && input.userEmail);
|
||||
}
|
||||
if (action === "deactivate") {
|
||||
return runConfigured(ctx, "SCRIPT_DEACTIVATE", input && input.userEmail);
|
||||
}
|
||||
throw new Error(`Unknown action: ${action}`);
|
||||
},
|
||||
async health() {
|
||||
return { ok: true };
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function runConfigured(ctx, key, userEmail) {
|
||||
const configuredKey = key === "SCRIPT_ACTIVATE" ? "scriptActivate" : "scriptDeactivate";
|
||||
const command = String(ctx.getSetting(configuredKey, ctx.env[key] || "")).trim();
|
||||
if (!command) {
|
||||
return {
|
||||
ok: true,
|
||||
skipped: true,
|
||||
message: `Kein Kommando in ${key} gesetzt`
|
||||
};
|
||||
}
|
||||
const simulate = typeof ctx.simulateHardware === "boolean"
|
||||
? ctx.simulateHardware
|
||||
: (process.platform !== "linux" && String(ctx.env.ALLOW_NON_LINUX_CMDS || "false") !== "true");
|
||||
if (simulate) {
|
||||
return {
|
||||
ok: true,
|
||||
skipped: true,
|
||||
message: `${key} nur simuliert (${ctx.execMode || "dev"})`
|
||||
};
|
||||
}
|
||||
const fallbackCheck = resolveMissingDefaultScriptFallback(ctx, key, command);
|
||||
if (fallbackCheck.skip) {
|
||||
return {
|
||||
ok: true,
|
||||
skipped: true,
|
||||
message: fallbackCheck.message
|
||||
};
|
||||
}
|
||||
const commandToRun = fallbackCheck.command || command;
|
||||
const cwdSetting = ctx.getSetting("scriptRoot", ctx.env.SCRIPT_ROOT || "../Remotestation-Bestand-Submodules/sk");
|
||||
const cwd = path.resolve(ctx.rootDir, String(cwdSetting));
|
||||
const timeoutMs = Number(ctx.getSetting("timeoutMs", ctx.env.STATION_SCRIPT_TIMEOUT_MS || 180000));
|
||||
const result = await ctx.commandRunner(commandToRun, {
|
||||
cwd,
|
||||
env: {
|
||||
RMS_USER_EMAIL: userEmail || "",
|
||||
RMS_ACTION: key === "SCRIPT_ACTIVATE" ? "activate" : "deactivate"
|
||||
},
|
||||
timeoutMs
|
||||
});
|
||||
if (!result.ok) {
|
||||
throw new Error(result.stderr || result.error || `${key} failed`);
|
||||
}
|
||||
return {
|
||||
ok: true,
|
||||
message: `${key} ausgefuehrt`
|
||||
};
|
||||
}
|
||||
|
||||
function resolveMissingDefaultScriptFallback(ctx, key, command) {
|
||||
const parts = splitCommand(command);
|
||||
if (parts.length === 0) {
|
||||
return { skip: true, message: `${key} leer` };
|
||||
}
|
||||
const executable = parts[0];
|
||||
const defaultPath = key === "SCRIPT_ACTIVATE"
|
||||
? "/opt/remotestation/bin/activate.sh"
|
||||
: "/opt/remotestation/bin/deactivate.sh";
|
||||
if (executable !== defaultPath || fs.existsSync(executable)) {
|
||||
return { skip: false, command };
|
||||
}
|
||||
|
||||
const fallback = findRuntimeFallbackScript(ctx, key);
|
||||
if (fallback) {
|
||||
return { skip: false, command: [fallback].concat(parts.slice(1)).join(" ") };
|
||||
}
|
||||
|
||||
return {
|
||||
skip: true,
|
||||
message: `${key} Standardskript fehlt (${defaultPath}), Aktion ohne externes Skript fortgesetzt`
|
||||
};
|
||||
}
|
||||
|
||||
function findRuntimeFallbackScript(ctx, key) {
|
||||
const fileName = key === "SCRIPT_ACTIVATE" ? "activate.sh" : "deactivate.sh";
|
||||
const scriptRoot = String(ctx.env.SCRIPT_ROOT || "/opt/remotestation").trim() || "/opt/remotestation";
|
||||
const candidates = [
|
||||
path.join(scriptRoot, "src", "tx-runtime", "bin", fileName),
|
||||
path.join(scriptRoot, "src", "tx-runtime", fileName),
|
||||
path.join(scriptRoot, "src", "openWebTrX", "bin", fileName),
|
||||
path.join(scriptRoot, "src", "openWebTrX", fileName),
|
||||
path.resolve(ctx.rootDir, "../Remotestation-Bestand-Submodules/sk/bin", fileName)
|
||||
];
|
||||
for (const candidate of candidates) {
|
||||
try {
|
||||
if (fs.existsSync(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
} catch {
|
||||
// ignore invalid candidate
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function splitCommand(commandString) {
|
||||
return commandString.match(/(?:[^\s\"]+|\"[^\"]*\")+/g)?.map((part) => part.replace(/^\"|\"$/g, "")) || [];
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createPlugin
|
||||
};
|
||||
21
plugins/rms.station.shell/manifest.json
Normal file
21
plugins/rms.station.shell/manifest.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"id": "rms.station.shell",
|
||||
"name": "Station Shell Control",
|
||||
"version": "1.0.0",
|
||||
"apiVersion": "1.0",
|
||||
"capabilities": [
|
||||
"station.activate",
|
||||
"station.deactivate"
|
||||
],
|
||||
"settingsSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"scriptActivate": { "type": "string" },
|
||||
"scriptDeactivate": { "type": "string" },
|
||||
"scriptRoot": { "type": "string" },
|
||||
"timeoutMs": { "type": "integer", "minimum": 1000 }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"uiControls": []
|
||||
}
|
||||
Reference in New Issue
Block a user