From 1579d8480fc5b10d652bb63878d43d946c708e61 Mon Sep 17 00:00:00 2001 From: velvettear Date: Tue, 22 Mar 2022 12:33:58 +0100 Subject: [PATCH] added configurable '/systemd' endpoints --- .nvmrc | 2 +- .vscode/launch.json | 1 + config.json | 3 +++ libs/api.js | 12 ++++++++++- libs/commands.js | 45 ++++++++++++++++++++++++++++++---------- libs/constants.js | 6 ++++++ libs/systemd.js | 50 +++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 106 insertions(+), 13 deletions(-) create mode 100644 libs/systemd.js diff --git a/.nvmrc b/.nvmrc index 331d858..19c7bdb 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -default \ No newline at end of file +16 \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 3451e71..3d28bc0 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -3,6 +3,7 @@ "configurations": [ { "type": "pwa-node", + "runtimeVersion": "16", "request": "launch", "name": "api", "skipFiles": [ diff --git a/config.json b/config.json index 96f10b1..d6009fb 100644 --- a/config.json +++ b/config.json @@ -7,6 +7,9 @@ "active": true, "lifetime": 0 }, + "systemd": [ + "docker" + ], "log": { "level": "debug", "format": "DD.MM.YYYY HH:mm:ss:SS" diff --git a/libs/api.js b/libs/api.js index 643405a..b4c6f00 100644 --- a/libs/api.js +++ b/libs/api.js @@ -4,6 +4,7 @@ const constants = require('./constants.js'); const modep = require('./modep.js'); const osc = require('./osc.js'); const info = require('./info.js'); +const systemd = require('./systemd.js'); const endpoints = new Map(); @@ -69,8 +70,17 @@ async function setupEndpoints() { setEndpoint( constants.API_MIDI, undefined, - { method: osc.sendByRequest} + { method: osc.sendByRequest } ) + if (global.config.systemd !== undefined) { + for (let index = 0; index < global.config.systemd.length; index++) { + setEndpoint( + constants.API_SYSTEMD + '/' + global.config.systemd[index], + { method: systemd.getServiceState }, + { method: systemd.setServiceState } + ) + } + } logger.debug('setting up ' + endpoints.size + ' endpoints took ' + util.timeDiff(timestamp) + 'ms'); } diff --git a/libs/commands.js b/libs/commands.js index c329bc6..18efe9d 100644 --- a/libs/commands.js +++ b/libs/commands.js @@ -2,22 +2,45 @@ const logger = require('./logger.js'); const util = require('./util.js'); const { spawn } = require('child_process'); -function execute(cmd, args) { - return new Promise(function (resolve, reject) { - var spawned = spawn(cmd, args); +function execute(cmd, args, await) { + return new Promise((resolve, reject) => { + let result = ''; + let error = ''; + const spawned = spawn(cmd, args); spawned.timestamp = new Date(); - spawned.stdout.on('data', function (data) { - logger.debug(data); + spawned.on('spawn', () => { + logger.info('spawned command \'' + cmd + '\' with args \'' + args + '\''); + if (await !== true) { + resolve(); + } }); - spawned.stderr.on('data', function (data) { - logger.error(data); + spawned.stdout.on('data', (data) => { + result += data; }); - spawned.on('error', function (err) { + spawned.stderr.on('data', (data) => { + if (data.toString().toLowerCase().startsWith('warning')) { + result += data; + return; + } + error += data; + }); + spawned.on('error', (err) => { reject('command \'' + cmd + '\' with args \'' + args + '\' encountered an error after ' + util.timeDiff(spawned.timestamp) + 'ms >>> ' + err); }); - spawned.on('exit', function (code) { - logger.debug('command \'' + cmd + '\' with args \'' + args + '\' finished with exit code ' + code + ' after ' + util.timeDiff(spawned.timestamp) + 'ms'); - resolve(); + spawned.on('exit', (code) => { + let msg = 'command \'' + cmd + '\' with args \'' + args + '\' finished with exit code ' + code + ' after ' + util.timeDiff(spawned.timestamp) + 'ms'; + if (error !== undefined && error.length > 0) { + error = error.trim(); + msg += ' > error: ' + error; + logger.error(error); + return reject(error); + } + if (result !== undefined && result.length > 0) { + result = result.trim(); + msg += ' > data: ' + result; + } + logger.info(msg); + resolve(result); }); }); } diff --git a/libs/constants.js b/libs/constants.js index 0e3bb8d..eeab937 100644 --- a/libs/constants.js +++ b/libs/constants.js @@ -8,6 +8,11 @@ const PEDALBOARDS = '/pedalboards'; const PEDALS = '/pedals'; const BYPASS = '/bypass'; const MIDI = '/midi'; +const SYSTEMD = '/systemd'; + +exports.SYSTEMD_STATE_ACTIVE = 'active'; +exports.SYSTEMD_STATE_INACTIVE = 'inactive'; +exports.SYSTEMD_STATE_TOGGLE = 'toggle'; exports.VARIABLE_ID = VARIABLE_ID; @@ -27,6 +32,7 @@ exports.API_PEDAL_BY_ID = PEDALS + '/' + VARIABLE_ID; exports.API_BYPASS = BYPASS; exports.API_BYPASS_BY_ID = BYPASS + '/' + VARIABLE_ID; exports.API_MIDI = MIDI; +exports.API_SYSTEMD = SYSTEMD; exports.CACHE_INFO = "info"; exports.CACHE_BANKS = "banks"; diff --git a/libs/systemd.js b/libs/systemd.js new file mode 100644 index 0000000..bd41676 --- /dev/null +++ b/libs/systemd.js @@ -0,0 +1,50 @@ +const logger = require('./logger.js'); +const commands = require('./commands.js'); +const constants = require('./constants.js'); +const blinky = require('./blinky.js'); + +async function getServiceState(name) { + if (name === undefined) { + return; + } + logger.debug('checking service \'' + name + '\'...'); + const state = await commands.execute('systemctl', ['is-active', name], true); + logger.debug('state of service \'' + name + '\' is \'' + state + '\''); + return { service: name, state: state }; +} + +async function setServiceState(name, args) { + if (name === undefined || args === undefined) { + return; + } + let state = args.get('state'); + if (state === undefined) { + return; + } + if (state !== constants.SYSTEMD_STATE_ACTIVE && state !== constants.SYSTEMD_STATE_INACTIVE && state !== constants.SYSTEMD_STATE_TOGGLE) { + const msg = 'can not set state of service \'' + name + '\' to unknown state \'' + state + '\''; + logger.debug(msg); + return { err: msg }; + } + let service = await getServiceState(name); + if (state !== constants.SYSTEMD_STATE_TOGGLE && service.state === state) { + const msg = 'service \'' + name + '\' is already in state \'' + service.state + '\''; + logger.debug(msg); + return { msg: msg }; + } + let command; + if (service.state === constants.SYSTEMD_STATE_ACTIVE) { + command = 'stop'; + state = constants.SYSTEMD_STATE_INACTIVE; + } else if (service.state === constants.SYSTEMD_STATE_INACTIVE) { + command = 'start'; + state = constants.SYSTEMD_STATE_ACTIVE; + } + logger.debug('setting state of service \'' + name + '\' to \'' + state + '\'...'); + return { service: name, state: state, result: await commands.execute('systemctl', [command, name], true)}; +} + +module.exports = { + getServiceState, + setServiceState +} \ No newline at end of file