UNPKG

nodejs-event-driven

Version:

NodeJS agnostic event driven with EventEmitter support

101 lines 3.9 kB
import { BaseEventBusService } from '../../../base-event-bus.service.js'; export default class RabbitmqEventBusService extends BaseEventBusService { static DEFAULT_USERNAME = 'guest'; static DEFAULT_PASSWORD = 'guest'; static DEFAULT_URL = `amqp://${RabbitmqEventBusService.DEFAULT_USERNAME}:${RabbitmqEventBusService.DEFAULT_PASSWORD}@localhost:5672`; #logger; #connection = null; #registeredChannel = {}; #url; constructor(config) { super(); this.#url = config.url ?? RabbitmqEventBusService.DEFAULT_URL; this.#logger = config.logger; } #checkConnection() { const connection = this.#connection; if (!connection) { throw new Error('Connection is not initialized'); } return connection; } async #closeRegisteredChannels() { await Promise.all(Object.keys(this.#registeredChannel).map(async (eventName) => { const channel = this.#registeredChannel[eventName]; await channel.cancel(eventName); this.off(eventName); })); } async #createChannel(eventName) { const connection = this.#checkConnection(); const channel = await connection.createChannel(); this.#registeredChannel[eventName] = channel; await channel.assertQueue(eventName, { durable: false }); return channel; } async #consumeQueue(eventName, listener, once = false) { if (once) { this.#logger?.debug(`register once listener for channel: ${eventName}`); } else { this.#logger?.debug(`register listener for channel: ${eventName}`); } const channel = await this.#createChannel(eventName); const consumeMsg = async (msg) => { if (once) { await channel.cancel(eventName); } const data = JSON.parse(String(msg.content)); this.#logger?.debug(`received event ${eventName}: ${String(data)}`); listener(data); return Promise.resolve(); }; await channel.consume(eventName, (msg) => { if (msg === null) { return; } void consumeMsg(msg); }, { noAck: true, consumerTag: eventName }); } on(eventName, listener) { void this.#consumeQueue(eventName, listener); } once(eventName, listener) { void this.#consumeQueue(eventName, listener, true); } off(eventName) { const channel = this.#registeredChannel[eventName]; if (!channel) { return; } delete this.#registeredChannel[eventName]; this.#logger?.debug(`closing channel ${eventName}`); void channel.close().catch((err) => { const error = err; this.#logger?.warn(`Error while trying to close channel for event: ${eventName}: ${error.message}`); }); } send(eventName, data) { void this.#createChannel(eventName).then((channel) => { this.#logger?.debug(`sending ${String(data)} to channel ${eventName}`); channel.sendToQueue(eventName, Buffer.from(JSON.stringify(data))); }); } sendAndWait(sendEventName, successEventName, errorEventName, data) { this.#logger?.debug(`sending event ${sendEventName} and waiting for event ${successEventName}…`); return super.sendAndWait(sendEventName, successEventName, errorEventName, data); } async start() { const { connect, } = await import('amqplib'); this.#connection = await connect(this.#url); } async stop() { await this.#closeRegisteredChannels(); const connection = this.#connection; if (connection) { await connection.close(); this.#connection = null; } } } //# sourceMappingURL=rabbitmq-event-bus.service.js.map