UNPKG

inceptum

Version:

hipages take on the foundational library for enterprise-grade apps written in NodeJS

162 lines 5.41 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const events_1 = require("events"); const LogManager_1 = require("../log/LogManager"); class LifecycleState { constructor(name, value) { this.name = name; this.value = value; LifecycleState.all.push(this); LifecycleState.all.sort((a, b) => { if (a.getValue() < b.getValue()) { return -1; } if (a.getValue() === b.getValue()) { return 0; } return 1; }); } static getStatesBefore(val) { return LifecycleState.all.filter((state) => state.getValue() < val.getValue()); } toString() { return this.name; } getName() { return this.name; } getValue() { return this.value; } isAfter(other) { return this.getValue() > other.getValue(); } isAtOrAfter(other) { return !this.isBefore(other); } isBefore(other) { return this.getValue() < other.getValue(); } isAtOrBefore(other) { return !this.isAfter(other); } } LifecycleState.all = []; LifecycleState.NOT_STARTED = new LifecycleState('NOT_STARTED', 0); LifecycleState.STARTING = new LifecycleState('STARTING', 1000); LifecycleState.STARTED = new LifecycleState('STARTED', 2000); LifecycleState.STOPPING = new LifecycleState('STOPPING', 10000); LifecycleState.STOPPED = new LifecycleState('STOPPED', 10001); exports.LifecycleState = LifecycleState; // STATES.all = Object.keys(STATES).filter((n) => n !== 'fromValue' && n !== 'all'); class LifecycleException extends Error { constructor(message, context) { super(message); this.context = context; } getContext() { return this.context; } } exports.LifecycleException = LifecycleException; class Lifecycle extends events_1.EventEmitter { constructor(name, logger) { super(); this.name = name; this.logger = logger || LogManager_1.LogManager.getLogger(__filename); this.status = LifecycleState.NOT_STARTED; } /** * Initiates the lifecycle of this object. * This is the method you should call before using the object * * @return {Promise<void>} A promise that will resolve when this object's lifecycle has started */ lcStart() { return new Promise((resolve, reject) => { if (!this.setStatus(LifecycleState.STARTING)) { reject(new Error(`Can't start object ${this.name}. It's on state ${this.status}`)); } else { this.startTime = Date.now(); resolve(); } }) .then(() => this.doStart()) .then(() => { this.setStatus(LifecycleState.STARTED, { elapsed: (Date.now() - this.startTime) }); }) .catch((err) => { if (this.logger) { this.logger.error({ err }, `There was an error starting element ${this.name}`); } throw err; }); } lcStop() { return new Promise((resolve, reject) => { if (!this.setStatus(LifecycleState.STOPPING)) { reject(new Error(`Can't stop object ${this.name}. It's on state ${this.status}`)); } else { this.stopTime = Date.now(); resolve(); } }) .then(() => this.doStop()) .then(() => { this.setStatus(LifecycleState.STOPPED, { elapsed: (Date.now() - this.startTime) }); }) .catch((err) => { if (this.logger) { this.logger.error({ err }, `There was an error stopping element ${this.name}`); } throw err; }); } setStatus(newStatus, eventPayload) { if (newStatus.getValue() < this.status.getValue()) { throw new LifecycleException(`Can't revert on the status chain. Object "${this.name}" can't go from ${this.status} to ${newStatus}`); } if (newStatus.getValue() === this.status.getValue()) { return false; } if (this.logger) { this.logger.debug(`Switching state for object ${this.name} from ${this.status} to ${newStatus}`); } this.status = newStatus; this.emit(newStatus.getName(), this.name, eventPayload); // Cleanup references to listeners that we may have skipped if any as they will never be called LifecycleState.getStatesBefore(newStatus).forEach((state) => this.removeAllListeners(state.getName())); return true; } getName() { return this.name; } onState(state, callback) { this.on(state.getName(), callback); } onStateOnce(state, callback) { this.once(state.getName(), callback); } assertState(state) { if (this.status !== state) { throw new LifecycleException(`Operation requires state to be ${state.getName()} but is ${this.status.getName()}`); } } getLogger() { return this.logger; } copy() { return this.constructor(this.name, this.logger); } getStatus() { return this.status; } setLogger(logger) { this.logger = logger; } } exports.Lifecycle = Lifecycle; //# sourceMappingURL=Lifecycle.js.map