UNPKG

@21jumpclick/service-messenger

Version:

Amqp lib to send and receive messages from different applications

214 lines 7.47 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Broker = void 0; const amqplib_1 = require("amqplib"); const crypto_1 = require("crypto"); const appId = '@21jumpclick/service-messenger'; const allowedAppIds = [ appId, '@vicgrk/messenger' ]; class Broker { constructor(opts, exchange) { this.opts = opts; this.exchange = exchange; this.closing = false; } async connect() { this.rabbitMQ = await (0, amqplib_1.connect)(typeof this.opts === 'string' ? this.opts : `amqp://${this.opts.user || 'guest'}:${this.opts.password || 'guest'}@${this.opts.host || 'localhost'}:${this.opts.port || 5672}?frameMax=0`); this.channel = await this.rabbitMQ.createChannel(); await this.channel.prefetch(10); await this.assertExchange(this.exchange); await this.assertBroadcast(); this.closing = false; } async publish(key, data, options) { if (this.closing) { return; } if (!this.channel) { await this.connect(); } await this.send(key, data, options); } async listen(cb) { if (this.closing) { return; } if (!this.channel) { await this.connect(); } this.channel.consume(this.broadcastQueue.queue, async (msg) => { if (!msg) { return; } this.channel.ack(msg); let opts = msg.properties.headers; opts || (opts = { origin: 'UNKNOWN' }); const args = JSON.parse(msg.content.toString()); const key = args.pattern; try { cb({ key, args, opts }); } catch (error) { console.error(error); } }); this.channel.consume(this.exchange, async (msg) => { if (!msg) { return; } this.channel.ack(msg); let tmp = JSON.parse(msg.content.toString()); const key = tmp.pattern; if (allowedAppIds.includes(msg.properties.appId) && typeof tmp.data !== 'undefined') { tmp = tmp.data; } const args = tmp; let opts = msg.properties.headers; opts || (opts = { origin: 'UNKNOWN' }); if (!msg.properties.correlationId) { try { cb({ key, args, opts }); } catch (error) { console.error(error); } } else { try { const data = await cb({ key, args, opts }); this.channel.sendToQueue(msg.properties.replyTo, Buffer.from(JSON.stringify({ data: { error: null, data } })), { correlationId: msg.properties.correlationId, headers: { origin: this.exchange, } }); } catch (error) { this.channel.sendToQueue(msg.properties.replyTo, Buffer.from(JSON.stringify({ data: { error } })), { correlationId: msg.properties.correlationId, headers: { origin: this.exchange, } }); } } }); } async broadcast(key, data) { if (this.closing) { return; } if (!this.channel) { await this.connect(); } const [exchange] = key.split('.'); await this.channel.assertExchange(`${exchange}-broadcast`, 'fanout', { durable: true }); const buffer = Buffer.from(JSON.stringify({ data })); this.channel.publish(`${exchange}-broadcast`, key, buffer, { appId, headers: { origin: this.exchange } }); } async invoke(key, data, options) { if (this.closing) { return; } if (!this.channel) { await this.connect(); } const correlationId = this.generateCorrelationId(); const { queue } = await this.channel.assertQueue('', { exclusive: true, autoDelete: true, durable: false, }); let opts = { ...options, appId, correlationId, replyTo: queue, headers: { ...options === null || options === void 0 ? void 0 : options.headers, origin: this.exchange } }; return new Promise((resolve, reject) => { this.channel.consume(queue, (msg) => { if (!msg) { return; } this.channel.ack(msg); this.channel.deleteQueue(queue); if (msg.properties.correlationId == correlationId) { const response = JSON.parse(msg.content.toString()).data; if (response.error) { return reject(response.error); } resolve(response.data); } }); this.send(key, data, opts); }); } async send(key, data, options) { const [exchange] = key.split('.'); await this.assertExchange(exchange); let opts = { ...options, headers: { ...options === null || options === void 0 ? void 0 : options.headers, // 'x-deduplication-header': options?.deduplicationFieldPath, origin: this.exchange }, appId, }; // if (options?.deduplicationFieldPath) { // opts['x-deduplication-header'] = valueFromPath(data, options.deduplicationFieldPath) // } const pattern = key.replace(`${exchange}.`, ''); const buffer = Buffer.from(JSON.stringify({ data, pattern })); this.channel.publish(exchange, key, buffer, opts); } async close() { try { this.closing = false; await this.channel.close(); return await this.rabbitMQ.close(); } catch (error) { return; } } async assertExchange(exchange) { var _a; await this.channel.assertExchange(exchange, ((_a = this.opts) === null || _a === void 0 ? void 0 : _a.exhangeType) || 'fanout', { durable: true, arguments: { 'x-cache-size': 128, 'x-cache-ttl': 1e3, 'x-cache-persistence': 'memory' } }); await this.channel.assertQueue(exchange, { durable: true, }); await this.channel.bindQueue(exchange, exchange, `${exchange}.*`); return; } async assertBroadcast() { await this.channel.assertExchange(`${this.exchange}-broadcast`, 'fanout', { durable: true }); this.broadcastQueue = await this.channel.assertQueue('', { durable: false, exclusive: true, }); await this.channel.bindQueue(this.broadcastQueue.queue, `${this.exchange}-broadcast`, '*'); } generateCorrelationId() { return (0, crypto_1.randomBytes)(4).toString('hex'); } } exports.Broker = Broker; //# sourceMappingURL=messenger.js.map