diff --git a/lib/multi-bar.js b/lib/multi-bar.js index d40ccfc..37092db 100644 --- a/lib/multi-bar.js +++ b/lib/multi-bar.js @@ -2,6 +2,7 @@ const _Terminal = require('./terminal'); const _BarElement = require('./generic-bar'); const _options = require('./options'); const _EventEmitter = require('events'); +const _ShutdownListener = require('./shutdown-listener.js'); // Progress-Bar constructor module.exports = class MultiBar extends _EventEmitter{ @@ -33,8 +34,9 @@ module.exports = class MultiBar extends _EventEmitter{ // logging output buffer this.loggingBuffer = []; - // callback used for gracefulExit - this.sigintCallback = null; + // add handler to restore cursor settings (stop the bar) on SIGINT/SIGTERM ? + const signals = ['SIGINT', 'SIGTERM']; + this.shuthdownListener = new _ShutdownListener(signals, this.stop.bind(this)); } // add a new bar to the stack @@ -65,12 +67,10 @@ module.exports = class MultiBar extends _EventEmitter{ } // add handler to restore cursor settings (stop the bar) on SIGINT/SIGTERM ? - if (this.sigintCallback === null && this.options.gracefulExit){ - this.sigintCallback = this.stop.bind(this); - process.once('SIGINT', this.sigintCallback); - process.once('SIGTERM', this.sigintCallback); + if (this.options.gracefulExit){ + this.shuthdownListener.attach(); } - + // multiprogress already active ? if (!this.isActive){ // hide the cursor ? @@ -188,13 +188,6 @@ module.exports = class MultiBar extends _EventEmitter{ clearTimeout(this.timer); this.timer = null; - // remove sigint listener - if (this.sigintCallback){ - process.removeListener('SIGINT', this.sigintCallback); - process.removeListener('SIGTERM', this.sigintCallback); - this.sigintCallback = null; - } - // set flag this.isActive = false; @@ -239,6 +232,8 @@ module.exports = class MultiBar extends _EventEmitter{ this.terminal.newline(); } + this.shuthdownListener.detach(); + // trigger event this.emit('stop'); } diff --git a/lib/shutdown-listener.js b/lib/shutdown-listener.js new file mode 100644 index 0000000..f19d93f --- /dev/null +++ b/lib/shutdown-listener.js @@ -0,0 +1,41 @@ + +module.exports = class ShutdownListener { + constructor(signals, cleanupFunction, processOverride) { + this._signals = signals; + this._isSignalReceived = false; + this._isAttached = false; + this._process = processOverride ? processOverride : process; + this._handler = (signal) => { + if (this._isSignalReceived) { + return; + } + this._isSignalReceived = true; + Promise.resolve(cleanupFunction()) + .catch((e) => { + console.log(e); + }) + .then(() => { + this._signals.forEach(sig => this._process.removeListener(sig, this._handler)); + this._process.kill(this._process.pid, signal); + }) + } + } + + attach() { + if (this._isAttached) { + return; + } + this._signals.forEach(sig => { + this._process.on(sig, this._handler) + }); + this._isAttached = true; + } + + detach() { + if (this._isSignalReceived) { + return; + } + this._signals.forEach(sig => this._process.removeListener(sig, this._handler)); + this._isAttached = false; + } +} diff --git a/lib/single-bar.js b/lib/single-bar.js index e8235e4..42866bb 100644 --- a/lib/single-bar.js +++ b/lib/single-bar.js @@ -1,5 +1,6 @@ const _GenericBar = require('./generic-bar'); const _options = require('./options'); +const _ShutdownListener = require("./shutdown-listener.js"); // Progress-Bar constructor module.exports = class SingleBar extends _GenericBar{ @@ -18,8 +19,9 @@ module.exports = class SingleBar extends _GenericBar{ // update interval this.schedulingRate = (this.terminal.isTTY() ? this.options.throttleTime : this.options.notTTYSchedule); - // callback used for gracefulExit - this.sigintCallback = null; + // add handler to restore cursor settings (stop the bar) on SIGINT/SIGTERM ? + const signals = ['SIGINT', 'SIGTERM']; + this.shuthdownListener = new _ShutdownListener(signals, this.stop.bind(this)); } // internal render function @@ -66,10 +68,8 @@ module.exports = class SingleBar extends _GenericBar{ } // add handler to restore cursor settings (stop the bar) on SIGINT/SIGTERM ? - if (this.sigintCallback === null && this.options.gracefulExit){ - this.sigintCallback = this.stop.bind(this); - process.once('SIGINT', this.sigintCallback); - process.once('SIGTERM', this.sigintCallback); + if (this.options.gracefulExit){ + this.shuthdownListener.attach(); } // save current cursor settings @@ -99,13 +99,6 @@ module.exports = class SingleBar extends _GenericBar{ return; } - // remove sigint listener - if (this.sigintCallback){ - process.removeListener('SIGINT', this.sigintCallback); - process.removeListener('SIGTERM', this.sigintCallback); - this.sigintCallback = null; - } - // trigger final rendering this.render(); @@ -137,5 +130,6 @@ module.exports = class SingleBar extends _GenericBar{ // new line on complete this.terminal.newline(); } + this.shuthdownListener.detach(); } -} \ No newline at end of file +}