inceptum
Version:
hipages take on the foundational library for enterprise-grade apps written in NodeJS
162 lines • 5.41 kB
JavaScript
"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