added possibility to spawn commands with sudo, optimized some stuff
This commit is contained in:
parent
e2b7a71c8e
commit
3e40dc85e7
11 changed files with 205 additions and 205 deletions
1
.vscode/launch.json
vendored
1
.vscode/launch.json
vendored
|
@ -3,6 +3,7 @@
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"type": "pwa-node",
|
"type": "pwa-node",
|
||||||
|
"runtimeVersion": "17",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "ninwa",
|
"name": "ninwa",
|
||||||
"skipFiles": [
|
"skipFiles": [
|
||||||
|
|
15
config.json
15
config.json
|
@ -5,8 +5,9 @@
|
||||||
},
|
},
|
||||||
"watchers": [
|
"watchers": [
|
||||||
{
|
{
|
||||||
"device": "usb-Razer_Razer_Blade_Stealth-if01-event-kbd",
|
"device": "/dev/input/by-id/usb-Chicony_HP_Elite_USB_Keyboard-event-kbd",
|
||||||
"restart": true,
|
"restart": true,
|
||||||
|
"sudo": true,
|
||||||
"keys": [
|
"keys": [
|
||||||
{
|
{
|
||||||
"key": "key_f1",
|
"key": "key_f1",
|
||||||
|
@ -21,7 +22,8 @@
|
||||||
"args": [
|
"args": [
|
||||||
"combo",
|
"combo",
|
||||||
"{{ key }} {{ type }}"
|
"{{ key }} {{ type }}"
|
||||||
]
|
],
|
||||||
|
"sudo": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "key_enter",
|
"key": "key_enter",
|
||||||
|
@ -30,7 +32,8 @@
|
||||||
"args": [
|
"args": [
|
||||||
"{{ key }}",
|
"{{ key }}",
|
||||||
"{{ type }}"
|
"{{ type }}"
|
||||||
]
|
],
|
||||||
|
"sudo": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "key_esc",
|
"key": "key_esc",
|
||||||
|
@ -39,7 +42,8 @@
|
||||||
"args": [
|
"args": [
|
||||||
"{{ key }}",
|
"{{ key }}",
|
||||||
"{{ type }}"
|
"{{ type }}"
|
||||||
]
|
],
|
||||||
|
"sudo": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "key_space",
|
"key": "key_space",
|
||||||
|
@ -49,7 +53,8 @@
|
||||||
"args": [
|
"args": [
|
||||||
"{{ key }}",
|
"{{ key }}",
|
||||||
"{{ type }}"
|
"{{ type }}"
|
||||||
]
|
],
|
||||||
|
"sudo": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
1
libs/.nvmrc
Normal file
1
libs/.nvmrc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
17
|
95
libs/cli.js
95
libs/cli.js
|
@ -1,58 +1,57 @@
|
||||||
const logger = require('./logger.js');
|
const logger = require('./logger.js');
|
||||||
const spawn = require('child_process').spawn;
|
const spawn = require('child_process').spawn;
|
||||||
|
const sudo = require('sudo');
|
||||||
|
|
||||||
async function execute(command, args, returnOnClose) {
|
async function execute(command, args, useSudo, returnOnClose) {
|
||||||
// return new Promise((resolve, reject) => {
|
if (command === undefined || command.length === 0) {
|
||||||
if (command === undefined || command.length === 0) {
|
return;
|
||||||
|
}
|
||||||
|
if (returnOnClose === undefined) {
|
||||||
|
returnOnClose = false;
|
||||||
|
}
|
||||||
|
let startTime = new Date().getTime();
|
||||||
|
let resultData = "";
|
||||||
|
let resultError = "";
|
||||||
|
command = command.trim();
|
||||||
|
let process;
|
||||||
|
if (useSudo) {
|
||||||
|
logger.debug('executing sudo command \'' + command + '\' (args: \'' + args + '\')...');
|
||||||
|
args.unshift(command);
|
||||||
|
process = sudo(args, { cachePassword: true, prompt: 'sudo password:' });
|
||||||
|
} else {
|
||||||
|
logger.debug('executing command \'' + command + '\' (args: \'' + args + '\')...');
|
||||||
|
process = spawn(command, args);
|
||||||
|
}
|
||||||
|
process.stdout.on('data', (data) => {
|
||||||
|
resultData += data;
|
||||||
|
});
|
||||||
|
process.stderr.on('data', (data) => {
|
||||||
|
resultError += data;
|
||||||
|
});
|
||||||
|
process.on('spawn', () => {
|
||||||
|
logger.info('spawned command \'' + command + '\' (args: \'' + args + '\')');
|
||||||
|
if (!returnOnClose) {
|
||||||
return;
|
return;
|
||||||
// reject();
|
|
||||||
}
|
}
|
||||||
if (returnOnClose === undefined) {
|
});
|
||||||
returnOnClose = false;
|
process.on('error', (err) => {
|
||||||
|
throw new Error(err);
|
||||||
|
});
|
||||||
|
process.on('close', (code) => {
|
||||||
|
let msg = 'command \'' + command + '\' (args: \'' + args + '\') finished with exit code ' + code + ' after ' + (new Date().getTime() - startTime) + 'ms';
|
||||||
|
if (resultData.length > 0) {
|
||||||
|
msg += " > data: " + resultData;
|
||||||
}
|
}
|
||||||
var startTime = new Date().getTime();
|
if (resultError.length > 0) {
|
||||||
var resultData = "";
|
msg += " >>> error: " + resultError;
|
||||||
var resultError = "";
|
logger.error(msg)
|
||||||
command = command.trim();
|
return;
|
||||||
logger.debug('executing command \'' + command + '\' (args: \'' + args + '\') ...');
|
|
||||||
try {
|
|
||||||
var process = spawn(command, args);
|
|
||||||
} catch (err) {
|
|
||||||
logger.error(err);
|
|
||||||
}
|
}
|
||||||
process.stdout.on('data', (data) => {
|
logger.debug(msg);
|
||||||
resultData += data;
|
if (returnOnClose) {
|
||||||
});
|
return;
|
||||||
process.stderr.on('data', (data) => {
|
}
|
||||||
resultError += data;
|
});
|
||||||
});
|
|
||||||
process.on('spawn', () => {
|
|
||||||
logger.info('spawned command \'' + command + '\' (args: \'' + args + '\')');
|
|
||||||
if (!returnOnClose) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
process.on('error', (err) => {
|
|
||||||
throw new Error(err);
|
|
||||||
// resultError += err;
|
|
||||||
});
|
|
||||||
process.on('close', (code) => {
|
|
||||||
var msg = 'command \'' + command + '\' (args: \'' + args + '\') finished with exit code ' + code + ' after ' + (new Date().getTime() - startTime) + 'ms';
|
|
||||||
if (resultData.length > 0) {
|
|
||||||
msg += " > data: " + resultData;
|
|
||||||
}
|
|
||||||
if (resultError.length > 0) {
|
|
||||||
msg += " >>> error: " + resultError;
|
|
||||||
throw new Error(msg);
|
|
||||||
// reject(msg);
|
|
||||||
}
|
|
||||||
if (returnOnClose) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// resolve(msg);
|
|
||||||
});
|
|
||||||
|
|
||||||
// });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
@ -13,13 +13,13 @@ class Keyfilter {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.actions = new Map();
|
this.actions = new Map();
|
||||||
for (var index = 0; index < keys.length; index++) {
|
for (let index = 0; index < keys.length; index++) {
|
||||||
this.setAction(keys[index]);
|
this.setAction(keys[index]);
|
||||||
}
|
}
|
||||||
this.currentCombo = undefined;
|
this.currentCombo = undefined;
|
||||||
}
|
}
|
||||||
setAction(config) {
|
setAction(config) {
|
||||||
var type = ACTION_KEYDOWN;
|
let type = ACTION_KEYDOWN;
|
||||||
switch (config.type.toLowerCase()) {
|
switch (config.type.toLowerCase()) {
|
||||||
case ACTION_KEYUP.action:
|
case ACTION_KEYUP.action:
|
||||||
type = ACTION_KEYUP;
|
type = ACTION_KEYUP;
|
||||||
|
@ -34,6 +34,7 @@ class Keyfilter {
|
||||||
event: config.event,
|
event: config.event,
|
||||||
command: config.command,
|
command: config.command,
|
||||||
args: config.args,
|
args: config.args,
|
||||||
|
sudo: config.sudo,
|
||||||
combo: config.combo,
|
combo: config.combo,
|
||||||
delay: function () {
|
delay: function () {
|
||||||
if (config.combo === undefined) {
|
if (config.combo === undefined) {
|
||||||
|
@ -49,9 +50,9 @@ class Keyfilter {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
input = input.toString();
|
input = input.toString();
|
||||||
var lines = input.split("\n");
|
let lines = input.split("\n");
|
||||||
for (var index = 0; index < lines.length; index++) {
|
for (let index = 0; index < lines.length; index++) {
|
||||||
var line = lines[index];
|
let line = lines[index];
|
||||||
if (line.length === 0) {
|
if (line.length === 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -62,7 +63,7 @@ class Keyfilter {
|
||||||
if (parsedEvent === undefined) {
|
if (parsedEvent === undefined) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (var [key, event] of this.actions) {
|
for (let [key, event] of this.actions) {
|
||||||
if (this.currentCombo === undefined && !this.isParsedEventValid(key, event, parsedEvent)) {
|
if (this.currentCombo === undefined && !this.isParsedEventValid(key, event, parsedEvent)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -103,6 +104,7 @@ class Keyfilter {
|
||||||
type: event.type.action,
|
type: event.type.action,
|
||||||
command: event.command,
|
command: event.command,
|
||||||
args: event.args,
|
args: event.args,
|
||||||
|
sudo: event.sudo,
|
||||||
delay: event.delay
|
delay: event.delay
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -123,7 +125,7 @@ class Keyfilter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
replaceVariables(filtered) {
|
replaceVariables(filtered) {
|
||||||
for (var index = 0; index < filtered.args.length; index++) {
|
for (let index = 0; index < filtered.args.length; index++) {
|
||||||
filtered.args[index] = filtered.args[index].replace(VARIABLE_KEY, filtered.key);
|
filtered.args[index] = filtered.args[index].replace(VARIABLE_KEY, filtered.key);
|
||||||
filtered.args[index] = filtered.args[index].replace(VARIABLE_TYPE, filtered.type);
|
filtered.args[index] = filtered.args[index].replace(VARIABLE_TYPE, filtered.type);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,49 +10,42 @@ const LOGLEVEL_INFO = 1;
|
||||||
const LOGLEVEL_WARNING = 2;
|
const LOGLEVEL_WARNING = 2;
|
||||||
const LOGLEVEL_ERROR = 3;
|
const LOGLEVEL_ERROR = 3;
|
||||||
|
|
||||||
var loglevel = getLogLevel();
|
let loglevel;
|
||||||
var timestamp = getTimestamp();
|
let timestamp;
|
||||||
|
|
||||||
function initialize() {
|
|
||||||
return new Promise((resolve, reject) => {
|
function initialize(loglevel, timestamp) {
|
||||||
if (global.config == undefined) {
|
setLogLevel(loglevel);
|
||||||
reject('could not initialize logger, config is undefined');
|
setTimestamp(timestamp);
|
||||||
}
|
|
||||||
loglevel = getLogLevel();
|
|
||||||
timestamp = getTimestamp();
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the loglevel
|
// set the loglevel
|
||||||
function getLogLevel() {
|
function setLogLevel(value) {
|
||||||
if (global.config?.log?.level == undefined) {
|
switch (value) {
|
||||||
return LOGLEVEL_INFO;
|
|
||||||
}
|
|
||||||
switch (global.config.log.level) {
|
|
||||||
case LOG_PREFIX_DEBUG:
|
case LOG_PREFIX_DEBUG:
|
||||||
case LOGLEVEL_DEBUG:
|
case LOGLEVEL_DEBUG:
|
||||||
return LOGLEVEL_DEBUG;
|
loglevel = LOGLEVEL_DEBUG;
|
||||||
|
break;
|
||||||
case LOG_PREFIX_INFO:
|
case LOG_PREFIX_INFO:
|
||||||
case LOGLEVEL_INFO:
|
case LOGLEVEL_INFO:
|
||||||
return LOGLEVEL_INFO;
|
loglevel = LOGLEVEL_INFO;
|
||||||
|
break;
|
||||||
case LOG_PREFIX_WARNING:
|
case LOG_PREFIX_WARNING:
|
||||||
case LOGLEVEL_WARNING:
|
case LOGLEVEL_WARNING:
|
||||||
return LOGLEVEL_WARNING;
|
loglevel = LOGLEVEL_WARNING;
|
||||||
|
break;
|
||||||
case LOG_PREFIX_ERROR:
|
case LOG_PREFIX_ERROR:
|
||||||
case LOGLEVEL_ERROR:
|
case LOGLEVEL_ERROR:
|
||||||
return LOGLEVEL_ERROR;
|
loglevel = LOGLEVEL_ERROR;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return LOGLEVEL_INFO;
|
loglevel = LOGLEVEL_INFO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the timestamp format
|
// set the timestamp format
|
||||||
function getTimestamp() {
|
function setTimestamp(value) {
|
||||||
if (global.config?.log?.format != undefined) {
|
timestamp = value || 'DD.MM.YYYY HH:mm:ss:SS';
|
||||||
return global.config.log.timestamp;
|
|
||||||
}
|
|
||||||
return "DD.MM.YYYY HH:mm:ss:SS";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// prefix log with 'info'
|
// prefix log with 'info'
|
||||||
|
@ -84,12 +77,20 @@ function error(message) {
|
||||||
if (loglevel > LOGLEVEL_ERROR) {
|
if (loglevel > LOGLEVEL_ERROR) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (message.errors != undefined) {
|
if (message.stack) {
|
||||||
for (var index = 0; index < message.errors.length; index++) {
|
trace(message.stack, 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (message.errors !== undefined) {
|
||||||
|
for (let index = 0; index < message.errors.length; index++) {
|
||||||
trace(message.errors[index], 'error');
|
trace(message.errors[index], 'error');
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (message.message) {
|
||||||
|
trace(message.message, 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
trace(message, 'error');
|
trace(message, 'error');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
39
libs/util.js
39
libs/util.js
|
@ -1,36 +1,23 @@
|
||||||
const realpath = require('fs/promises').realpath;
|
const realpath = require('fs/promises').realpath;
|
||||||
const stat = require('fs/promises').stat;
|
const stat = require('fs/promises').stat;
|
||||||
|
|
||||||
function fileExists(file) {
|
async function getFileInfo(file) {
|
||||||
return new Promise((resolve, reject) => {
|
if (file === undefined) {
|
||||||
if (file == undefined) {
|
throw new Error('can not check the existence of an undefined file');
|
||||||
reject('can not check the existence of an undefined file');
|
}
|
||||||
}
|
const path = await resolvePath(file);
|
||||||
resolvePath(file)
|
const stats = await stat(path);
|
||||||
.then((path) => {
|
return { path, stats };
|
||||||
stat(path)
|
|
||||||
.then((stats) => {
|
|
||||||
resolve({path, stats});
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch(reject);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolvePath(file) {
|
async function resolvePath(file) {
|
||||||
return new Promise((resolve, reject) => {
|
if (file === undefined) {
|
||||||
if (file == undefined) {
|
throw new Error('can not resolve a path to an undefined file');
|
||||||
reject('can not resolve a path to an undefined file');
|
}
|
||||||
}
|
return realpath(file);
|
||||||
realpath(file)
|
|
||||||
.then(resolve)
|
|
||||||
.catch((err) => {
|
|
||||||
reject('resolving path \'' + file + '\' encountered an error >>> ' + err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
fileExists,
|
getFileInfo,
|
||||||
resolvePath
|
resolvePath
|
||||||
}
|
}
|
|
@ -3,52 +3,61 @@ const util = require('./util.js');
|
||||||
const Keyfilter = require('./keyfilter.js');
|
const Keyfilter = require('./keyfilter.js');
|
||||||
const cli = require('./cli.js');
|
const cli = require('./cli.js');
|
||||||
const spawn = require('child_process').spawn;
|
const spawn = require('child_process').spawn;
|
||||||
|
const sudo = require('sudo');
|
||||||
|
|
||||||
const inputDevices = '/dev/input/';
|
const inputDevices = '/dev/input/';
|
||||||
const inputDevicesById = '/dev/input/by-id/';
|
const inputDevicesById = '/dev/input/by-id/';
|
||||||
|
|
||||||
class Watcher {
|
class Watcher {
|
||||||
constructor(config, callback) {
|
constructor(config, callback) {
|
||||||
if (config == undefined || config.device == undefined) {
|
if (config === undefined || config.device === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (var key in config) {
|
for (let key in config) {
|
||||||
this[key] = config[key];
|
this[key] = config[key];
|
||||||
}
|
}
|
||||||
this.keyfilter = new Keyfilter(config.keys, config.combos);
|
this.keyfilter = new Keyfilter(config.keys, config.combos);
|
||||||
this.restart = config.restart;
|
this.restart = config.restart;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
}
|
}
|
||||||
start() {
|
async start() {
|
||||||
return new Promise((resolve, reject) => {
|
if (this.process !== undefined) {
|
||||||
if (this.process != undefined) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
if (this.sudo) {
|
||||||
|
logger.debug('starting sudo watcher \'' + this.device + '\'...');
|
||||||
|
this.process = sudo(['evtest', this.device], { cachePassword: true, prompt: 'sudo password:' });
|
||||||
|
} else {
|
||||||
logger.debug('starting watcher \'' + this.device + '\'...');
|
logger.debug('starting watcher \'' + this.device + '\'...');
|
||||||
this.process = spawn("evtest", [this.device]);
|
this.process = spawn('evtest', [this.device]);
|
||||||
this.attachListeners(resolve, reject);
|
}
|
||||||
});
|
try {
|
||||||
|
await this.attachListeners();
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(err);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
stop() {
|
stop() {
|
||||||
if (this.process == undefined) {
|
if (this.process === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logger.debug('stopping watcher \'' + this.device + '\'...');
|
logger.debug('stopping watcher \'' + this.device + '\'...');
|
||||||
this.process.kill();
|
this.process.kill();
|
||||||
logger.info('watcher \'' + this.device + '\' stopped');
|
logger.info('watcher \'' + this.device + '\' stopped');
|
||||||
}
|
}
|
||||||
attachListeners(resolve, reject) {
|
async attachListeners() {
|
||||||
if (this.process == undefined) {
|
if (this.process === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.addSpawnListener(resolve);
|
|
||||||
this.addErrorListener(reject);
|
|
||||||
this.addCloseListener();
|
|
||||||
this.addStdOutListener();
|
this.addStdOutListener();
|
||||||
this.addStdErrListener();
|
this.addStdErrListener();
|
||||||
|
this.addErrorListener();
|
||||||
|
this.addCloseListener();
|
||||||
|
await this.addSpawnListener();
|
||||||
}
|
}
|
||||||
addStdOutListener() {
|
addStdOutListener() {
|
||||||
if (this.process == undefined) {
|
if (this.process === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logger.debug('adding stdout listener to watcher \'' + this.device + '\'...');
|
logger.debug('adding stdout listener to watcher \'' + this.device + '\'...');
|
||||||
|
@ -56,8 +65,8 @@ class Watcher {
|
||||||
if (this.keyfilter == undefined) {
|
if (this.keyfilter == undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var filtered = this.keyfilter.filter(data);
|
let filtered = this.keyfilter.filter(data);
|
||||||
if (filtered == undefined) {
|
if (filtered === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (filtered.delayed) {
|
if (filtered.delayed) {
|
||||||
|
@ -73,46 +82,55 @@ class Watcher {
|
||||||
}
|
}
|
||||||
this.keyfilter.resetCurrentCombo();
|
this.keyfilter.resetCurrentCombo();
|
||||||
logger.info('executing command \'' + filtered.command + '\' (args: \'' + filtered.args + '\') registered for captured \'' + filtered.type + '\' event for \'' + filtered.key + '\' from watcher \'' + this.device + '\'');
|
logger.info('executing command \'' + filtered.command + '\' (args: \'' + filtered.args + '\') registered for captured \'' + filtered.type + '\' event for \'' + filtered.key + '\' from watcher \'' + this.device + '\'');
|
||||||
cli.execute(filtered.command, filtered.args)
|
cli.execute(filtered.command, filtered.args, filtered.sudo)
|
||||||
.then(logger.info)
|
.then(logger.info)
|
||||||
.catch(logger.error);
|
.catch(logger.error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
addStdErrListener() {
|
addStdErrListener() {
|
||||||
if (this.process == undefined) {
|
if (this.process === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logger.debug('adding stderr listener to watcher \'' + this.device + '\'...');
|
logger.debug('adding stderr listener to watcher \'' + this.device + '\'...');
|
||||||
this.process.stderr.on('data', (data) => {
|
this.process.stderr.on('data', (data) => {
|
||||||
logger.error(data);
|
this.error = data.toString().trim();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
addSpawnListener(resolve) {
|
addSpawnListener() {
|
||||||
logger.debug('adding spawn listener to watcher \'' + this.device + '\'...');
|
return new Promise((resolve, reject) => {
|
||||||
this.process.on('spawn', () => {
|
logger.debug('adding spawn listener to watcher \'' + this.device + '\'...');
|
||||||
logger.info('watcher \'' + this.device + '\' initialized and capturing configured events');
|
this.process.on('spawn', () => {
|
||||||
resolve();
|
logger.info('watcher \'' + this.device + '\' initialized and capturing configured events');
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
addCloseListener() {
|
addCloseListener() {
|
||||||
if (this.process == undefined) {
|
if (this.process === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logger.debug('adding close listener to watcher \'' + this.device + '\'...');
|
logger.debug('adding close listener to watcher \'' + this.device + '\'...');
|
||||||
this.process.on('close', (code) => {
|
this.process.on('close', (code) => {
|
||||||
if (code == undefined) {
|
if (code === undefined) {
|
||||||
code = 0;
|
code = 0;
|
||||||
|
if (this.error !== undefined) {
|
||||||
|
code = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.error !== undefined) {
|
||||||
|
logger.error('watcher \'' + this.device + '\' encountered an error > ' + this.error);
|
||||||
|
this.restart = false;
|
||||||
}
|
}
|
||||||
this.process = undefined;
|
this.process = undefined;
|
||||||
this.code = code;
|
this.code = code;
|
||||||
logger.info('watcher \'' + this.device + '\' finished with exit code ' + code);
|
logger.info('watcher \'' + this.device + '\' finished with exit code ' + code);
|
||||||
if (this.callback != undefined) {
|
if (this.callback !== undefined) {
|
||||||
this.callback(this);
|
this.callback(this);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
addErrorListener(reject) {
|
addErrorListener(reject) {
|
||||||
if (this.process == undefined) {
|
if (this.process === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logger.debug('adding error listener to \'' + this.device + '\'...');
|
logger.debug('adding error listener to \'' + this.device + '\'...');
|
||||||
|
@ -125,9 +143,9 @@ class Watcher {
|
||||||
if (!this.keyfilter.isValid()) {
|
if (!this.keyfilter.isValid()) {
|
||||||
reject('no key(s) defined for watcher \'' + this.device + '\'');
|
reject('no key(s) defined for watcher \'' + this.device + '\'');
|
||||||
}
|
}
|
||||||
Promise.any([this.device, inputDevices + this.device, inputDevicesById + this.device].map(util.fileExists))
|
Promise.any([this.device, inputDevices + this.device, inputDevicesById + this.device].map(util.getFileInfo))
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
if (result.path != this.device) {
|
if (result.path !== this.device) {
|
||||||
logger.info('resolved watcher for device \'' + this.device + '\' to \'' + result.path + '\'')
|
logger.info('resolved watcher for device \'' + this.device + '\' to \'' + result.path + '\'')
|
||||||
}
|
}
|
||||||
this.device = result.path;
|
this.device = result.path;
|
||||||
|
|
|
@ -3,44 +3,32 @@ const Watcher = require('./watcher.js');
|
||||||
|
|
||||||
const watchers = [];
|
const watchers = [];
|
||||||
|
|
||||||
async function initialize() {
|
async function initialize(config) {
|
||||||
if (global.config == undefined) {
|
if (config == undefined) {
|
||||||
throw new Error('could not initialize watchers, no config defined');
|
throw new Error('could not initialize watchers, no config defined');
|
||||||
}
|
}
|
||||||
if (global.config.watchers == undefined || global.config.watchers.length == 0) {
|
if (config.length == 0) {
|
||||||
throw new Error('no watchers in config \'' + global.config.path + '\' defined');
|
throw new Error('no watchers in config \'' + global.config.path + '\' defined');
|
||||||
}
|
}
|
||||||
for (var index = 0; index < global.config.watchers.length; index++) {
|
for (var index = 0; index < config.length; index++) {
|
||||||
var watcher = new Watcher(global.config.watchers[index], watcherCallback);
|
var watcher = new Watcher(config[index], watcherCallback);
|
||||||
try {
|
await watcher.check();
|
||||||
await watcher.check();
|
watchers.push(watcher);
|
||||||
watchers.push(watcher);
|
logger.debug('added watcher \'' + watcher.device + '\' to internal map');
|
||||||
logger.debug('added watcher \'' + watcher.device + '\' to internal map');
|
|
||||||
} catch(err) {
|
|
||||||
logger.error(err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function start() {
|
async function start() {
|
||||||
logger.info('starting ' + watchers.length + ' watcher(s)...');
|
logger.info('starting ' + watchers.length + ' watcher(s)...');
|
||||||
for (var index = 0; index < watchers.length; index++) {
|
for (var index = 0; index < watchers.length; index++) {
|
||||||
try {
|
await watchers[index].start();
|
||||||
await watchers[index].start();
|
|
||||||
} catch (err) {
|
|
||||||
logger.error(err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function stop() {
|
async function stop() {
|
||||||
logger.info('stopping ' + watchers.length + ' watcher(s)...');
|
logger.info('stopping ' + watchers.length + ' watcher(s)...');
|
||||||
for (var index = 0; index < watchers.length; index++) {
|
for (var index = 0; index < watchers.length; index++) {
|
||||||
try {
|
await watchers[index].stop();
|
||||||
await watchers[index].stop();
|
|
||||||
} catch (err) {
|
|
||||||
logger.error(err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,12 +37,10 @@ async function watcherCallback(watcher) {
|
||||||
await watcher.start();
|
await watcher.start();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
watchers.splice(watchers.findIndex((foundWatcher) => foundWatcher.device == watcher), 1);
|
watchers.splice(watchers.findIndex((foundWatcher) => foundWatcher.device === watcher), 1);
|
||||||
logger.debug('removed watcher \'' + watcher + '\' from internal map');
|
logger.debug('removed watcher \'' + watcher.device + '\' from internal map');
|
||||||
if (watchers.length === 0) {
|
if (watchers.length === 0) {
|
||||||
logger.info('no watchers are active any longer');
|
logger.warn('no watchers are active any longer');
|
||||||
logger.info(global.appName + ' ' + global.appVersion + ' exiting with code \'0\'');
|
|
||||||
process.exit(0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
55
ninwa.js
55
ninwa.js
|
@ -5,45 +5,44 @@ const packageJSON = require('./package.json');
|
||||||
|
|
||||||
const INTERRUPTS = ['SIGINT', 'SIGTERM'];
|
const INTERRUPTS = ['SIGINT', 'SIGTERM'];
|
||||||
|
|
||||||
global.appName = packageJSON.name;
|
let config;
|
||||||
global.appVersion = packageJSON.version;
|
|
||||||
global.config = process.argv[2] || __dirname + '/config.json';
|
|
||||||
|
|
||||||
handleInterrupts();
|
main();
|
||||||
|
|
||||||
util.fileExists(config)
|
async function main() {
|
||||||
.catch((err) => {
|
handleInterrupts();
|
||||||
logger.error('given config file \'' + config + '\' does not exist');
|
try {
|
||||||
|
let configFile = await util.getFileInfo(process.argv[2] || __dirname + '/config.json');
|
||||||
|
config = require(configFile.path);
|
||||||
|
config.path = config.path;
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
logger.initialize(config.log.level, config.log.timestamp);
|
||||||
|
logger.info(packageJSON.name + ' ' + packageJSON.version + ' starting...');
|
||||||
|
await watchers.initialize(config.watchers);
|
||||||
|
await watchers.start();
|
||||||
|
} catch (err) {
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
exit(1);
|
exit(1);
|
||||||
})
|
}
|
||||||
.then((result) => {
|
|
||||||
global.config = require(result.path);
|
|
||||||
global.config.path = result.path;
|
|
||||||
})
|
|
||||||
.then(logger.initialize)
|
|
||||||
.then(() => {
|
|
||||||
logger.info(appName + ' ' + appVersion + ' starting...');
|
|
||||||
})
|
|
||||||
.then(watchers.initialize)
|
|
||||||
.then(watchers.start)
|
|
||||||
.catch((err) => {
|
|
||||||
logger.error(err);
|
|
||||||
exit(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
function exit(code) {
|
|
||||||
code = code || 0;
|
|
||||||
logger.info(appName + ' ' + appVersion + ' exiting with code \'' + code + '\'...');
|
|
||||||
process.exit(code);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleInterrupts() {
|
function handleInterrupts() {
|
||||||
for (var index = 0; index < INTERRUPTS.length; index++) {
|
for (var index = 0; index < INTERRUPTS.length; index++) {
|
||||||
process.once(INTERRUPTS[index], (code) => {
|
process.on(INTERRUPTS[index], (code) => {
|
||||||
|
exit(code);
|
||||||
watchers.stop()
|
watchers.stop()
|
||||||
.then(exit(code))
|
.then(exit(code))
|
||||||
.catch(exit(code));
|
.catch(exit(code));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function exit(code) {
|
||||||
|
code = code || 0;
|
||||||
|
logger.info(packageJSON.name + ' ' + packageJSON.version + ' exiting with code \'' + code + '\'...');
|
||||||
|
process.exit(code);
|
||||||
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
"author": "Daniel Sommer <daniel.sommer@velvettear.de>",
|
"author": "Daniel Sommer <daniel.sommer@velvettear.de>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"moment": "^2.29.1"
|
"moment": "^2.29.1",
|
||||||
|
"sudo": "^1.0.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue