added configurable '/systemd' endpoints

This commit is contained in:
Daniel Sommer 2022-03-22 12:33:58 +01:00
parent a32544fbff
commit 1579d8480f
7 changed files with 106 additions and 13 deletions

2
.nvmrc
View file

@ -1 +1 @@
default 16

1
.vscode/launch.json vendored
View file

@ -3,6 +3,7 @@
"configurations": [ "configurations": [
{ {
"type": "pwa-node", "type": "pwa-node",
"runtimeVersion": "16",
"request": "launch", "request": "launch",
"name": "api", "name": "api",
"skipFiles": [ "skipFiles": [

View file

@ -7,6 +7,9 @@
"active": true, "active": true,
"lifetime": 0 "lifetime": 0
}, },
"systemd": [
"docker"
],
"log": { "log": {
"level": "debug", "level": "debug",
"format": "DD.MM.YYYY HH:mm:ss:SS" "format": "DD.MM.YYYY HH:mm:ss:SS"

View file

@ -4,6 +4,7 @@ const constants = require('./constants.js');
const modep = require('./modep.js'); const modep = require('./modep.js');
const osc = require('./osc.js'); const osc = require('./osc.js');
const info = require('./info.js'); const info = require('./info.js');
const systemd = require('./systemd.js');
const endpoints = new Map(); const endpoints = new Map();
@ -69,8 +70,17 @@ async function setupEndpoints() {
setEndpoint( setEndpoint(
constants.API_MIDI, constants.API_MIDI,
undefined, 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'); logger.debug('setting up ' + endpoints.size + ' endpoints took ' + util.timeDiff(timestamp) + 'ms');
} }

View file

@ -2,22 +2,45 @@ const logger = require('./logger.js');
const util = require('./util.js'); const util = require('./util.js');
const { spawn } = require('child_process'); const { spawn } = require('child_process');
function execute(cmd, args) { function execute(cmd, args, await) {
return new Promise(function (resolve, reject) { return new Promise((resolve, reject) => {
var spawned = spawn(cmd, args); let result = '';
let error = '';
const spawned = spawn(cmd, args);
spawned.timestamp = new Date(); spawned.timestamp = new Date();
spawned.stdout.on('data', function (data) { spawned.on('spawn', () => {
logger.debug(data); logger.info('spawned command \'' + cmd + '\' with args \'' + args + '\'');
if (await !== true) {
resolve();
}
}); });
spawned.stderr.on('data', function (data) { spawned.stdout.on('data', (data) => {
logger.error(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); reject('command \'' + cmd + '\' with args \'' + args + '\' encountered an error after ' + util.timeDiff(spawned.timestamp) + 'ms >>> ' + err);
}); });
spawned.on('exit', function (code) { spawned.on('exit', (code) => {
logger.debug('command \'' + cmd + '\' with args \'' + args + '\' finished with exit code ' + code + ' after ' + util.timeDiff(spawned.timestamp) + 'ms'); let msg = 'command \'' + cmd + '\' with args \'' + args + '\' finished with exit code ' + code + ' after ' + util.timeDiff(spawned.timestamp) + 'ms';
resolve(); 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);
}); });
}); });
} }

View file

@ -8,6 +8,11 @@ const PEDALBOARDS = '/pedalboards';
const PEDALS = '/pedals'; const PEDALS = '/pedals';
const BYPASS = '/bypass'; const BYPASS = '/bypass';
const MIDI = '/midi'; 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; exports.VARIABLE_ID = VARIABLE_ID;
@ -27,6 +32,7 @@ exports.API_PEDAL_BY_ID = PEDALS + '/' + VARIABLE_ID;
exports.API_BYPASS = BYPASS; exports.API_BYPASS = BYPASS;
exports.API_BYPASS_BY_ID = BYPASS + '/' + VARIABLE_ID; exports.API_BYPASS_BY_ID = BYPASS + '/' + VARIABLE_ID;
exports.API_MIDI = MIDI; exports.API_MIDI = MIDI;
exports.API_SYSTEMD = SYSTEMD;
exports.CACHE_INFO = "info"; exports.CACHE_INFO = "info";
exports.CACHE_BANKS = "banks"; exports.CACHE_BANKS = "banks";

50
libs/systemd.js Normal file
View file

@ -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
}