added variable replacement, extended readme, implemented graceful shutdown
This commit is contained in:
parent
e68313270f
commit
6aade27a5a
6 changed files with 78 additions and 36 deletions
|
@ -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
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"log": {
|
||||
"level": "debug",
|
||||
"level": "info",
|
||||
"timestamp": "DD.MM.YYYY HH:mm:ss:SS"
|
||||
},
|
||||
"watchers": [
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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 = {
|
||||
|
|
24
ninwa.js
24
ninwa.js
|
@ -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));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue