added variable replacement, extended readme, implemented graceful shutdown

This commit is contained in:
Daniel Sommer 2022-02-16 03:28:17 +01:00
parent e68313270f
commit 6aade27a5a
6 changed files with 78 additions and 36 deletions

View file

@ -55,4 +55,4 @@ configuration is done entirely within the file `config.json`.
- type: [*string*] type of the key event; either `keyup`, `keydown` or `keyhold`
- delay: [*number*] time in milliseconds until the key will be registered again (mostly useful for keyhold-events)
- command: [*string*] command to execute on key press
- args: [*string-array*] arguments to pass to the executed command
- args: [*string-array*] arguments to pass to the executed command; variables `{{ key }}` and `{{ type }}` used in args will be replaced

View file

@ -1,6 +1,6 @@
{
"log": {
"level": "debug",
"level": "info",
"timestamp": "DD.MM.YYYY HH:mm:ss:SS"
},
"watchers": [

View file

@ -6,6 +6,9 @@ const ACTION_KEYUP = { id: 0, action: 'keyup' };
const ACTION_KEYDOWN = { id: 1, action: 'keydown' };
const ACTION_KEYHOLD = { id: 2, action: 'keyhold' };
const VARIABLE_KEY = '{{ key }}';
const VARIABLE_TYPE = '{{ type }}';
class Keyfilter {
constructor(config) {
if (config == undefined || config.length == 0) {
@ -66,16 +69,23 @@ class Keyfilter {
if (this.shouldBeDelayed(action)) {
return { key: key, type: action.type.action, delayed: true };
}
action.executed = new Date().getTime();
return { key: key, type: action.type.action, command: action.command, args: action.args };
action.captured = new Date().getTime();
return this.replaceVariables({ key: key, type: action.type.action, command: action.command, args: action.args });
}
}
}
replaceVariables(filtered) {
for (var 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_TYPE, filtered.type);
}
return filtered;
}
shouldBeDelayed(action) {
if (action.delay == undefined || action.delay == 0 || action.executed == undefined) {
if (action.delay == undefined || action.delay == 0 || action.captured == undefined) {
return false;
}
return new Date().getTime() - action.executed < action.delay;
return new Date().getTime() - action.captured < action.delay;
}
isValid() {
return this.actions != undefined && this.actions.size > 0;

View file

@ -25,6 +25,7 @@ class Watcher {
logger.debug('starting watcher \'' + this.device + '\'...');
this.process = spawn("evtest", [this.device]);
this.attachListeners();
logger.info('watcher \'' + this.device + '\' initialized and capturing configured events');
}
stop() {
if (this.process == undefined) {
@ -32,9 +33,7 @@ class Watcher {
}
logger.debug('stopping watcher \'' + this.device + '\'...');
this.process.kill();
if (this.callback != undefined) {
this.callback();
}
logger.info('watcher \'' + this.device + '\' stopped');
}
attachListeners() {
if (this.process == undefined) {
@ -84,9 +83,13 @@ class Watcher {
}
logger.debug('adding close listener to watcher \'' + this.device + '\'...');
this.process.on('close', (code) => {
if (code == undefined) {
code = 0;
}
this.code = code;
logger.info('watcher \'' + this.device + '\' finished with exit code ' + code);
if (this.callback != undefined) {
this.callback(null, this.device, code);
this.callback(this.device);
}
});
}
@ -110,7 +113,7 @@ class Watcher {
logger.info('resolved watcher for device \'' + this.device + '\' to \'' + result.path + '\'')
}
this.device = result.path;
resolve();
resolve(this);
})
.catch(reject);
});

View file

@ -11,48 +11,57 @@ function initialize() {
}
var tmp = []
for (var index = 0; index < configJSON.watchers.length; index++) {
tmp.push(new Watcher(configJSON.watchers[index]));
tmp.push(new Watcher(configJSON.watchers[index], watcherCallback));
}
Promise.all(tmp.map(check)).then(resolve);
Promise.all(tmp.map(check))
.then(resolve)
.catch(reject);
});
}
function check(watcher) {
return new Promise(function (resolve, reject) {
return new Promise((resolve, reject) => {
if (watcher == undefined) {
reject();
}
watcher.check()
.then(() => {
logger.info('watcher \'' + watcher.device + '\' initialized and capturing configured events...');
watcher.start();
watchers.push(watcher);
watchers.push(watcher)
logger.debug('added watcher \'' + watcher.device + '\' to internal map');
})
.catch((err) => {
logger.error(err);
});
.then(resolve)
.catch(reject);
});
}
function start() {
logger.debug('starting ' + watchers.size + ' watcher(s)...');
for (const watcher of watchers.entries()) {
watcher[1].start();
return new Promise((resolve, reject) => {
logger.info('starting ' + watchers.length + ' watcher(s)...');
var promises = [];
for (var index = 0; index < watchers.length; index++) {
promises.push(watchers[index].start());
}
Promise.all(promises)
.then(resolve)
.catch(reject);
});
}
function stop() {
const count = watchers.size;
logger.info('stopping all ' + count + ' watchers...');
for (var index = 0; index < count; index++) {
var watcher = watchers[index];
logger.debug('stopping watcher ' + watcher.id + '...');
watcher.kill();
return new Promise((resolve, reject) => {
logger.info('stopping ' + watchers.length + ' watcher(s)...');
var promises = [];
for (var index = 0; index < watchers.length; index++) {
promises.push(watchers[index].stop());
}
Promise.all(promises)
.then(resolve)
.catch(reject);
});
}
function callback(err, id, code) {
this.watchers.delete(id);
logger.debug('removed watcher \'' + id + '\'');
function watcherCallback(watcher) {
watchers.splice(watchers.findIndex((foundWatcher) => foundWatcher.device == watcher), 1);
logger.debug('removed watcher \'' + watcher + '\' from internal map');
}
module.exports = {

View file

@ -2,11 +2,31 @@ const watchers = require('./libs/watchers.js');
const logger = require('./libs/logger.js');
const packageJSON = require('./package.json');
logger.info(packageJSON.name + ' ' + packageJSON.version);
const INTERRUPTS = ['SIGINT', 'SIGTERM'];
logger.info(packageJSON.name + ' ' + packageJSON.version + ' starting...');
handleInterrupts();
watchers.initialize()
.then(watchers.start)
.catch((err) => {
logger.error(err);
process.exit(1);
exit(1);
});
function exit(code) {
code = code || 0;
logger.info(packageJSON.name + ' ' + packageJSON.version + ' exiting with code \'' + code + '\'...');
process.exit(code);
}
function handleInterrupts() {
for (var index = 0; index < INTERRUPTS.length; index++) {
process.once(INTERRUPTS[index], (code) => {
watchers.stop()
.then(exit(code))
.catch(exit(code));
});
}
}