ninwa/libs/watcher.js

159 lines
5.8 KiB
JavaScript
Raw Normal View History

2022-02-15 04:33:19 +01:00
const logger = require('./logger.js');
const util = require('./util.js');
const Keyfilter = require('./keyfilter.js');
const cli = require('./cli.js');
const spawn = require('child_process').spawn;
const sudo = require('sudo');
2022-02-15 04:33:19 +01:00
const inputDevices = '/dev/input/';
const inputDevicesById = '/dev/input/by-id/';
class Watcher {
constructor(config, callback) {
if (config === undefined || config.device === undefined) {
2022-02-15 04:33:19 +01:00
return;
}
for (let key in config) {
2022-02-15 04:33:19 +01:00
this[key] = config[key];
}
this.keyfilter = new Keyfilter(config.keys);
this.restart = config.restart;
2022-02-15 04:33:19 +01:00
this.callback = callback;
}
async start() {
if (this.process !== undefined) {
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 + '\'...');
this.process = spawn('evtest', [this.device]);
}
try {
await this.attachListeners();
} catch (err) {
logger.error(err);
}
2022-02-15 04:33:19 +01:00
}
stop() {
if (this.process === undefined) {
2022-02-15 04:33:19 +01:00
return;
}
logger.debug('stopping watcher \'' + this.device + '\'...');
this.process.kill();
logger.info('watcher \'' + this.device + '\' stopped');
2022-02-15 04:33:19 +01:00
}
async attachListeners() {
if (this.process === undefined) {
2022-02-15 04:33:19 +01:00
return;
}
this.addStdOutListener();
this.addStdErrListener();
this.addErrorListener();
this.addCloseListener();
await this.addSpawnListener();
2022-02-15 04:33:19 +01:00
}
addStdOutListener() {
if (this.process === undefined) {
2022-02-15 04:33:19 +01:00
return;
}
logger.debug('adding stdout listener to watcher \'' + this.device + '\'...');
this.process.stdout.on('data', (data) => {
if (this.keyfilter == undefined) {
return;
}
let filtered = this.keyfilter.filter(data);
if (filtered === undefined) {
2022-02-15 04:33:19 +01:00
return;
}
2022-03-11 15:47:48 +01:00
logger.debug('handling captured \'' + filtered.type + '\' event for key \'' + filtered.key + '\' from watcher \'' + this.device + '\'...');
2022-02-15 04:33:19 +01:00
if (filtered.delayed) {
2022-03-11 15:47:48 +01:00
logger.debug('delaying captured event...');
2022-02-15 04:33:19 +01:00
return;
}
2022-03-03 03:35:34 +01:00
if (filtered.combo) {
if (!filtered.combo.finished) {
2022-03-11 15:47:48 +01:00
logger.debug('captured event is part of ' + filtered.combo.possibilities + ' possible combo(s) and not yet finished')
2022-03-03 03:35:34 +01:00
return;
}
2022-03-11 15:47:48 +01:00
logger.debug('captured event finished combo \'' + filtered.combo.done.toString().toUpperCase()+ '\'');
2022-03-03 03:35:34 +01:00
}
this.keyfilter.resetCurrentCombo();
2022-03-11 15:47:48 +01:00
logger.info('executing command \'' + filtered.command.name + '\' registered for captured event...');
2022-03-10 14:05:08 +01:00
cli.execute(filtered.command.cmd, filtered.command.args, filtered.command.sudo)
2022-02-15 04:33:19 +01:00
.then(logger.info)
.catch(logger.error);
});
}
addStdErrListener() {
if (this.process === undefined) {
2022-02-15 04:33:19 +01:00
return;
}
logger.debug('adding stderr listener to watcher \'' + this.device + '\'...');
this.process.stderr.on('data', (data) => {
this.error = data.toString().trim();
2022-02-15 04:33:19 +01:00
});
}
addSpawnListener() {
return new Promise((resolve, reject) => {
logger.debug('adding spawn listener to watcher \'' + this.device + '\'...');
this.process.on('spawn', () => {
logger.info('watcher \'' + this.device + '\' initialized and capturing configured events');
resolve();
});
});
}
2022-02-15 04:33:19 +01:00
addCloseListener() {
if (this.process === undefined) {
2022-02-15 04:33:19 +01:00
return;
}
logger.debug('adding close listener to watcher \'' + this.device + '\'...');
this.process.on('close', (code) => {
if (code === undefined) {
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.code = code;
2022-02-15 04:33:19 +01:00
logger.info('watcher \'' + this.device + '\' finished with exit code ' + code);
if (this.callback !== undefined) {
this.callback(this);
2022-02-15 04:33:19 +01:00
}
});
}
addErrorListener(reject) {
if (this.process === undefined) {
2022-02-15 04:33:19 +01:00
return;
}
logger.debug('adding error listener to \'' + this.device + '\'...');
this.process.on('error', (err) => {
reject(logger.error('watcher \'' + this.device + '\' encountered an error >>> ' + err));
2022-02-15 04:33:19 +01:00
});
}
check() {
return new Promise((resolve, reject) => {
if (!this.keyfilter.isValid()) {
reject('no key(s) defined for watcher \'' + this.device + '\'');
}
Promise.any([this.device, inputDevices + this.device, inputDevicesById + this.device].map(util.getFileInfo))
2022-02-15 04:33:19 +01:00
.then((result) => {
if (result.path !== this.device) {
2022-02-15 04:33:19 +01:00
logger.info('resolved watcher for device \'' + this.device + '\' to \'' + result.path + '\'')
}
this.device = result.path;
resolve(this);
2022-02-15 04:33:19 +01:00
})
.catch(reject);
});
}
}
module.exports = Watcher;