rabbitmq-event-manager
Version:
A nodeJS Event Manager to emit, and listen event through RabbitMQ
200 lines • 10.3 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const uuid_1 = require("uuid");
const adapter = require("./adapter");
const defaultOptions_1 = require("./lib/defaultOptions");
const EventManagerError_1 = require("./lib/EventManagerError");
const helper_1 = require("./lib/helper");
const logger_1 = require("./lib/logger");
class EventManager {
constructor(options) {
this.options = Object.assign(Object.assign({}, defaultOptions_1.defaultOptions), options);
this.createLogger();
logger_1.LOGGER.debug('Event Manager initialized');
}
createLogger() {
logger_1.createLogger({
prefix: this.options.logPrefix,
level: this.options.logLevel,
transportMode: this.options.logTransportMode,
});
}
on(eventName, listener, options) {
return __awaiter(this, void 0, void 0, function* () {
try {
logger_1.LOGGER.debug(`Listening ${eventName} Event ...`);
const channel = yield adapter.createChannel(this.options.url);
const queueName = `${this.options.application}::${eventName}`;
const exchangeName = yield adapter.createExchange(channel, eventName, this.options.alternateExchangeName);
yield adapter.createQueue(channel, queueName, exchangeName, {
messageTtl: options ? options.ttl : this.options.ttl,
deadLetterExchange: options ? options.dlx : this.options.deadLetterExchangeName,
arguments: {
'x-dead-letter-routing-key': queueName,
},
});
const newListener = (payload) => {
return new Promise((resolve, reject) => {
const listenerInstance = listener(payload);
if (listenerInstance instanceof Promise) {
listenerInstance
.then(response => {
return this.emitResponseIfNeeded(payload, response);
})
.then(res => resolve(res))
.catch(err => reject(err));
}
else {
this.emitResponseIfNeeded(payload, listenerInstance)
.then(res => resolve(res))
.catch(err => reject(err));
}
});
};
adapter.consume(channel, queueName, newListener, this.options);
return;
}
catch (e) {
logger_1.LOGGER.error(`Unable to listen event ${eventName}`, e);
throw new EventManagerError_1.EventManagerError(`Unable to listen event ${eventName}`, e);
}
});
}
emit(eventName, payload) {
return __awaiter(this, void 0, void 0, function* () {
try {
logger_1.LOGGER.info(`Emitting ${eventName} Message ...`);
logger_1.LOGGER.debug(`Event ${eventName}, payload received`, { payload });
// we should create the metas information here
payload = this.addMetasToPayload(payload, eventName);
logger_1.LOGGER.debug(`Event ${eventName}, payload emitted`, { payload });
const channel = yield adapter.createChannel(this.options.url);
yield adapter.createExchange(channel, eventName, this.options.alternateExchangeName);
const returnedPayload = yield adapter.publish(channel, eventName, payload, this.options);
logger_1.LOGGER.debug(`Message ${eventName} Emitted`);
return returnedPayload;
}
catch (err) {
logger_1.LOGGER.error(err);
throw new EventManagerError_1.EventManagerError(`Unable to emit event ${eventName}`, err);
}
});
}
emitAndWait(eventName, payload, replyToName, options) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
logger_1.LOGGER.info(`Emitting ${eventName} Message and waiting ...`);
logger_1.LOGGER.debug(`Event ${eventName}, payload received`, { payload, replyToName });
let replyTo = replyToName ? replyToName : `${eventName}${this.options.defaultResponseSuffix}`;
const correlationId = uuid_1.v4();
replyTo += `.${correlationId}`;
const overrideMetas = payload._metas
? Object.assign({ correlationId,
replyTo }, payload._metas) : {
correlationId,
replyTo,
};
const newPayload = Object.assign({}, payload);
newPayload._metas = overrideMetas;
const listen = () => {
return new Promise(resolve => {
this.on(replyTo, (responsePayload) => {
resolve(responsePayload);
});
});
};
const duration = options && options.emitAndWaitTimeout ? options.emitAndWaitTimeout : this.options.emitAndWaitTimeout;
const timeoutMessage = `Timeout Error after ${duration} milliseconds for event ${eventName} and correlationId ${correlationId} `;
let channel;
let queueName;
Promise.race([helper_1.timeout(duration, timeoutMessage), listen()])
.then((payload) => __awaiter(this, void 0, void 0, function* () {
channel = yield adapter.createChannel(this.options.url);
queueName = `${this.options.application}::${replyTo}`;
yield adapter.deleteQueue(channel, queueName);
yield adapter.deleteExchange(channel, replyTo);
resolve(payload);
}))
.catch(() => {
setImmediate(() => __awaiter(this, void 0, void 0, function* () {
if (channel) {
yield adapter.deleteQueue(channel, queueName);
yield adapter.deleteExchange(channel, replyTo);
}
}));
reject();
});
const payloadEmitted = yield this.emit(eventName, newPayload);
logger_1.LOGGER.info(`EmitAndWait : ${eventName}`, { payload: payloadEmitted });
}));
});
}
initialize() {
return __awaiter(this, void 0, void 0, function* () {
try {
logger_1.LOGGER.debug(`Initializing EventManager`, Object.assign({}, this.options));
const channel = yield adapter.createChannel(this.options.url);
// Create Alternate
yield adapter.createExchange(channel, this.options.alternateExchangeName);
yield adapter.createQueue(channel, this.options.alternateQueueName, this.options.alternateExchangeName);
// Create Dead Letter
yield adapter.createExchange(channel, this.options.deadLetterExchangeName);
yield adapter.createQueue(channel, this.options.deadLetterQueueName, this.options.deadLetterExchangeName);
}
catch (err) {
throw new EventManagerError_1.EventManagerError('Error Initializing Event Manager', err);
}
});
}
close() {
return __awaiter(this, void 0, void 0, function* () {
logger_1.LOGGER.debug(`Disconnect EventManager`, Object.assign({}, this.options));
return adapter.disconnect();
});
}
addMetasToPayload(payload, eventName) {
if (!this.options.metas) {
return payload;
}
else {
const metasOverride = payload._metas ? payload._metas : {};
const metas = Object.assign({ guid: uuid_1.v4(), name: eventName, application: this.options.application, timestamp: Date.now() }, metasOverride);
if (isOverrideMetasFunction(this.options.metas)) {
return Object.assign(Object.assign({}, payload), { _metas: this.options.metas(metas) });
}
else {
return Object.assign(Object.assign({}, payload), { _metas: metas });
}
}
}
emitResponseIfNeeded(sourcePayload, targetPayload) {
return __awaiter(this, void 0, void 0, function* () {
if (sourcePayload &&
sourcePayload._metas &&
sourcePayload._metas.correlationId &&
sourcePayload._metas.replyTo &&
targetPayload !== null &&
typeof targetPayload === 'object') {
const newPayload = Object.assign({ _metas: {
responseTo: sourcePayload._metas.name,
correlationId: sourcePayload._metas.correlationId,
} }, targetPayload);
return this.emit(sourcePayload._metas.replyTo, newPayload);
}
});
}
}
exports.EventManager = EventManager;
function isOverrideMetasFunction(func) {
return {}.toString.call(func) === '[object Function]';
}
//# sourceMappingURL=EventManager.class.js.map