UNPKG

rabbitmq-event-manager

Version:

A nodeJS Event Manager to emit, and listen event through RabbitMQ

200 lines 10.3 kB
"use strict"; 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