@21jumpclick/service-messenger
Version:
Amqp lib to send and receive messages from different applications
214 lines • 7.47 kB
JavaScript
"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