redis-smq
Version:
A simple high-performance Redis message queue for Node.js.
216 lines • 10.2 kB
JavaScript
import { async, CallbackEmptyReplyError } from 'redis-smq-common';
import { redisKeys } from '../../../common/redis-keys/redis-keys.js';
import { _getQueueProperties } from '../../queue/_/_get-queue-properties.js';
import { _parseQueueParams } from '../../queue/_/_parse-queue-params.js';
import { EQueueProperty, } from '../../queue/index.js';
import { ExchangeFanOutExchangeHasBoundQueuesError, ExchangeFanOutQueueTypeError, ExchangeQueueIsNotBoundToExchangeError, } from '../errors/index.js';
import { ExchangeAbstract } from '../exchange-abstract.js';
import { _getFanOutExchangeQueues } from './_/_get-fan-out-exchange-queues.js';
import { _getQueueFanOutExchange } from './_/_get-queue-fan-out-exchange.js';
import { _validateExchangeFanOutParams } from './_/_validate-exchange-fan-out-params.js';
export class ExchangeFanOut extends ExchangeAbstract {
getQueues(exchangeParams, cb) {
const fanOutName = _validateExchangeFanOutParams(exchangeParams);
if (fanOutName instanceof Error)
cb(fanOutName);
else {
this.redisClient.getSetInstance((err, client) => {
if (err)
cb(err);
else if (!client)
cb(new CallbackEmptyReplyError());
else
_getFanOutExchangeQueues(client, fanOutName, cb);
});
}
}
saveExchange(exchangeParams, cb) {
const fanOutName = _validateExchangeFanOutParams(exchangeParams);
if (fanOutName instanceof Error)
cb(fanOutName);
else {
const { keyFanOutExchanges } = redisKeys.getMainKeys();
this.redisClient.getSetInstance((err, client) => {
if (err)
cb(err);
else {
client?.sadd(keyFanOutExchanges, fanOutName, (err) => cb(err));
}
});
}
}
deleteExchange(exchangeParams, cb) {
const fanOutName = _validateExchangeFanOutParams(exchangeParams);
if (fanOutName instanceof Error)
cb(fanOutName);
else {
const { keyExchangeBindings } = redisKeys.getFanOutExchangeKeys(fanOutName);
const { keyFanOutExchanges } = redisKeys.getMainKeys();
this.redisClient.getSetInstance((err, client) => {
if (err)
cb(err);
else {
client?.watch([keyFanOutExchanges, keyExchangeBindings], (err) => {
if (err)
cb(err);
else {
_getFanOutExchangeQueues(client, fanOutName, (err, reply = []) => {
if (err)
cb(err);
else if (reply.length)
cb(new ExchangeFanOutExchangeHasBoundQueuesError());
else {
const multi = client.multi();
multi.srem(keyFanOutExchanges, fanOutName);
multi.del(keyExchangeBindings);
multi.exec((err) => cb(err));
}
});
}
});
}
});
}
}
bindQueue(queue, exchangeParams, cb) {
const queueParams = _parseQueueParams(queue);
const fanOutName = _validateExchangeFanOutParams(exchangeParams);
if (queueParams instanceof Error)
cb(queueParams);
else if (fanOutName instanceof Error)
cb(fanOutName);
else {
const { keyQueueProperties } = redisKeys.getQueueKeys(queueParams, null);
const { keyExchangeBindings } = redisKeys.getFanOutExchangeKeys(fanOutName);
const { keyQueues, keyFanOutExchanges } = redisKeys.getMainKeys();
this.redisClient.getSetInstance((err, client) => {
if (err)
cb(err);
else if (!client)
cb(new CallbackEmptyReplyError());
else {
async.waterfall([
(cb) => client.watch([keyQueues, keyQueueProperties, keyExchangeBindings], (err) => cb(err)),
(cb) => _getQueueProperties(client, queueParams, cb),
(queueProperties, cb) => _getFanOutExchangeQueues(client, fanOutName, (err, queues) => {
if (err)
cb(err);
else {
const eQueue = queues?.pop();
if (eQueue)
_getQueueProperties(client, eQueue, (err, exchangeQueueProperties) => {
if (err)
cb(err);
else if (!exchangeQueueProperties)
cb(new CallbackEmptyReplyError());
else if (exchangeQueueProperties.queueType !==
queueProperties.queueType)
cb(new ExchangeFanOutQueueTypeError());
else
cb(null, queueProperties);
});
else
cb(null, queueProperties);
}
}),
(queueProperties, cb) => {
const currentExchangeParams = queueProperties.exchange;
if (currentExchangeParams === fanOutName)
cb();
else {
const multi = client.multi();
const queueParamsStr = JSON.stringify(queueParams);
multi.sadd(keyFanOutExchanges, fanOutName);
multi.sadd(keyExchangeBindings, queueParamsStr);
multi.hset(keyQueueProperties, String(EQueueProperty.EXCHANGE), fanOutName);
if (currentExchangeParams) {
const { keyExchangeBindings } = redisKeys.getFanOutExchangeKeys(currentExchangeParams);
multi.srem(keyExchangeBindings, queueParamsStr);
}
multi.exec((err) => cb(err));
}
},
], (err) => {
if (err)
client.unwatch(() => cb(err));
else
cb();
});
}
});
}
}
unbindQueue(queue, exchangeParams, cb) {
const queueParams = _parseQueueParams(queue);
const fanOutName = _validateExchangeFanOutParams(exchangeParams);
if (queueParams instanceof Error)
cb(queueParams);
else if (fanOutName instanceof Error)
cb(fanOutName);
else {
const { keyQueueProperties } = redisKeys.getQueueKeys(queueParams, null);
const { keyQueues } = redisKeys.getMainKeys();
const { keyExchangeBindings } = redisKeys.getFanOutExchangeKeys(fanOutName);
this.redisClient.getSetInstance((err, client) => {
if (err)
cb(err);
else if (!client)
cb(new CallbackEmptyReplyError());
else {
async.waterfall([
(cb) => client.watch([keyQueues, keyQueueProperties, keyExchangeBindings], (err) => cb(err)),
(cb) => _getQueueProperties(client, queueParams, (err, properties) => {
if (err)
cb(err);
else if (!properties)
cb(new CallbackEmptyReplyError());
else if (properties.exchange !== fanOutName)
cb(new ExchangeQueueIsNotBoundToExchangeError());
else
cb();
}),
(cb) => {
const multi = client.multi();
const queueParamsStr = JSON.stringify(queueParams);
multi.srem(keyExchangeBindings, queueParamsStr);
multi.hdel(keyQueueProperties, String(EQueueProperty.EXCHANGE));
multi.exec((err) => cb(err));
},
], (err) => {
if (err)
client.unwatch(() => cb(err));
else
cb();
});
}
});
}
}
getAllExchanges(cb) {
const { keyFanOutExchanges } = redisKeys.getMainKeys();
this.redisClient.getSetInstance((err, client) => {
if (err)
cb(err);
else if (!client)
cb(new CallbackEmptyReplyError());
else
client.sscanAll(keyFanOutExchanges, {}, cb);
});
}
getQueueExchange(queue, cb) {
const queueParams = _parseQueueParams(queue);
if (queueParams instanceof Error)
cb(queueParams);
else {
this.redisClient.getSetInstance((err, client) => {
if (err)
cb(err);
else if (!client)
cb(new CallbackEmptyReplyError());
else
_getQueueFanOutExchange(client, queueParams, cb);
});
}
}
}
//# sourceMappingURL=exchange-fan-out.js.map