@skazska/inform
Version:
[](https://travis-ci.org/skazska/inform)
177 lines (160 loc) • 4.11 kB
JavaScript
const EventEmitter = require('events');
const {STATUSES, STATUS} = require('./constants');
/**
* Common task status class
*/
class TaskStatus extends EventEmitter {
/**
* @param {number} [status]
*/
constructor (status) {
super();
this._status = status || STATUS.PENDING;
this.isDone = false;
}
/**
* status getter
* @return {number}
*/
get status () {
return this._status;
}
/**
* status setter
* @param {number} status
*/
set status (status) {
this._status = status;
this.emit('change', this._composeChangeEvent());
if (status === STATUS.FAILED || status === STATUS.DONE) this.complete();
}
/**
* status name
* @return {string}
*/
get statusName () {
return TaskStatus.statusName(this.status);
}
/**
* task setter
* @param {*} task
*/
set task (task) {
this.status = STATUS.IN_PROCESS;
if (false === this.taskStatusMonitor(task)) throw new Error('Task type was not recognized');
}
/**
* promise getter
* @return {Promise<any>}
*/
get promise () {
if (this.isDone) {
if (this.status === STATUS.FAILED) {
return Promise.reject(this._composeChangeError());
}
if (this.status === STATUS.DONE) {
return Promise.resolve(this._composeChangeEvent());
}
} else {
if (!this._promise) this._promise = new Promise((resolve, reject) => {
this._promiseResolve = resolve;
this._promiseReject = reject;
});
return this._promise;
}
}
/**
* resolve of reject all promises
* @param {'resolve'|'reject'} fn
* @param {*} val
* @private
*/
_processPromises (fn, val) {
fn = '_promise' + fn[0].toUpperCase() + fn.substr(1);
if (!!this[fn]) this[fn](val);
}
/**
* composes change event
* @private
*/
_composeChangeEvent () {
return {
status: this.status,
statusName: this.statusName
}
}
/**
* composes change event
* @private
*/
_composeChangeError () {
if (!this.error) this.error = new Error(this.statusName);
this.error.status = this.status;
this.error.statusName = this.statusName;
return this.error;
}
/**
* returns instance of TaskStatus suitable for task type
* @param task
* @return {Promise | boolean}
*/
taskStatusMonitor (task) {
if (task instanceof Promise) return promisedTaskMonitor.call(this, task);
return false;
}
/**
* sets IN_PROCESS status
*/
inProcess () {
this.status = STATUS.IN_PROCESS;
}
/**
* sets DONE status
*/
done () {
this.status = STATUS.DONE;
}
/**
* sets FAILED status
*/
failed () {
this.status = STATUS.FAILED;
}
/**
* finish status monitoring trigger
*/
complete () {
this.isDone = true;
if (this.status === STATUS.FAILED) {
this._processPromises ('reject', this._composeChangeError());
}
if (this.status === STATUS.DONE) {
this._processPromises('resolve', this._composeChangeEvent());
}
this.emit('end');
}
/**
* returns status name for status
* @param {number} status
* @return {string}
*/
static statusName (status) {
return STATUSES[status];
}
}
/**
* promised task status monitor
*/
function promisedTaskMonitor (task) {
//there is no effect on original promise, as no insertion in then/catch chain happening, keep in this.promise for test purposes
return task
.then(data => {
this.data = data;
this.status = STATUS.DONE;
})
.catch(err => {
this.error = err;
this.status = STATUS.FAILED;
});
}
module.exports = TaskStatus;