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 inputDevices = '/dev/input/'; const inputDevicesById = '/dev/input/by-id/'; class Watcher { constructor(config, callback) { if (config == undefined || config.device == undefined) { return; } for (var key in config) { this[key] = config[key]; } this.keyfilter = new Keyfilter(config.keys); this.callback = callback; } start() { if (this.process != undefined) { return; } logger.debug('starting watcher \'' + this.device + '\'...'); this.process = spawn("evtest", [this.device, "|", "grep", "EV_KEY"]); this.attachListeners(); logger.info('watcher \'' + this.device + '\' initialized and capturing configured events'); } stop() { if (this.process == undefined) { return; } logger.debug('stopping watcher \'' + this.device + '\'...'); this.process.kill(); logger.info('watcher \'' + this.device + '\' stopped'); } attachListeners() { if (this.process == undefined) { return; } this.addStdOutListener(); this.addStdErrListener(); this.addCloseListener(); this.addErrorListener(); } addStdOutListener() { if (this.process == undefined) { return; } logger.debug('adding stdout listener to watcher \'' + this.device + '\'...'); this.process.stdout.on('data', (data) => { if (this.keyfilter == undefined) { return; } var filtered = this.keyfilter.filter(data); if (filtered == undefined) { return; } var msg = 'watcher \'' + this.device + '\' captured event'; if (filtered.delayed) { logger.debug('delaying captured \'' + filtered.type + '\' event for \'' + filtered.key + '\' from watcher \'' + this.device + '\''); return; } 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) .then(logger.info) .catch(logger.error); }); } addStdErrListener() { if (this.process == undefined) { return; } logger.debug('adding stderr listener to watcher \'' + this.device + '\'...'); this.process.stderr.on('data', (data) => { logger.error(data); }); } addCloseListener() { if (this.process == undefined) { return; } 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(this.device); } }); } addErrorListener() { if (this.process == undefined) { return; } logger.debug('adding error listener to \'' + this.device + '\'...'); this.process.on('error', (err) => { logger.error('watcher \'' + this.device + '\' encountered an error >>> ' + err); }); } 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.fileExists)) .then((result) => { if (result.path != this.device) { logger.info('resolved watcher for device \'' + this.device + '\' to \'' + result.path + '\'') } this.device = result.path; resolve(this); }) .catch(reject); }); } } module.exports = Watcher;