@redis/client
Advanced tools
Comparing version 1.5.10 to 1.5.11
"use strict"; | ||
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); | ||
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); | ||
}; | ||
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
if (kind === "m") throw new TypeError("Private method is not writable"); | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); | ||
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; | ||
}; | ||
var _RedisCommandsQueue_instances, _a, _RedisCommandsQueue_flushQueue, _RedisCommandsQueue_maxLength, _RedisCommandsQueue_waitingToBeSent, _RedisCommandsQueue_waitingForReply, _RedisCommandsQueue_onShardedChannelMoved, _RedisCommandsQueue_pubSub, _RedisCommandsQueue_chainInExecution, _RedisCommandsQueue_decoder, _RedisCommandsQueue_pushPubSubCommand; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -10,60 +22,56 @@ const LinkedList = require("yallist"); | ||
class RedisCommandsQueue { | ||
static #flushQueue(queue, err) { | ||
while (queue.length) { | ||
queue.shift().reject(err); | ||
} | ||
} | ||
#maxLength; | ||
#waitingToBeSent = new LinkedList(); | ||
#waitingForReply = new LinkedList(); | ||
#onShardedChannelMoved; | ||
#pubSub = new pub_sub_1.PubSub(); | ||
get isPubSubActive() { | ||
return this.#pubSub.isActive; | ||
return __classPrivateFieldGet(this, _RedisCommandsQueue_pubSub, "f").isActive; | ||
} | ||
#chainInExecution; | ||
#decoder = new decoder_1.default({ | ||
returnStringsAsBuffers: () => { | ||
return !!this.#waitingForReply.head?.value.returnBuffers || | ||
this.#pubSub.isActive; | ||
}, | ||
onReply: reply => { | ||
if (this.#pubSub.isActive && Array.isArray(reply)) { | ||
if (this.#pubSub.handleMessageReply(reply)) | ||
return; | ||
const isShardedUnsubscribe = pub_sub_1.PubSub.isShardedUnsubscribe(reply); | ||
if (isShardedUnsubscribe && !this.#waitingForReply.length) { | ||
const channel = reply[1].toString(); | ||
this.#onShardedChannelMoved(channel, this.#pubSub.removeShardedListeners(channel)); | ||
return; | ||
} | ||
else if (isShardedUnsubscribe || pub_sub_1.PubSub.isStatusReply(reply)) { | ||
const head = this.#waitingForReply.head.value; | ||
if ((Number.isNaN(head.channelsCounter) && reply[2] === 0) || | ||
--head.channelsCounter === 0) { | ||
this.#waitingForReply.shift().resolve(); | ||
constructor(maxLength, onShardedChannelMoved) { | ||
_RedisCommandsQueue_instances.add(this); | ||
_RedisCommandsQueue_maxLength.set(this, void 0); | ||
_RedisCommandsQueue_waitingToBeSent.set(this, new LinkedList()); | ||
_RedisCommandsQueue_waitingForReply.set(this, new LinkedList()); | ||
_RedisCommandsQueue_onShardedChannelMoved.set(this, void 0); | ||
_RedisCommandsQueue_pubSub.set(this, new pub_sub_1.PubSub()); | ||
_RedisCommandsQueue_chainInExecution.set(this, void 0); | ||
_RedisCommandsQueue_decoder.set(this, new decoder_1.default({ | ||
returnStringsAsBuffers: () => { | ||
return !!__classPrivateFieldGet(this, _RedisCommandsQueue_waitingForReply, "f").head?.value.returnBuffers || | ||
__classPrivateFieldGet(this, _RedisCommandsQueue_pubSub, "f").isActive; | ||
}, | ||
onReply: reply => { | ||
if (__classPrivateFieldGet(this, _RedisCommandsQueue_pubSub, "f").isActive && Array.isArray(reply)) { | ||
if (__classPrivateFieldGet(this, _RedisCommandsQueue_pubSub, "f").handleMessageReply(reply)) | ||
return; | ||
const isShardedUnsubscribe = pub_sub_1.PubSub.isShardedUnsubscribe(reply); | ||
if (isShardedUnsubscribe && !__classPrivateFieldGet(this, _RedisCommandsQueue_waitingForReply, "f").length) { | ||
const channel = reply[1].toString(); | ||
__classPrivateFieldGet(this, _RedisCommandsQueue_onShardedChannelMoved, "f").call(this, channel, __classPrivateFieldGet(this, _RedisCommandsQueue_pubSub, "f").removeShardedListeners(channel)); | ||
return; | ||
} | ||
return; | ||
else if (isShardedUnsubscribe || pub_sub_1.PubSub.isStatusReply(reply)) { | ||
const head = __classPrivateFieldGet(this, _RedisCommandsQueue_waitingForReply, "f").head.value; | ||
if ((Number.isNaN(head.channelsCounter) && reply[2] === 0) || | ||
--head.channelsCounter === 0) { | ||
__classPrivateFieldGet(this, _RedisCommandsQueue_waitingForReply, "f").shift().resolve(); | ||
} | ||
return; | ||
} | ||
if (PONG.equals(reply[0])) { | ||
const { resolve, returnBuffers } = __classPrivateFieldGet(this, _RedisCommandsQueue_waitingForReply, "f").shift(), buffer = (reply[1].length === 0 ? reply[0] : reply[1]); | ||
resolve(returnBuffers ? buffer : buffer.toString()); | ||
return; | ||
} | ||
} | ||
if (PONG.equals(reply[0])) { | ||
const { resolve, returnBuffers } = this.#waitingForReply.shift(), buffer = (reply[1].length === 0 ? reply[0] : reply[1]); | ||
resolve(returnBuffers ? buffer : buffer.toString()); | ||
return; | ||
const { resolve, reject } = __classPrivateFieldGet(this, _RedisCommandsQueue_waitingForReply, "f").shift(); | ||
if (reply instanceof errors_1.ErrorReply) { | ||
reject(reply); | ||
} | ||
else { | ||
resolve(reply); | ||
} | ||
} | ||
const { resolve, reject } = this.#waitingForReply.shift(); | ||
if (reply instanceof errors_1.ErrorReply) { | ||
reject(reply); | ||
} | ||
else { | ||
resolve(reply); | ||
} | ||
} | ||
}); | ||
constructor(maxLength, onShardedChannelMoved) { | ||
this.#maxLength = maxLength; | ||
this.#onShardedChannelMoved = onShardedChannelMoved; | ||
})); | ||
__classPrivateFieldSet(this, _RedisCommandsQueue_maxLength, maxLength, "f"); | ||
__classPrivateFieldSet(this, _RedisCommandsQueue_onShardedChannelMoved, onShardedChannelMoved, "f"); | ||
} | ||
addCommand(args, options) { | ||
if (this.#maxLength && this.#waitingToBeSent.length + this.#waitingForReply.length >= this.#maxLength) { | ||
if (__classPrivateFieldGet(this, _RedisCommandsQueue_maxLength, "f") && __classPrivateFieldGet(this, _RedisCommandsQueue_waitingToBeSent, "f").length + __classPrivateFieldGet(this, _RedisCommandsQueue_waitingForReply, "f").length >= __classPrivateFieldGet(this, _RedisCommandsQueue_maxLength, "f")) { | ||
return Promise.reject(new Error('The queue is full')); | ||
@@ -84,3 +92,3 @@ } | ||
const listener = () => { | ||
this.#waitingToBeSent.removeNode(node); | ||
__classPrivateFieldGet(this, _RedisCommandsQueue_waitingToBeSent, "f").removeNode(node); | ||
node.value.reject(new errors_1.AbortError()); | ||
@@ -98,6 +106,6 @@ }; | ||
if (options?.asap) { | ||
this.#waitingToBeSent.unshiftNode(node); | ||
__classPrivateFieldGet(this, _RedisCommandsQueue_waitingToBeSent, "f").unshiftNode(node); | ||
} | ||
else { | ||
this.#waitingToBeSent.pushNode(node); | ||
__classPrivateFieldGet(this, _RedisCommandsQueue_waitingToBeSent, "f").pushNode(node); | ||
} | ||
@@ -107,43 +115,24 @@ }); | ||
subscribe(type, channels, listener, returnBuffers) { | ||
return this.#pushPubSubCommand(this.#pubSub.subscribe(type, channels, listener, returnBuffers)); | ||
return __classPrivateFieldGet(this, _RedisCommandsQueue_instances, "m", _RedisCommandsQueue_pushPubSubCommand).call(this, __classPrivateFieldGet(this, _RedisCommandsQueue_pubSub, "f").subscribe(type, channels, listener, returnBuffers)); | ||
} | ||
unsubscribe(type, channels, listener, returnBuffers) { | ||
return this.#pushPubSubCommand(this.#pubSub.unsubscribe(type, channels, listener, returnBuffers)); | ||
return __classPrivateFieldGet(this, _RedisCommandsQueue_instances, "m", _RedisCommandsQueue_pushPubSubCommand).call(this, __classPrivateFieldGet(this, _RedisCommandsQueue_pubSub, "f").unsubscribe(type, channels, listener, returnBuffers)); | ||
} | ||
resubscribe() { | ||
const commands = this.#pubSub.resubscribe(); | ||
const commands = __classPrivateFieldGet(this, _RedisCommandsQueue_pubSub, "f").resubscribe(); | ||
if (!commands.length) | ||
return; | ||
return Promise.all(commands.map(command => this.#pushPubSubCommand(command))); | ||
return Promise.all(commands.map(command => __classPrivateFieldGet(this, _RedisCommandsQueue_instances, "m", _RedisCommandsQueue_pushPubSubCommand).call(this, command))); | ||
} | ||
extendPubSubChannelListeners(type, channel, listeners) { | ||
return this.#pushPubSubCommand(this.#pubSub.extendChannelListeners(type, channel, listeners)); | ||
return __classPrivateFieldGet(this, _RedisCommandsQueue_instances, "m", _RedisCommandsQueue_pushPubSubCommand).call(this, __classPrivateFieldGet(this, _RedisCommandsQueue_pubSub, "f").extendChannelListeners(type, channel, listeners)); | ||
} | ||
extendPubSubListeners(type, listeners) { | ||
return this.#pushPubSubCommand(this.#pubSub.extendTypeListeners(type, listeners)); | ||
return __classPrivateFieldGet(this, _RedisCommandsQueue_instances, "m", _RedisCommandsQueue_pushPubSubCommand).call(this, __classPrivateFieldGet(this, _RedisCommandsQueue_pubSub, "f").extendTypeListeners(type, listeners)); | ||
} | ||
getPubSubListeners(type) { | ||
return this.#pubSub.getTypeListeners(type); | ||
return __classPrivateFieldGet(this, _RedisCommandsQueue_pubSub, "f").getTypeListeners(type); | ||
} | ||
#pushPubSubCommand(command) { | ||
if (command === undefined) | ||
return; | ||
return new Promise((resolve, reject) => { | ||
this.#waitingToBeSent.push({ | ||
args: command.args, | ||
channelsCounter: command.channelsCounter, | ||
returnBuffers: true, | ||
resolve: () => { | ||
command.resolve(); | ||
resolve(); | ||
}, | ||
reject: err => { | ||
command.reject?.(); | ||
reject(err); | ||
} | ||
}); | ||
}); | ||
} | ||
getCommandToSend() { | ||
const toSend = this.#waitingToBeSent.shift(); | ||
const toSend = __classPrivateFieldGet(this, _RedisCommandsQueue_waitingToBeSent, "f").shift(); | ||
if (!toSend) | ||
@@ -159,3 +148,3 @@ return; | ||
} | ||
this.#waitingForReply.push({ | ||
__classPrivateFieldGet(this, _RedisCommandsQueue_waitingForReply, "f").push({ | ||
resolve: toSend.resolve, | ||
@@ -166,26 +155,49 @@ reject: toSend.reject, | ||
}); | ||
this.#chainInExecution = toSend.chainId; | ||
__classPrivateFieldSet(this, _RedisCommandsQueue_chainInExecution, toSend.chainId, "f"); | ||
return encoded; | ||
} | ||
onReplyChunk(chunk) { | ||
this.#decoder.write(chunk); | ||
__classPrivateFieldGet(this, _RedisCommandsQueue_decoder, "f").write(chunk); | ||
} | ||
flushWaitingForReply(err) { | ||
this.#decoder.reset(); | ||
this.#pubSub.reset(); | ||
RedisCommandsQueue.#flushQueue(this.#waitingForReply, err); | ||
if (!this.#chainInExecution) | ||
__classPrivateFieldGet(this, _RedisCommandsQueue_decoder, "f").reset(); | ||
__classPrivateFieldGet(this, _RedisCommandsQueue_pubSub, "f").reset(); | ||
__classPrivateFieldGet(_a, _a, "m", _RedisCommandsQueue_flushQueue).call(_a, __classPrivateFieldGet(this, _RedisCommandsQueue_waitingForReply, "f"), err); | ||
if (!__classPrivateFieldGet(this, _RedisCommandsQueue_chainInExecution, "f")) | ||
return; | ||
while (this.#waitingToBeSent.head?.value.chainId === this.#chainInExecution) { | ||
this.#waitingToBeSent.shift(); | ||
while (__classPrivateFieldGet(this, _RedisCommandsQueue_waitingToBeSent, "f").head?.value.chainId === __classPrivateFieldGet(this, _RedisCommandsQueue_chainInExecution, "f")) { | ||
__classPrivateFieldGet(this, _RedisCommandsQueue_waitingToBeSent, "f").shift(); | ||
} | ||
this.#chainInExecution = undefined; | ||
__classPrivateFieldSet(this, _RedisCommandsQueue_chainInExecution, undefined, "f"); | ||
} | ||
flushAll(err) { | ||
this.#decoder.reset(); | ||
this.#pubSub.reset(); | ||
RedisCommandsQueue.#flushQueue(this.#waitingForReply, err); | ||
RedisCommandsQueue.#flushQueue(this.#waitingToBeSent, err); | ||
__classPrivateFieldGet(this, _RedisCommandsQueue_decoder, "f").reset(); | ||
__classPrivateFieldGet(this, _RedisCommandsQueue_pubSub, "f").reset(); | ||
__classPrivateFieldGet(_a, _a, "m", _RedisCommandsQueue_flushQueue).call(_a, __classPrivateFieldGet(this, _RedisCommandsQueue_waitingForReply, "f"), err); | ||
__classPrivateFieldGet(_a, _a, "m", _RedisCommandsQueue_flushQueue).call(_a, __classPrivateFieldGet(this, _RedisCommandsQueue_waitingToBeSent, "f"), err); | ||
} | ||
} | ||
_a = RedisCommandsQueue, _RedisCommandsQueue_maxLength = new WeakMap(), _RedisCommandsQueue_waitingToBeSent = new WeakMap(), _RedisCommandsQueue_waitingForReply = new WeakMap(), _RedisCommandsQueue_onShardedChannelMoved = new WeakMap(), _RedisCommandsQueue_pubSub = new WeakMap(), _RedisCommandsQueue_chainInExecution = new WeakMap(), _RedisCommandsQueue_decoder = new WeakMap(), _RedisCommandsQueue_instances = new WeakSet(), _RedisCommandsQueue_flushQueue = function _RedisCommandsQueue_flushQueue(queue, err) { | ||
while (queue.length) { | ||
queue.shift().reject(err); | ||
} | ||
}, _RedisCommandsQueue_pushPubSubCommand = function _RedisCommandsQueue_pushPubSubCommand(command) { | ||
if (command === undefined) | ||
return; | ||
return new Promise((resolve, reject) => { | ||
__classPrivateFieldGet(this, _RedisCommandsQueue_waitingToBeSent, "f").push({ | ||
args: command.args, | ||
channelsCounter: command.channelsCounter, | ||
returnBuffers: true, | ||
resolve: () => { | ||
command.resolve(); | ||
resolve(); | ||
}, | ||
reject: err => { | ||
command.reject?.(); | ||
reject(err); | ||
} | ||
}); | ||
}); | ||
}; | ||
exports.default = RedisCommandsQueue; |
"use strict"; | ||
var _a; | ||
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); | ||
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); | ||
}; | ||
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
if (kind === "m") throw new TypeError("Private method is not writable"); | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); | ||
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; | ||
}; | ||
var _RedisClient_instances, _a, _RedisClient_options, _RedisClient_socket, _RedisClient_queue, _RedisClient_isolationPool, _RedisClient_v4, _RedisClient_selectedDB, _RedisClient_initiateOptions, _RedisClient_initiateQueue, _RedisClient_initiateSocket, _RedisClient_initiateIsolationPool, _RedisClient_legacyMode, _RedisClient_legacySendCommand, _RedisClient_defineLegacyCommand, _RedisClient_pingTimer, _RedisClient_setPingTimer, _RedisClient_sendCommand, _RedisClient_pubSubCommand, _RedisClient_tick, _RedisClient_addMultiCommands, _RedisClient_destroyIsolationPool; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -19,3 +30,2 @@ const commands_1 = require("./commands"); | ||
} | ||
commandOptions = _a.commandOptions; | ||
static extend(extensions) { | ||
@@ -70,187 +80,101 @@ const Client = (0, commander_1.attachExtensions)({ | ||
} | ||
#options; | ||
#socket; | ||
#queue; | ||
#isolationPool; | ||
#v4 = {}; | ||
#selectedDB = 0; | ||
get options() { | ||
return this.#options; | ||
return __classPrivateFieldGet(this, _RedisClient_options, "f"); | ||
} | ||
get isOpen() { | ||
return this.#socket.isOpen; | ||
return __classPrivateFieldGet(this, _RedisClient_socket, "f").isOpen; | ||
} | ||
get isReady() { | ||
return this.#socket.isReady; | ||
return __classPrivateFieldGet(this, _RedisClient_socket, "f").isReady; | ||
} | ||
get isPubSubActive() { | ||
return this.#queue.isPubSubActive; | ||
return __classPrivateFieldGet(this, _RedisClient_queue, "f").isPubSubActive; | ||
} | ||
get v4() { | ||
if (!this.#options?.legacyMode) { | ||
if (!__classPrivateFieldGet(this, _RedisClient_options, "f")?.legacyMode) { | ||
throw new Error('the client is not in "legacy mode"'); | ||
} | ||
return this.#v4; | ||
return __classPrivateFieldGet(this, _RedisClient_v4, "f"); | ||
} | ||
constructor(options) { | ||
super(); | ||
this.#options = this.#initiateOptions(options); | ||
this.#queue = this.#initiateQueue(); | ||
this.#socket = this.#initiateSocket(); | ||
_RedisClient_instances.add(this); | ||
Object.defineProperty(this, "commandOptions", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: _a.commandOptions | ||
}); | ||
_RedisClient_options.set(this, void 0); | ||
_RedisClient_socket.set(this, void 0); | ||
_RedisClient_queue.set(this, void 0); | ||
_RedisClient_isolationPool.set(this, void 0); | ||
_RedisClient_v4.set(this, {}); | ||
_RedisClient_selectedDB.set(this, 0); | ||
_RedisClient_pingTimer.set(this, void 0); | ||
Object.defineProperty(this, "select", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: this.SELECT | ||
}); | ||
Object.defineProperty(this, "subscribe", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: this.SUBSCRIBE | ||
}); | ||
Object.defineProperty(this, "unsubscribe", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: this.UNSUBSCRIBE | ||
}); | ||
Object.defineProperty(this, "pSubscribe", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: this.PSUBSCRIBE | ||
}); | ||
Object.defineProperty(this, "pUnsubscribe", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: this.PUNSUBSCRIBE | ||
}); | ||
Object.defineProperty(this, "sSubscribe", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: this.SSUBSCRIBE | ||
}); | ||
Object.defineProperty(this, "sUnsubscribe", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: this.SUNSUBSCRIBE | ||
}); | ||
Object.defineProperty(this, "quit", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: this.QUIT | ||
}); | ||
Object.defineProperty(this, "multi", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: this.MULTI | ||
}); | ||
__classPrivateFieldSet(this, _RedisClient_options, __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_initiateOptions).call(this, options), "f"); | ||
__classPrivateFieldSet(this, _RedisClient_queue, __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_initiateQueue).call(this), "f"); | ||
__classPrivateFieldSet(this, _RedisClient_socket, __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_initiateSocket).call(this), "f"); | ||
// should be initiated in connect, not here | ||
// TODO: consider breaking in v5 | ||
this.#isolationPool = this.#initiateIsolationPool(); | ||
this.#legacyMode(); | ||
__classPrivateFieldSet(this, _RedisClient_isolationPool, __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_initiateIsolationPool).call(this), "f"); | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_legacyMode).call(this); | ||
} | ||
#initiateOptions(options) { | ||
if (options?.url) { | ||
const parsed = _a.parseURL(options.url); | ||
if (options.socket) { | ||
parsed.socket = Object.assign(options.socket, parsed.socket); | ||
} | ||
Object.assign(options, parsed); | ||
} | ||
if (options?.database) { | ||
this.#selectedDB = options.database; | ||
} | ||
return options; | ||
} | ||
#initiateQueue() { | ||
return new commands_queue_1.default(this.#options?.commandsQueueMaxLength, (channel, listeners) => this.emit('sharded-channel-moved', channel, listeners)); | ||
} | ||
#initiateSocket() { | ||
const socketInitiator = async () => { | ||
const promises = []; | ||
if (this.#selectedDB !== 0) { | ||
promises.push(this.#queue.addCommand(['SELECT', this.#selectedDB.toString()], { asap: true })); | ||
} | ||
if (this.#options?.readonly) { | ||
promises.push(this.#queue.addCommand(commands_1.default.READONLY.transformArguments(), { asap: true })); | ||
} | ||
if (this.#options?.name) { | ||
promises.push(this.#queue.addCommand(commands_1.default.CLIENT_SETNAME.transformArguments(this.#options.name), { asap: true })); | ||
} | ||
if (this.#options?.username || this.#options?.password) { | ||
promises.push(this.#queue.addCommand(commands_1.default.AUTH.transformArguments({ | ||
username: this.#options.username, | ||
password: this.#options.password ?? '' | ||
}), { asap: true })); | ||
} | ||
const resubscribePromise = this.#queue.resubscribe(); | ||
if (resubscribePromise) { | ||
promises.push(resubscribePromise); | ||
} | ||
if (promises.length) { | ||
this.#tick(true); | ||
await Promise.all(promises); | ||
} | ||
}; | ||
return new socket_1.default(socketInitiator, this.#options?.socket) | ||
.on('data', chunk => this.#queue.onReplyChunk(chunk)) | ||
.on('error', err => { | ||
this.emit('error', err); | ||
if (this.#socket.isOpen && !this.#options?.disableOfflineQueue) { | ||
this.#queue.flushWaitingForReply(err); | ||
} | ||
else { | ||
this.#queue.flushAll(err); | ||
} | ||
}) | ||
.on('connect', () => { | ||
this.emit('connect'); | ||
}) | ||
.on('ready', () => { | ||
this.emit('ready'); | ||
this.#setPingTimer(); | ||
this.#tick(); | ||
}) | ||
.on('reconnecting', () => this.emit('reconnecting')) | ||
.on('drain', () => this.#tick()) | ||
.on('end', () => this.emit('end')); | ||
} | ||
#initiateIsolationPool() { | ||
return (0, generic_pool_1.createPool)({ | ||
create: async () => { | ||
const duplicate = this.duplicate({ | ||
isolationPoolOptions: undefined | ||
}).on('error', err => this.emit('error', err)); | ||
await duplicate.connect(); | ||
return duplicate; | ||
}, | ||
destroy: client => client.disconnect() | ||
}, this.#options?.isolationPoolOptions); | ||
} | ||
#legacyMode() { | ||
if (!this.#options?.legacyMode) | ||
return; | ||
this.#v4.sendCommand = this.#sendCommand.bind(this); | ||
this.sendCommand = (...args) => { | ||
const result = this.#legacySendCommand(...args); | ||
if (result) { | ||
result.promise | ||
.then(reply => result.callback(null, reply)) | ||
.catch(err => result.callback(err)); | ||
} | ||
}; | ||
for (const [name, command] of Object.entries(commands_1.default)) { | ||
this.#defineLegacyCommand(name, command); | ||
this[name.toLowerCase()] ??= this[name]; | ||
} | ||
// hard coded commands | ||
this.#defineLegacyCommand('SELECT'); | ||
this.#defineLegacyCommand('select'); | ||
this.#defineLegacyCommand('SUBSCRIBE'); | ||
this.#defineLegacyCommand('subscribe'); | ||
this.#defineLegacyCommand('PSUBSCRIBE'); | ||
this.#defineLegacyCommand('pSubscribe'); | ||
this.#defineLegacyCommand('UNSUBSCRIBE'); | ||
this.#defineLegacyCommand('unsubscribe'); | ||
this.#defineLegacyCommand('PUNSUBSCRIBE'); | ||
this.#defineLegacyCommand('pUnsubscribe'); | ||
this.#defineLegacyCommand('QUIT'); | ||
this.#defineLegacyCommand('quit'); | ||
} | ||
#legacySendCommand(...args) { | ||
const callback = typeof args[args.length - 1] === 'function' ? | ||
args.pop() : | ||
undefined; | ||
const promise = this.#sendCommand((0, commander_1.transformLegacyCommandArguments)(args)); | ||
if (callback) | ||
return { | ||
promise, | ||
callback | ||
}; | ||
promise.catch(err => this.emit('error', err)); | ||
} | ||
#defineLegacyCommand(name, command) { | ||
this.#v4[name] = this[name].bind(this); | ||
this[name] = command && command.TRANSFORM_LEGACY_REPLY && command.transformReply ? | ||
(...args) => { | ||
const result = this.#legacySendCommand(name, ...args); | ||
if (result) { | ||
result.promise | ||
.then(reply => result.callback(null, command.transformReply(reply))) | ||
.catch(err => result.callback(err)); | ||
} | ||
} : | ||
(...args) => this.sendCommand(name, ...args); | ||
} | ||
#pingTimer; | ||
#setPingTimer() { | ||
if (!this.#options?.pingInterval || !this.#socket.isReady) | ||
return; | ||
clearTimeout(this.#pingTimer); | ||
this.#pingTimer = setTimeout(() => { | ||
if (!this.#socket.isReady) | ||
return; | ||
// using #sendCommand to support legacy mode | ||
this.#sendCommand(['PING']) | ||
.then(reply => this.emit('ping-interval', reply)) | ||
.catch(err => this.emit('error', err)) | ||
.finally(() => this.#setPingTimer()); | ||
}, this.#options.pingInterval); | ||
} | ||
duplicate(overrides) { | ||
return new (Object.getPrototypeOf(this).constructor)({ | ||
...this.#options, | ||
...__classPrivateFieldGet(this, _RedisClient_options, "f"), | ||
...overrides | ||
@@ -261,4 +185,4 @@ }); | ||
// see comment in constructor | ||
this.#isolationPool ??= this.#initiateIsolationPool(); | ||
await this.#socket.connect(); | ||
__classPrivateFieldSet(this, _RedisClient_isolationPool, __classPrivateFieldGet(this, _RedisClient_isolationPool, "f") ?? __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_initiateIsolationPool).call(this), "f"); | ||
await __classPrivateFieldGet(this, _RedisClient_socket, "f").connect(); | ||
return this; | ||
@@ -268,25 +192,7 @@ } | ||
const { args: redisArgs, options } = (0, commander_1.transformCommandArguments)(command, args); | ||
return (0, commander_1.transformCommandReply)(command, await this.#sendCommand(redisArgs, options), redisArgs.preserve); | ||
return (0, commander_1.transformCommandReply)(command, await __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_sendCommand).call(this, redisArgs, options), redisArgs.preserve); | ||
} | ||
sendCommand(args, options) { | ||
return this.#sendCommand(args, options); | ||
return __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_sendCommand).call(this, args, options); | ||
} | ||
// using `#sendCommand` cause `sendCommand` is overwritten in legacy mode | ||
#sendCommand(args, options) { | ||
if (!this.#socket.isOpen) { | ||
return Promise.reject(new errors_1.ClientClosedError()); | ||
} | ||
else if (options?.isolated) { | ||
return this.executeIsolated(isolatedClient => isolatedClient.sendCommand(args, { | ||
...options, | ||
isolated: false | ||
})); | ||
} | ||
else if (!this.#socket.isReady && this.#options?.disableOfflineQueue) { | ||
return Promise.reject(new errors_1.ClientOfflineError()); | ||
} | ||
const promise = this.#queue.addCommand(args, options); | ||
this.#tick(); | ||
return promise; | ||
} | ||
async functionsExecuter(fn, args, name) { | ||
@@ -297,3 +203,3 @@ const { args: redisArgs, options } = (0, commander_1.transformCommandArguments)(fn, args); | ||
executeFunction(name, fn, args, options) { | ||
return this.#sendCommand((0, commander_1.fCallArguments)(name, fn, args), options); | ||
return __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_sendCommand).call(this, (0, commander_1.fCallArguments)(name, fn, args), options); | ||
} | ||
@@ -311,3 +217,3 @@ async scriptsExecuter(script, args) { | ||
try { | ||
return await this.#sendCommand(redisArgs, options); | ||
return await __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_sendCommand).call(this, redisArgs, options); | ||
} | ||
@@ -320,3 +226,3 @@ catch (err) { | ||
redisArgs[1] = script.SCRIPT; | ||
return this.#sendCommand(redisArgs, options); | ||
return __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_sendCommand).call(this, redisArgs, options); | ||
} | ||
@@ -329,54 +235,41 @@ } | ||
} | ||
await this.#sendCommand(['SELECT', db.toString()], options); | ||
this.#selectedDB = db; | ||
await __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_sendCommand).call(this, ['SELECT', db.toString()], options); | ||
__classPrivateFieldSet(this, _RedisClient_selectedDB, db, "f"); | ||
} | ||
select = this.SELECT; | ||
#pubSubCommand(promise) { | ||
if (promise === undefined) | ||
return Promise.resolve(); | ||
this.#tick(); | ||
return promise; | ||
} | ||
SUBSCRIBE(channels, listener, bufferMode) { | ||
return this.#pubSubCommand(this.#queue.subscribe(pub_sub_1.PubSubType.CHANNELS, channels, listener, bufferMode)); | ||
return __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_pubSubCommand).call(this, __classPrivateFieldGet(this, _RedisClient_queue, "f").subscribe(pub_sub_1.PubSubType.CHANNELS, channels, listener, bufferMode)); | ||
} | ||
subscribe = this.SUBSCRIBE; | ||
UNSUBSCRIBE(channels, listener, bufferMode) { | ||
return this.#pubSubCommand(this.#queue.unsubscribe(pub_sub_1.PubSubType.CHANNELS, channels, listener, bufferMode)); | ||
return __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_pubSubCommand).call(this, __classPrivateFieldGet(this, _RedisClient_queue, "f").unsubscribe(pub_sub_1.PubSubType.CHANNELS, channels, listener, bufferMode)); | ||
} | ||
unsubscribe = this.UNSUBSCRIBE; | ||
PSUBSCRIBE(patterns, listener, bufferMode) { | ||
return this.#pubSubCommand(this.#queue.subscribe(pub_sub_1.PubSubType.PATTERNS, patterns, listener, bufferMode)); | ||
return __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_pubSubCommand).call(this, __classPrivateFieldGet(this, _RedisClient_queue, "f").subscribe(pub_sub_1.PubSubType.PATTERNS, patterns, listener, bufferMode)); | ||
} | ||
pSubscribe = this.PSUBSCRIBE; | ||
PUNSUBSCRIBE(patterns, listener, bufferMode) { | ||
return this.#pubSubCommand(this.#queue.unsubscribe(pub_sub_1.PubSubType.PATTERNS, patterns, listener, bufferMode)); | ||
return __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_pubSubCommand).call(this, __classPrivateFieldGet(this, _RedisClient_queue, "f").unsubscribe(pub_sub_1.PubSubType.PATTERNS, patterns, listener, bufferMode)); | ||
} | ||
pUnsubscribe = this.PUNSUBSCRIBE; | ||
SSUBSCRIBE(channels, listener, bufferMode) { | ||
return this.#pubSubCommand(this.#queue.subscribe(pub_sub_1.PubSubType.SHARDED, channels, listener, bufferMode)); | ||
return __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_pubSubCommand).call(this, __classPrivateFieldGet(this, _RedisClient_queue, "f").subscribe(pub_sub_1.PubSubType.SHARDED, channels, listener, bufferMode)); | ||
} | ||
sSubscribe = this.SSUBSCRIBE; | ||
SUNSUBSCRIBE(channels, listener, bufferMode) { | ||
return this.#pubSubCommand(this.#queue.unsubscribe(pub_sub_1.PubSubType.SHARDED, channels, listener, bufferMode)); | ||
return __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_pubSubCommand).call(this, __classPrivateFieldGet(this, _RedisClient_queue, "f").unsubscribe(pub_sub_1.PubSubType.SHARDED, channels, listener, bufferMode)); | ||
} | ||
sUnsubscribe = this.SUNSUBSCRIBE; | ||
getPubSubListeners(type) { | ||
return this.#queue.getPubSubListeners(type); | ||
return __classPrivateFieldGet(this, _RedisClient_queue, "f").getPubSubListeners(type); | ||
} | ||
extendPubSubChannelListeners(type, channel, listeners) { | ||
return this.#pubSubCommand(this.#queue.extendPubSubChannelListeners(type, channel, listeners)); | ||
return __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_pubSubCommand).call(this, __classPrivateFieldGet(this, _RedisClient_queue, "f").extendPubSubChannelListeners(type, channel, listeners)); | ||
} | ||
extendPubSubListeners(type, listeners) { | ||
return this.#pubSubCommand(this.#queue.extendPubSubListeners(type, listeners)); | ||
return __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_pubSubCommand).call(this, __classPrivateFieldGet(this, _RedisClient_queue, "f").extendPubSubListeners(type, listeners)); | ||
} | ||
QUIT() { | ||
return this.#socket.quit(async () => { | ||
if (this.#pingTimer) | ||
clearTimeout(this.#pingTimer); | ||
const quitPromise = this.#queue.addCommand(['QUIT']); | ||
this.#tick(); | ||
return __classPrivateFieldGet(this, _RedisClient_socket, "f").quit(async () => { | ||
if (__classPrivateFieldGet(this, _RedisClient_pingTimer, "f")) | ||
clearTimeout(__classPrivateFieldGet(this, _RedisClient_pingTimer, "f")); | ||
const quitPromise = __classPrivateFieldGet(this, _RedisClient_queue, "f").addCommand(['QUIT']); | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_tick).call(this); | ||
const [reply] = await Promise.all([ | ||
quitPromise, | ||
this.#destroyIsolationPool() | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_destroyIsolationPool).call(this) | ||
]); | ||
@@ -386,26 +279,12 @@ return reply; | ||
} | ||
quit = this.QUIT; | ||
#tick(force = false) { | ||
if (this.#socket.writableNeedDrain || (!force && !this.#socket.isReady)) { | ||
return; | ||
} | ||
this.#socket.cork(); | ||
while (!this.#socket.writableNeedDrain) { | ||
const args = this.#queue.getCommandToSend(); | ||
if (args === undefined) | ||
break; | ||
this.#socket.writeCommand(args); | ||
} | ||
} | ||
executeIsolated(fn) { | ||
if (!this.#isolationPool) | ||
if (!__classPrivateFieldGet(this, _RedisClient_isolationPool, "f")) | ||
return Promise.reject(new errors_1.ClientClosedError()); | ||
return this.#isolationPool.use(fn); | ||
return __classPrivateFieldGet(this, _RedisClient_isolationPool, "f").use(fn); | ||
} | ||
MULTI() { | ||
return new this.Multi(this.multiExecutor.bind(this), this.#options?.legacyMode); | ||
return new this.Multi(this.multiExecutor.bind(this), __classPrivateFieldGet(this, _RedisClient_options, "f")?.legacyMode); | ||
} | ||
multi = this.MULTI; | ||
async multiExecutor(commands, selectedDB, chainId) { | ||
if (!this.#socket.isOpen) { | ||
if (!__classPrivateFieldGet(this, _RedisClient_socket, "f").isOpen) { | ||
return Promise.reject(new errors_1.ClientClosedError()); | ||
@@ -416,17 +295,14 @@ } | ||
Promise.all([ | ||
this.#queue.addCommand(['MULTI'], { chainId }), | ||
this.#addMultiCommands(commands, chainId), | ||
this.#queue.addCommand(['EXEC'], { chainId }) | ||
__classPrivateFieldGet(this, _RedisClient_queue, "f").addCommand(['MULTI'], { chainId }), | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_addMultiCommands).call(this, commands, chainId), | ||
__classPrivateFieldGet(this, _RedisClient_queue, "f").addCommand(['EXEC'], { chainId }) | ||
]) : | ||
this.#addMultiCommands(commands); | ||
this.#tick(); | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_addMultiCommands).call(this, commands); | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_tick).call(this); | ||
const results = await promise; | ||
if (selectedDB !== undefined) { | ||
this.#selectedDB = selectedDB; | ||
__classPrivateFieldSet(this, _RedisClient_selectedDB, selectedDB, "f"); | ||
} | ||
return results; | ||
} | ||
#addMultiCommands(commands, chainId) { | ||
return Promise.all(commands.map(({ args }) => this.#queue.addCommand(args, { chainId }))); | ||
} | ||
async *scanIterator(options) { | ||
@@ -473,21 +349,194 @@ let cursor = 0; | ||
async disconnect() { | ||
if (this.#pingTimer) | ||
clearTimeout(this.#pingTimer); | ||
this.#queue.flushAll(new errors_1.DisconnectsClientError()); | ||
this.#socket.disconnect(); | ||
await this.#destroyIsolationPool(); | ||
if (__classPrivateFieldGet(this, _RedisClient_pingTimer, "f")) | ||
clearTimeout(__classPrivateFieldGet(this, _RedisClient_pingTimer, "f")); | ||
__classPrivateFieldGet(this, _RedisClient_queue, "f").flushAll(new errors_1.DisconnectsClientError()); | ||
__classPrivateFieldGet(this, _RedisClient_socket, "f").disconnect(); | ||
await __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_destroyIsolationPool).call(this); | ||
} | ||
async #destroyIsolationPool() { | ||
await this.#isolationPool.drain(); | ||
await this.#isolationPool.clear(); | ||
this.#isolationPool = undefined; | ||
} | ||
ref() { | ||
this.#socket.ref(); | ||
__classPrivateFieldGet(this, _RedisClient_socket, "f").ref(); | ||
} | ||
unref() { | ||
this.#socket.unref(); | ||
__classPrivateFieldGet(this, _RedisClient_socket, "f").unref(); | ||
} | ||
} | ||
_a = RedisClient; | ||
_a = RedisClient, _RedisClient_options = new WeakMap(), _RedisClient_socket = new WeakMap(), _RedisClient_queue = new WeakMap(), _RedisClient_isolationPool = new WeakMap(), _RedisClient_v4 = new WeakMap(), _RedisClient_selectedDB = new WeakMap(), _RedisClient_pingTimer = new WeakMap(), _RedisClient_instances = new WeakSet(), _RedisClient_initiateOptions = function _RedisClient_initiateOptions(options) { | ||
if (options?.url) { | ||
const parsed = _a.parseURL(options.url); | ||
if (options.socket) { | ||
parsed.socket = Object.assign(options.socket, parsed.socket); | ||
} | ||
Object.assign(options, parsed); | ||
} | ||
if (options?.database) { | ||
__classPrivateFieldSet(this, _RedisClient_selectedDB, options.database, "f"); | ||
} | ||
return options; | ||
}, _RedisClient_initiateQueue = function _RedisClient_initiateQueue() { | ||
return new commands_queue_1.default(__classPrivateFieldGet(this, _RedisClient_options, "f")?.commandsQueueMaxLength, (channel, listeners) => this.emit('sharded-channel-moved', channel, listeners)); | ||
}, _RedisClient_initiateSocket = function _RedisClient_initiateSocket() { | ||
const socketInitiator = async () => { | ||
const promises = []; | ||
if (__classPrivateFieldGet(this, _RedisClient_selectedDB, "f") !== 0) { | ||
promises.push(__classPrivateFieldGet(this, _RedisClient_queue, "f").addCommand(['SELECT', __classPrivateFieldGet(this, _RedisClient_selectedDB, "f").toString()], { asap: true })); | ||
} | ||
if (__classPrivateFieldGet(this, _RedisClient_options, "f")?.readonly) { | ||
promises.push(__classPrivateFieldGet(this, _RedisClient_queue, "f").addCommand(commands_1.default.READONLY.transformArguments(), { asap: true })); | ||
} | ||
if (__classPrivateFieldGet(this, _RedisClient_options, "f")?.name) { | ||
promises.push(__classPrivateFieldGet(this, _RedisClient_queue, "f").addCommand(commands_1.default.CLIENT_SETNAME.transformArguments(__classPrivateFieldGet(this, _RedisClient_options, "f").name), { asap: true })); | ||
} | ||
if (__classPrivateFieldGet(this, _RedisClient_options, "f")?.username || __classPrivateFieldGet(this, _RedisClient_options, "f")?.password) { | ||
promises.push(__classPrivateFieldGet(this, _RedisClient_queue, "f").addCommand(commands_1.default.AUTH.transformArguments({ | ||
username: __classPrivateFieldGet(this, _RedisClient_options, "f").username, | ||
password: __classPrivateFieldGet(this, _RedisClient_options, "f").password ?? '' | ||
}), { asap: true })); | ||
} | ||
const resubscribePromise = __classPrivateFieldGet(this, _RedisClient_queue, "f").resubscribe(); | ||
if (resubscribePromise) { | ||
promises.push(resubscribePromise); | ||
} | ||
if (promises.length) { | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_tick).call(this, true); | ||
await Promise.all(promises); | ||
} | ||
}; | ||
return new socket_1.default(socketInitiator, __classPrivateFieldGet(this, _RedisClient_options, "f")?.socket) | ||
.on('data', chunk => __classPrivateFieldGet(this, _RedisClient_queue, "f").onReplyChunk(chunk)) | ||
.on('error', err => { | ||
this.emit('error', err); | ||
if (__classPrivateFieldGet(this, _RedisClient_socket, "f").isOpen && !__classPrivateFieldGet(this, _RedisClient_options, "f")?.disableOfflineQueue) { | ||
__classPrivateFieldGet(this, _RedisClient_queue, "f").flushWaitingForReply(err); | ||
} | ||
else { | ||
__classPrivateFieldGet(this, _RedisClient_queue, "f").flushAll(err); | ||
} | ||
}) | ||
.on('connect', () => { | ||
this.emit('connect'); | ||
}) | ||
.on('ready', () => { | ||
this.emit('ready'); | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_setPingTimer).call(this); | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_tick).call(this); | ||
}) | ||
.on('reconnecting', () => this.emit('reconnecting')) | ||
.on('drain', () => __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_tick).call(this)) | ||
.on('end', () => this.emit('end')); | ||
}, _RedisClient_initiateIsolationPool = function _RedisClient_initiateIsolationPool() { | ||
return (0, generic_pool_1.createPool)({ | ||
create: async () => { | ||
const duplicate = this.duplicate({ | ||
isolationPoolOptions: undefined | ||
}).on('error', err => this.emit('error', err)); | ||
await duplicate.connect(); | ||
return duplicate; | ||
}, | ||
destroy: client => client.disconnect() | ||
}, __classPrivateFieldGet(this, _RedisClient_options, "f")?.isolationPoolOptions); | ||
}, _RedisClient_legacyMode = function _RedisClient_legacyMode() { | ||
var _b, _c; | ||
if (!__classPrivateFieldGet(this, _RedisClient_options, "f")?.legacyMode) | ||
return; | ||
__classPrivateFieldGet(this, _RedisClient_v4, "f").sendCommand = __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_sendCommand).bind(this); | ||
this.sendCommand = (...args) => { | ||
const result = __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_legacySendCommand).call(this, ...args); | ||
if (result) { | ||
result.promise | ||
.then(reply => result.callback(null, reply)) | ||
.catch(err => result.callback(err)); | ||
} | ||
}; | ||
for (const [name, command] of Object.entries(commands_1.default)) { | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_defineLegacyCommand).call(this, name, command); | ||
(_b = this)[_c = name.toLowerCase()] ?? (_b[_c] = this[name]); | ||
} | ||
// hard coded commands | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_defineLegacyCommand).call(this, 'SELECT'); | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_defineLegacyCommand).call(this, 'select'); | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_defineLegacyCommand).call(this, 'SUBSCRIBE'); | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_defineLegacyCommand).call(this, 'subscribe'); | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_defineLegacyCommand).call(this, 'PSUBSCRIBE'); | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_defineLegacyCommand).call(this, 'pSubscribe'); | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_defineLegacyCommand).call(this, 'UNSUBSCRIBE'); | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_defineLegacyCommand).call(this, 'unsubscribe'); | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_defineLegacyCommand).call(this, 'PUNSUBSCRIBE'); | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_defineLegacyCommand).call(this, 'pUnsubscribe'); | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_defineLegacyCommand).call(this, 'QUIT'); | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_defineLegacyCommand).call(this, 'quit'); | ||
}, _RedisClient_legacySendCommand = function _RedisClient_legacySendCommand(...args) { | ||
const callback = typeof args[args.length - 1] === 'function' ? | ||
args.pop() : | ||
undefined; | ||
const promise = __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_sendCommand).call(this, (0, commander_1.transformLegacyCommandArguments)(args)); | ||
if (callback) | ||
return { | ||
promise, | ||
callback | ||
}; | ||
promise.catch(err => this.emit('error', err)); | ||
}, _RedisClient_defineLegacyCommand = function _RedisClient_defineLegacyCommand(name, command) { | ||
__classPrivateFieldGet(this, _RedisClient_v4, "f")[name] = this[name].bind(this); | ||
this[name] = command && command.TRANSFORM_LEGACY_REPLY && command.transformReply ? | ||
(...args) => { | ||
const result = __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_legacySendCommand).call(this, name, ...args); | ||
if (result) { | ||
result.promise | ||
.then(reply => result.callback(null, command.transformReply(reply))) | ||
.catch(err => result.callback(err)); | ||
} | ||
} : | ||
(...args) => this.sendCommand(name, ...args); | ||
}, _RedisClient_setPingTimer = function _RedisClient_setPingTimer() { | ||
if (!__classPrivateFieldGet(this, _RedisClient_options, "f")?.pingInterval || !__classPrivateFieldGet(this, _RedisClient_socket, "f").isReady) | ||
return; | ||
clearTimeout(__classPrivateFieldGet(this, _RedisClient_pingTimer, "f")); | ||
__classPrivateFieldSet(this, _RedisClient_pingTimer, setTimeout(() => { | ||
if (!__classPrivateFieldGet(this, _RedisClient_socket, "f").isReady) | ||
return; | ||
// using #sendCommand to support legacy mode | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_sendCommand).call(this, ['PING']) | ||
.then(reply => this.emit('ping-interval', reply)) | ||
.catch(err => this.emit('error', err)) | ||
.finally(() => __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_setPingTimer).call(this)); | ||
}, __classPrivateFieldGet(this, _RedisClient_options, "f").pingInterval), "f"); | ||
}, _RedisClient_sendCommand = function _RedisClient_sendCommand(args, options) { | ||
if (!__classPrivateFieldGet(this, _RedisClient_socket, "f").isOpen) { | ||
return Promise.reject(new errors_1.ClientClosedError()); | ||
} | ||
else if (options?.isolated) { | ||
return this.executeIsolated(isolatedClient => isolatedClient.sendCommand(args, { | ||
...options, | ||
isolated: false | ||
})); | ||
} | ||
else if (!__classPrivateFieldGet(this, _RedisClient_socket, "f").isReady && __classPrivateFieldGet(this, _RedisClient_options, "f")?.disableOfflineQueue) { | ||
return Promise.reject(new errors_1.ClientOfflineError()); | ||
} | ||
const promise = __classPrivateFieldGet(this, _RedisClient_queue, "f").addCommand(args, options); | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_tick).call(this); | ||
return promise; | ||
}, _RedisClient_pubSubCommand = function _RedisClient_pubSubCommand(promise) { | ||
if (promise === undefined) | ||
return Promise.resolve(); | ||
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_tick).call(this); | ||
return promise; | ||
}, _RedisClient_tick = function _RedisClient_tick(force = false) { | ||
if (__classPrivateFieldGet(this, _RedisClient_socket, "f").writableNeedDrain || (!force && !__classPrivateFieldGet(this, _RedisClient_socket, "f").isReady)) { | ||
return; | ||
} | ||
__classPrivateFieldGet(this, _RedisClient_socket, "f").cork(); | ||
while (!__classPrivateFieldGet(this, _RedisClient_socket, "f").writableNeedDrain) { | ||
const args = __classPrivateFieldGet(this, _RedisClient_queue, "f").getCommandToSend(); | ||
if (args === undefined) | ||
break; | ||
__classPrivateFieldGet(this, _RedisClient_socket, "f").writeCommand(args); | ||
} | ||
}, _RedisClient_addMultiCommands = function _RedisClient_addMultiCommands(commands, chainId) { | ||
return Promise.all(commands.map(({ args }) => __classPrivateFieldGet(this, _RedisClient_queue, "f").addCommand(args, { chainId }))); | ||
}, _RedisClient_destroyIsolationPool = async function _RedisClient_destroyIsolationPool() { | ||
await __classPrivateFieldGet(this, _RedisClient_isolationPool, "f").drain(); | ||
await __classPrivateFieldGet(this, _RedisClient_isolationPool, "f").clear(); | ||
__classPrivateFieldSet(this, _RedisClient_isolationPool, undefined, "f"); | ||
}; | ||
exports.default = RedisClient; | ||
@@ -494,0 +543,0 @@ (0, commander_1.attachCommands)({ |
"use strict"; | ||
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
if (kind === "m") throw new TypeError("Private method is not writable"); | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); | ||
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; | ||
}; | ||
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); | ||
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); | ||
}; | ||
var _RedisClientMultiCommand_instances, _RedisClientMultiCommand_multi, _RedisClientMultiCommand_executor, _RedisClientMultiCommand_selectedDB, _RedisClientMultiCommand_legacyMode, _RedisClientMultiCommand_defineLegacyCommand; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -18,48 +30,30 @@ const commands_1 = require("./commands"); | ||
} | ||
#multi = new multi_command_1.default(); | ||
#executor; | ||
v4 = {}; | ||
#selectedDB; | ||
constructor(executor, legacyMode = false) { | ||
this.#executor = executor; | ||
_RedisClientMultiCommand_instances.add(this); | ||
_RedisClientMultiCommand_multi.set(this, new multi_command_1.default()); | ||
_RedisClientMultiCommand_executor.set(this, void 0); | ||
Object.defineProperty(this, "v4", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: {} | ||
}); | ||
_RedisClientMultiCommand_selectedDB.set(this, void 0); | ||
Object.defineProperty(this, "select", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: this.SELECT | ||
}); | ||
Object.defineProperty(this, "EXEC", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: this.exec | ||
}); | ||
__classPrivateFieldSet(this, _RedisClientMultiCommand_executor, executor, "f"); | ||
if (legacyMode) { | ||
this.#legacyMode(); | ||
__classPrivateFieldGet(this, _RedisClientMultiCommand_instances, "m", _RedisClientMultiCommand_legacyMode).call(this); | ||
} | ||
} | ||
#legacyMode() { | ||
this.v4.addCommand = this.addCommand.bind(this); | ||
this.addCommand = (...args) => { | ||
this.#multi.addCommand((0, commander_1.transformLegacyCommandArguments)(args)); | ||
return this; | ||
}; | ||
this.v4.exec = this.exec.bind(this); | ||
this.exec = (callback) => { | ||
this.v4.exec() | ||
.then((reply) => { | ||
if (!callback) | ||
return; | ||
callback(null, reply); | ||
}) | ||
.catch((err) => { | ||
if (!callback) { | ||
// this.emit('error', err); | ||
return; | ||
} | ||
callback(err); | ||
}); | ||
}; | ||
for (const [name, command] of Object.entries(commands_1.default)) { | ||
this.#defineLegacyCommand(name, command); | ||
this[name.toLowerCase()] ??= this[name]; | ||
} | ||
} | ||
#defineLegacyCommand(name, command) { | ||
this.v4[name] = this[name].bind(this.v4); | ||
this[name] = command && command.TRANSFORM_LEGACY_REPLY && command.transformReply ? | ||
(...args) => { | ||
this.#multi.addCommand([name, ...(0, commander_1.transformLegacyCommandArguments)(args)], command.transformReply); | ||
return this; | ||
} : | ||
(...args) => this.addCommand(name, ...args); | ||
} | ||
commandsExecutor(command, args) { | ||
@@ -69,16 +63,15 @@ return this.addCommand(command.transformArguments(...args), command.transformReply); | ||
SELECT(db, transformReply) { | ||
this.#selectedDB = db; | ||
__classPrivateFieldSet(this, _RedisClientMultiCommand_selectedDB, db, "f"); | ||
return this.addCommand(['SELECT', db.toString()], transformReply); | ||
} | ||
select = this.SELECT; | ||
addCommand(args, transformReply) { | ||
this.#multi.addCommand(args, transformReply); | ||
__classPrivateFieldGet(this, _RedisClientMultiCommand_multi, "f").addCommand(args, transformReply); | ||
return this; | ||
} | ||
functionsExecutor(fn, args, name) { | ||
this.#multi.addFunction(name, fn, args); | ||
__classPrivateFieldGet(this, _RedisClientMultiCommand_multi, "f").addFunction(name, fn, args); | ||
return this; | ||
} | ||
scriptsExecutor(script, args) { | ||
this.#multi.addScript(script, args); | ||
__classPrivateFieldGet(this, _RedisClientMultiCommand_multi, "f").addScript(script, args); | ||
return this; | ||
@@ -90,11 +83,46 @@ } | ||
} | ||
return this.#multi.handleExecReplies(await this.#executor(this.#multi.queue, this.#selectedDB, multi_command_1.default.generateChainId())); | ||
return __classPrivateFieldGet(this, _RedisClientMultiCommand_multi, "f").handleExecReplies(await __classPrivateFieldGet(this, _RedisClientMultiCommand_executor, "f").call(this, __classPrivateFieldGet(this, _RedisClientMultiCommand_multi, "f").queue, __classPrivateFieldGet(this, _RedisClientMultiCommand_selectedDB, "f"), multi_command_1.default.generateChainId())); | ||
} | ||
EXEC = this.exec; | ||
async execAsPipeline() { | ||
if (this.#multi.queue.length === 0) | ||
if (__classPrivateFieldGet(this, _RedisClientMultiCommand_multi, "f").queue.length === 0) | ||
return []; | ||
return this.#multi.transformReplies(await this.#executor(this.#multi.queue, this.#selectedDB)); | ||
return __classPrivateFieldGet(this, _RedisClientMultiCommand_multi, "f").transformReplies(await __classPrivateFieldGet(this, _RedisClientMultiCommand_executor, "f").call(this, __classPrivateFieldGet(this, _RedisClientMultiCommand_multi, "f").queue, __classPrivateFieldGet(this, _RedisClientMultiCommand_selectedDB, "f"))); | ||
} | ||
} | ||
_RedisClientMultiCommand_multi = new WeakMap(), _RedisClientMultiCommand_executor = new WeakMap(), _RedisClientMultiCommand_selectedDB = new WeakMap(), _RedisClientMultiCommand_instances = new WeakSet(), _RedisClientMultiCommand_legacyMode = function _RedisClientMultiCommand_legacyMode() { | ||
var _a, _b; | ||
this.v4.addCommand = this.addCommand.bind(this); | ||
this.addCommand = (...args) => { | ||
__classPrivateFieldGet(this, _RedisClientMultiCommand_multi, "f").addCommand((0, commander_1.transformLegacyCommandArguments)(args)); | ||
return this; | ||
}; | ||
this.v4.exec = this.exec.bind(this); | ||
this.exec = (callback) => { | ||
this.v4.exec() | ||
.then((reply) => { | ||
if (!callback) | ||
return; | ||
callback(null, reply); | ||
}) | ||
.catch((err) => { | ||
if (!callback) { | ||
// this.emit('error', err); | ||
return; | ||
} | ||
callback(err); | ||
}); | ||
}; | ||
for (const [name, command] of Object.entries(commands_1.default)) { | ||
__classPrivateFieldGet(this, _RedisClientMultiCommand_instances, "m", _RedisClientMultiCommand_defineLegacyCommand).call(this, name, command); | ||
(_a = this)[_b = name.toLowerCase()] ?? (_a[_b] = this[name]); | ||
} | ||
}, _RedisClientMultiCommand_defineLegacyCommand = function _RedisClientMultiCommand_defineLegacyCommand(name, command) { | ||
this.v4[name] = this[name].bind(this.v4); | ||
this[name] = command && command.TRANSFORM_LEGACY_REPLY && command.transformReply ? | ||
(...args) => { | ||
__classPrivateFieldGet(this, _RedisClientMultiCommand_multi, "f").addCommand([name, ...(0, commander_1.transformLegacyCommandArguments)(args)], command.transformReply); | ||
return this; | ||
} : | ||
(...args) => this.addCommand(name, ...args); | ||
}; | ||
exports.default = RedisClientMultiCommand; | ||
@@ -101,0 +129,0 @@ (0, commander_1.attachCommands)({ |
"use strict"; | ||
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); | ||
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); | ||
}; | ||
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
if (kind === "m") throw new TypeError("Private method is not writable"); | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); | ||
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; | ||
}; | ||
var _PubSub_instances, _a, _PubSub_channelsArray, _PubSub_listenersSet, _PubSub_subscribing, _PubSub_isActive, _PubSub_listeners, _PubSub_extendChannelListeners, _PubSub_unsubscribeCommand, _PubSub_updateIsActive, _PubSub_emitPubSubMessage; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -28,2 +40,12 @@ exports.PubSub = exports.PubSubType = void 0; | ||
class PubSub { | ||
constructor() { | ||
_PubSub_instances.add(this); | ||
_PubSub_subscribing.set(this, 0); | ||
_PubSub_isActive.set(this, false); | ||
_PubSub_listeners.set(this, { | ||
[PubSubType.CHANNELS]: new Map(), | ||
[PubSubType.PATTERNS]: new Map(), | ||
[PubSubType.SHARDED]: new Map() | ||
}); | ||
} | ||
static isStatusReply(reply) { | ||
@@ -39,22 +61,10 @@ return (COMMANDS[PubSubType.CHANNELS].subscribe.equals(reply[0]) || | ||
} | ||
static #channelsArray(channels) { | ||
return (Array.isArray(channels) ? channels : [channels]); | ||
} | ||
static #listenersSet(listeners, returnBuffers) { | ||
return (returnBuffers ? listeners.buffers : listeners.strings); | ||
} | ||
#subscribing = 0; | ||
#isActive = false; | ||
get isActive() { | ||
return this.#isActive; | ||
return __classPrivateFieldGet(this, _PubSub_isActive, "f"); | ||
} | ||
#listeners = { | ||
[PubSubType.CHANNELS]: new Map(), | ||
[PubSubType.PATTERNS]: new Map(), | ||
[PubSubType.SHARDED]: new Map() | ||
}; | ||
subscribe(type, channels, listener, returnBuffers) { | ||
const args = [COMMANDS[type].subscribe], channelsArray = PubSub.#channelsArray(channels); | ||
var _b; | ||
const args = [COMMANDS[type].subscribe], channelsArray = __classPrivateFieldGet(_a, _a, "m", _PubSub_channelsArray).call(_a, channels); | ||
for (const channel of channelsArray) { | ||
let channelListeners = this.#listeners[type].get(channel); | ||
let channelListeners = __classPrivateFieldGet(this, _PubSub_listeners, "f")[type].get(channel); | ||
if (!channelListeners || channelListeners.unsubscribing) { | ||
@@ -67,8 +77,8 @@ args.push(channel); | ||
for (const channel of channelsArray) { | ||
PubSub.#listenersSet(this.#listeners[type].get(channel), returnBuffers).add(listener); | ||
__classPrivateFieldGet(_a, _a, "m", _PubSub_listenersSet).call(_a, __classPrivateFieldGet(this, _PubSub_listeners, "f")[type].get(channel), returnBuffers).add(listener); | ||
} | ||
return; | ||
} | ||
this.#isActive = true; | ||
this.#subscribing++; | ||
__classPrivateFieldSet(this, _PubSub_isActive, true, "f"); | ||
__classPrivateFieldSet(this, _PubSub_subscribing, (_b = __classPrivateFieldGet(this, _PubSub_subscribing, "f"), _b++, _b), "f"); | ||
return { | ||
@@ -78,5 +88,6 @@ args, | ||
resolve: () => { | ||
this.#subscribing--; | ||
var _b; | ||
__classPrivateFieldSet(this, _PubSub_subscribing, (_b = __classPrivateFieldGet(this, _PubSub_subscribing, "f"), _b--, _b), "f"); | ||
for (const channel of channelsArray) { | ||
let listeners = this.#listeners[type].get(channel); | ||
let listeners = __classPrivateFieldGet(this, _PubSub_listeners, "f")[type].get(channel); | ||
if (!listeners) { | ||
@@ -88,10 +99,11 @@ listeners = { | ||
}; | ||
this.#listeners[type].set(channel, listeners); | ||
__classPrivateFieldGet(this, _PubSub_listeners, "f")[type].set(channel, listeners); | ||
} | ||
PubSub.#listenersSet(listeners, returnBuffers).add(listener); | ||
__classPrivateFieldGet(_a, _a, "m", _PubSub_listenersSet).call(_a, listeners, returnBuffers).add(listener); | ||
} | ||
}, | ||
reject: () => { | ||
this.#subscribing--; | ||
this.#updateIsActive(); | ||
var _b; | ||
__classPrivateFieldSet(this, _PubSub_subscribing, (_b = __classPrivateFieldGet(this, _PubSub_subscribing, "f"), _b--, _b), "f"); | ||
__classPrivateFieldGet(this, _PubSub_instances, "m", _PubSub_updateIsActive).call(this); | ||
} | ||
@@ -101,6 +113,7 @@ }; | ||
extendChannelListeners(type, channel, listeners) { | ||
if (!this.#extendChannelListeners(type, channel, listeners)) | ||
var _b; | ||
if (!__classPrivateFieldGet(this, _PubSub_instances, "m", _PubSub_extendChannelListeners).call(this, type, channel, listeners)) | ||
return; | ||
this.#isActive = true; | ||
this.#subscribing++; | ||
__classPrivateFieldSet(this, _PubSub_isActive, true, "f"); | ||
__classPrivateFieldSet(this, _PubSub_subscribing, (_b = __classPrivateFieldGet(this, _PubSub_subscribing, "f"), _b++, _b), "f"); | ||
return { | ||
@@ -112,27 +125,15 @@ args: [ | ||
channelsCounter: 1, | ||
resolve: () => this.#subscribing--, | ||
resolve: () => { var _b, _c; return __classPrivateFieldSet(this, _PubSub_subscribing, (_c = __classPrivateFieldGet(this, _PubSub_subscribing, "f"), _b = _c--, _c), "f"), _b; }, | ||
reject: () => { | ||
this.#subscribing--; | ||
this.#updateIsActive(); | ||
var _b; | ||
__classPrivateFieldSet(this, _PubSub_subscribing, (_b = __classPrivateFieldGet(this, _PubSub_subscribing, "f"), _b--, _b), "f"); | ||
__classPrivateFieldGet(this, _PubSub_instances, "m", _PubSub_updateIsActive).call(this); | ||
} | ||
}; | ||
} | ||
#extendChannelListeners(type, channel, listeners) { | ||
const existingListeners = this.#listeners[type].get(channel); | ||
if (!existingListeners) { | ||
this.#listeners[type].set(channel, listeners); | ||
return true; | ||
} | ||
for (const listener of listeners.buffers) { | ||
existingListeners.buffers.add(listener); | ||
} | ||
for (const listener of listeners.strings) { | ||
existingListeners.strings.add(listener); | ||
} | ||
return false; | ||
} | ||
extendTypeListeners(type, listeners) { | ||
var _b; | ||
const args = [COMMANDS[type].subscribe]; | ||
for (const [channel, channelListeners] of listeners) { | ||
if (this.#extendChannelListeners(type, channel, channelListeners)) { | ||
if (__classPrivateFieldGet(this, _PubSub_instances, "m", _PubSub_extendChannelListeners).call(this, type, channel, channelListeners)) { | ||
args.push(channel); | ||
@@ -143,11 +144,12 @@ } | ||
return; | ||
this.#isActive = true; | ||
this.#subscribing++; | ||
__classPrivateFieldSet(this, _PubSub_isActive, true, "f"); | ||
__classPrivateFieldSet(this, _PubSub_subscribing, (_b = __classPrivateFieldGet(this, _PubSub_subscribing, "f"), _b++, _b), "f"); | ||
return { | ||
args, | ||
channelsCounter: args.length - 1, | ||
resolve: () => this.#subscribing--, | ||
resolve: () => { var _b, _c; return __classPrivateFieldSet(this, _PubSub_subscribing, (_c = __classPrivateFieldGet(this, _PubSub_subscribing, "f"), _b = _c--, _c), "f"), _b; }, | ||
reject: () => { | ||
this.#subscribing--; | ||
this.#updateIsActive(); | ||
var _b; | ||
__classPrivateFieldSet(this, _PubSub_subscribing, (_b = __classPrivateFieldGet(this, _PubSub_subscribing, "f"), _b--, _b), "f"); | ||
__classPrivateFieldGet(this, _PubSub_instances, "m", _PubSub_updateIsActive).call(this); | ||
} | ||
@@ -157,5 +159,5 @@ }; | ||
unsubscribe(type, channels, listener, returnBuffers) { | ||
const listeners = this.#listeners[type]; | ||
const listeners = __classPrivateFieldGet(this, _PubSub_listeners, "f")[type]; | ||
if (!channels) { | ||
return this.#unsubscribeCommand([COMMANDS[type].unsubscribe], | ||
return __classPrivateFieldGet(this, _PubSub_instances, "m", _PubSub_unsubscribeCommand).call(this, [COMMANDS[type].unsubscribe], | ||
// cannot use `this.#subscribed` because there might be some `SUBSCRIBE` commands in the queue | ||
@@ -165,5 +167,5 @@ // cannot use `this.#subscribed + this.#subscribing` because some `SUBSCRIBE` commands might fail | ||
} | ||
const channelsArray = PubSub.#channelsArray(channels); | ||
const channelsArray = __classPrivateFieldGet(_a, _a, "m", _PubSub_channelsArray).call(_a, channels); | ||
if (!listener) { | ||
return this.#unsubscribeCommand([COMMANDS[type].unsubscribe, ...channelsArray], channelsArray.length, () => { | ||
return __classPrivateFieldGet(this, _PubSub_instances, "m", _PubSub_unsubscribeCommand).call(this, [COMMANDS[type].unsubscribe, ...channelsArray], channelsArray.length, () => { | ||
for (const channel of channelsArray) { | ||
@@ -198,7 +200,7 @@ listeners.delete(channel); | ||
for (const channel of channelsArray) { | ||
PubSub.#listenersSet(listeners.get(channel), returnBuffers).delete(listener); | ||
__classPrivateFieldGet(_a, _a, "m", _PubSub_listenersSet).call(_a, listeners.get(channel), returnBuffers).delete(listener); | ||
} | ||
return; | ||
} | ||
return this.#unsubscribeCommand(args, args.length - 1, () => { | ||
return __classPrivateFieldGet(this, _PubSub_instances, "m", _PubSub_unsubscribeCommand).call(this, args, args.length - 1, () => { | ||
for (const channel of channelsArray) { | ||
@@ -215,31 +217,15 @@ const sets = listeners.get(channel); | ||
} | ||
#unsubscribeCommand(args, channelsCounter, removeListeners) { | ||
return { | ||
args, | ||
channelsCounter, | ||
resolve: () => { | ||
removeListeners(); | ||
this.#updateIsActive(); | ||
}, | ||
reject: undefined // use the same structure as `subscribe` | ||
}; | ||
} | ||
#updateIsActive() { | ||
this.#isActive = (this.#listeners[PubSubType.CHANNELS].size !== 0 || | ||
this.#listeners[PubSubType.PATTERNS].size !== 0 || | ||
this.#listeners[PubSubType.SHARDED].size !== 0 || | ||
this.#subscribing !== 0); | ||
} | ||
reset() { | ||
this.#isActive = false; | ||
this.#subscribing = 0; | ||
__classPrivateFieldSet(this, _PubSub_isActive, false, "f"); | ||
__classPrivateFieldSet(this, _PubSub_subscribing, 0, "f"); | ||
} | ||
resubscribe() { | ||
var _b; | ||
const commands = []; | ||
for (const [type, listeners] of Object.entries(this.#listeners)) { | ||
for (const [type, listeners] of Object.entries(__classPrivateFieldGet(this, _PubSub_listeners, "f"))) { | ||
if (!listeners.size) | ||
continue; | ||
this.#isActive = true; | ||
this.#subscribing++; | ||
const callback = () => this.#subscribing--; | ||
__classPrivateFieldSet(this, _PubSub_isActive, true, "f"); | ||
__classPrivateFieldSet(this, _PubSub_subscribing, (_b = __classPrivateFieldGet(this, _PubSub_subscribing, "f"), _b++, _b), "f"); | ||
const callback = () => { var _b, _c; return __classPrivateFieldSet(this, _PubSub_subscribing, (_c = __classPrivateFieldGet(this, _PubSub_subscribing, "f"), _b = _c--, _c), "f"), _b; }; | ||
commands.push({ | ||
@@ -259,11 +245,11 @@ args: [ | ||
if (COMMANDS[PubSubType.CHANNELS].message.equals(reply[0])) { | ||
this.#emitPubSubMessage(PubSubType.CHANNELS, reply[2], reply[1]); | ||
__classPrivateFieldGet(this, _PubSub_instances, "m", _PubSub_emitPubSubMessage).call(this, PubSubType.CHANNELS, reply[2], reply[1]); | ||
return true; | ||
} | ||
else if (COMMANDS[PubSubType.PATTERNS].message.equals(reply[0])) { | ||
this.#emitPubSubMessage(PubSubType.PATTERNS, reply[3], reply[2], reply[1]); | ||
__classPrivateFieldGet(this, _PubSub_instances, "m", _PubSub_emitPubSubMessage).call(this, PubSubType.PATTERNS, reply[3], reply[2], reply[1]); | ||
return true; | ||
} | ||
else if (COMMANDS[PubSubType.SHARDED].message.equals(reply[0])) { | ||
this.#emitPubSubMessage(PubSubType.SHARDED, reply[2], reply[1]); | ||
__classPrivateFieldGet(this, _PubSub_instances, "m", _PubSub_emitPubSubMessage).call(this, PubSubType.SHARDED, reply[2], reply[1]); | ||
return true; | ||
@@ -274,29 +260,61 @@ } | ||
removeShardedListeners(channel) { | ||
const listeners = this.#listeners[PubSubType.SHARDED].get(channel); | ||
this.#listeners[PubSubType.SHARDED].delete(channel); | ||
this.#updateIsActive(); | ||
const listeners = __classPrivateFieldGet(this, _PubSub_listeners, "f")[PubSubType.SHARDED].get(channel); | ||
__classPrivateFieldGet(this, _PubSub_listeners, "f")[PubSubType.SHARDED].delete(channel); | ||
__classPrivateFieldGet(this, _PubSub_instances, "m", _PubSub_updateIsActive).call(this); | ||
return listeners; | ||
} | ||
#emitPubSubMessage(type, message, channel, pattern) { | ||
const keyString = (pattern ?? channel).toString(), listeners = this.#listeners[type].get(keyString); | ||
if (!listeners) | ||
return; | ||
for (const listener of listeners.buffers) { | ||
listener(message, channel); | ||
} | ||
if (!listeners.strings.size) | ||
return; | ||
const channelString = pattern ? channel.toString() : keyString, messageString = channelString === '__redis__:invalidate' ? | ||
// https://github.com/redis/redis/pull/7469 | ||
// https://github.com/redis/redis/issues/7463 | ||
(message === null ? null : message.map(x => x.toString())) : | ||
message.toString(); | ||
for (const listener of listeners.strings) { | ||
listener(messageString, channelString); | ||
} | ||
} | ||
getTypeListeners(type) { | ||
return this.#listeners[type]; | ||
return __classPrivateFieldGet(this, _PubSub_listeners, "f")[type]; | ||
} | ||
} | ||
exports.PubSub = PubSub; | ||
_a = PubSub, _PubSub_subscribing = new WeakMap(), _PubSub_isActive = new WeakMap(), _PubSub_listeners = new WeakMap(), _PubSub_instances = new WeakSet(), _PubSub_channelsArray = function _PubSub_channelsArray(channels) { | ||
return (Array.isArray(channels) ? channels : [channels]); | ||
}, _PubSub_listenersSet = function _PubSub_listenersSet(listeners, returnBuffers) { | ||
return (returnBuffers ? listeners.buffers : listeners.strings); | ||
}, _PubSub_extendChannelListeners = function _PubSub_extendChannelListeners(type, channel, listeners) { | ||
const existingListeners = __classPrivateFieldGet(this, _PubSub_listeners, "f")[type].get(channel); | ||
if (!existingListeners) { | ||
__classPrivateFieldGet(this, _PubSub_listeners, "f")[type].set(channel, listeners); | ||
return true; | ||
} | ||
for (const listener of listeners.buffers) { | ||
existingListeners.buffers.add(listener); | ||
} | ||
for (const listener of listeners.strings) { | ||
existingListeners.strings.add(listener); | ||
} | ||
return false; | ||
}, _PubSub_unsubscribeCommand = function _PubSub_unsubscribeCommand(args, channelsCounter, removeListeners) { | ||
return { | ||
args, | ||
channelsCounter, | ||
resolve: () => { | ||
removeListeners(); | ||
__classPrivateFieldGet(this, _PubSub_instances, "m", _PubSub_updateIsActive).call(this); | ||
}, | ||
reject: undefined // use the same structure as `subscribe` | ||
}; | ||
}, _PubSub_updateIsActive = function _PubSub_updateIsActive() { | ||
__classPrivateFieldSet(this, _PubSub_isActive, (__classPrivateFieldGet(this, _PubSub_listeners, "f")[PubSubType.CHANNELS].size !== 0 || | ||
__classPrivateFieldGet(this, _PubSub_listeners, "f")[PubSubType.PATTERNS].size !== 0 || | ||
__classPrivateFieldGet(this, _PubSub_listeners, "f")[PubSubType.SHARDED].size !== 0 || | ||
__classPrivateFieldGet(this, _PubSub_subscribing, "f") !== 0), "f"); | ||
}, _PubSub_emitPubSubMessage = function _PubSub_emitPubSubMessage(type, message, channel, pattern) { | ||
const keyString = (pattern ?? channel).toString(), listeners = __classPrivateFieldGet(this, _PubSub_listeners, "f")[type].get(keyString); | ||
if (!listeners) | ||
return; | ||
for (const listener of listeners.buffers) { | ||
listener(message, channel); | ||
} | ||
if (!listeners.strings.size) | ||
return; | ||
const channelString = pattern ? channel.toString() : keyString, messageString = channelString === '__redis__:invalidate' ? | ||
// https://github.com/redis/redis/pull/7469 | ||
// https://github.com/redis/redis/issues/7463 | ||
(message === null ? null : message.map(x => x.toString())) : | ||
message.toString(); | ||
for (const listener of listeners.strings) { | ||
listener(messageString, channelString); | ||
} | ||
}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
class BufferComposer { | ||
chunks = []; | ||
constructor() { | ||
Object.defineProperty(this, "chunks", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: [] | ||
}); | ||
} | ||
write(buffer) { | ||
@@ -6,0 +13,0 @@ this.chunks.push(buffer); |
@@ -5,4 +5,16 @@ "use strict"; | ||
class StringComposer { | ||
decoder = new string_decoder_1.StringDecoder(); | ||
string = ''; | ||
constructor() { | ||
Object.defineProperty(this, "decoder", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: new string_decoder_1.StringDecoder() | ||
}); | ||
Object.defineProperty(this, "string", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: '' | ||
}); | ||
} | ||
write(buffer) { | ||
@@ -9,0 +21,0 @@ this.string += this.decoder.write(buffer); |
@@ -24,11 +24,76 @@ "use strict"; | ||
class RESP2Decoder { | ||
options; | ||
constructor(options) { | ||
this.options = options; | ||
Object.defineProperty(this, "options", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: options | ||
}); | ||
Object.defineProperty(this, "cursor", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: 0 | ||
}); | ||
Object.defineProperty(this, "type", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "bufferComposer", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: new buffer_1.default() | ||
}); | ||
Object.defineProperty(this, "stringComposer", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: new string_1.default() | ||
}); | ||
Object.defineProperty(this, "currentStringComposer", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: this.stringComposer | ||
}); | ||
Object.defineProperty(this, "integer", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: 0 | ||
}); | ||
Object.defineProperty(this, "isNegativeInteger", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "bulkStringRemainingLength", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "arraysInProcess", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: [] | ||
}); | ||
Object.defineProperty(this, "initializeArray", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: false | ||
}); | ||
Object.defineProperty(this, "arrayItemType", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
} | ||
cursor = 0; | ||
type; | ||
bufferComposer = new buffer_1.default(); | ||
stringComposer = new string_1.default(); | ||
currentStringComposer = this.stringComposer; | ||
reset() { | ||
@@ -94,4 +159,2 @@ this.cursor = 0; | ||
} | ||
integer = 0; | ||
isNegativeInteger; | ||
parseInteger(chunk) { | ||
@@ -115,3 +178,2 @@ if (this.isNegativeInteger === undefined) { | ||
} | ||
bulkStringRemainingLength; | ||
parseBulkString(chunk) { | ||
@@ -140,5 +202,2 @@ if (this.bulkStringRemainingLength === undefined) { | ||
} | ||
arraysInProcess = []; | ||
initializeArray = false; | ||
arrayItemType; | ||
parseArray(chunk, arraysToKeep = 0) { | ||
@@ -145,0 +204,0 @@ if (this.initializeArray || this.arraysInProcess.length === arraysToKeep) { |
"use strict"; | ||
var _a; | ||
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); | ||
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); | ||
}; | ||
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
if (kind === "m") throw new TypeError("Private method is not writable"); | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); | ||
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; | ||
}; | ||
var _RedisSocket_instances, _a, _RedisSocket_initiateOptions, _RedisSocket_isTlsSocket, _RedisSocket_initiator, _RedisSocket_options, _RedisSocket_socket, _RedisSocket_isOpen, _RedisSocket_isReady, _RedisSocket_writableNeedDrain, _RedisSocket_isSocketUnrefed, _RedisSocket_reconnectStrategy, _RedisSocket_shouldReconnect, _RedisSocket_connect, _RedisSocket_createSocket, _RedisSocket_createNetSocket, _RedisSocket_createTlsSocket, _RedisSocket_onSocketError, _RedisSocket_disconnect, _RedisSocket_isCorked; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -10,221 +21,213 @@ const events_1 = require("events"); | ||
class RedisSocket extends events_1.EventEmitter { | ||
static #initiateOptions(options) { | ||
options ??= {}; | ||
if (!options.path) { | ||
options.port ??= 6379; | ||
options.host ??= 'localhost'; | ||
} | ||
options.connectTimeout ??= 5000; | ||
options.keepAlive ??= 5000; | ||
options.noDelay ??= true; | ||
return options; | ||
} | ||
static #isTlsSocket(options) { | ||
return options.tls === true; | ||
} | ||
#initiator; | ||
#options; | ||
#socket; | ||
#isOpen = false; | ||
get isOpen() { | ||
return this.#isOpen; | ||
return __classPrivateFieldGet(this, _RedisSocket_isOpen, "f"); | ||
} | ||
#isReady = false; | ||
get isReady() { | ||
return this.#isReady; | ||
return __classPrivateFieldGet(this, _RedisSocket_isReady, "f"); | ||
} | ||
// `writable.writableNeedDrain` was added in v15.2.0 and therefore can't be used | ||
// https://nodejs.org/api/stream.html#stream_writable_writableneeddrain | ||
#writableNeedDrain = false; | ||
get writableNeedDrain() { | ||
return this.#writableNeedDrain; | ||
return __classPrivateFieldGet(this, _RedisSocket_writableNeedDrain, "f"); | ||
} | ||
#isSocketUnrefed = false; | ||
constructor(initiator, options) { | ||
super(); | ||
this.#initiator = initiator; | ||
this.#options = _a.#initiateOptions(options); | ||
_RedisSocket_instances.add(this); | ||
_RedisSocket_initiator.set(this, void 0); | ||
_RedisSocket_options.set(this, void 0); | ||
_RedisSocket_socket.set(this, void 0); | ||
_RedisSocket_isOpen.set(this, false); | ||
_RedisSocket_isReady.set(this, false); | ||
// `writable.writableNeedDrain` was added in v15.2.0 and therefore can't be used | ||
// https://nodejs.org/api/stream.html#stream_writable_writableneeddrain | ||
_RedisSocket_writableNeedDrain.set(this, false); | ||
_RedisSocket_isSocketUnrefed.set(this, false); | ||
_RedisSocket_isCorked.set(this, false); | ||
__classPrivateFieldSet(this, _RedisSocket_initiator, initiator, "f"); | ||
__classPrivateFieldSet(this, _RedisSocket_options, __classPrivateFieldGet(_a, _a, "m", _RedisSocket_initiateOptions).call(_a, options), "f"); | ||
} | ||
#reconnectStrategy(retries, cause) { | ||
if (this.#options.reconnectStrategy === false) { | ||
return false; | ||
} | ||
else if (typeof this.#options.reconnectStrategy === 'number') { | ||
return this.#options.reconnectStrategy; | ||
} | ||
else if (this.#options.reconnectStrategy) { | ||
try { | ||
const retryIn = this.#options.reconnectStrategy(retries, cause); | ||
if (retryIn !== false && !(retryIn instanceof Error) && typeof retryIn !== 'number') { | ||
throw new TypeError(`Reconnect strategy should return \`false | Error | number\`, got ${retryIn} instead`); | ||
} | ||
return retryIn; | ||
} | ||
catch (err) { | ||
this.emit('error', err); | ||
} | ||
} | ||
return Math.min(retries * 50, 500); | ||
} | ||
#shouldReconnect(retries, cause) { | ||
const retryIn = this.#reconnectStrategy(retries, cause); | ||
if (retryIn === false) { | ||
this.#isOpen = false; | ||
this.emit('error', cause); | ||
return cause; | ||
} | ||
else if (retryIn instanceof Error) { | ||
this.#isOpen = false; | ||
this.emit('error', cause); | ||
return new errors_1.ReconnectStrategyError(retryIn, cause); | ||
} | ||
return retryIn; | ||
} | ||
async connect() { | ||
if (this.#isOpen) { | ||
if (__classPrivateFieldGet(this, _RedisSocket_isOpen, "f")) { | ||
throw new Error('Socket already opened'); | ||
} | ||
this.#isOpen = true; | ||
return this.#connect(); | ||
__classPrivateFieldSet(this, _RedisSocket_isOpen, true, "f"); | ||
return __classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_connect).call(this); | ||
} | ||
async #connect() { | ||
let retries = 0; | ||
do { | ||
try { | ||
this.#socket = await this.#createSocket(); | ||
this.#writableNeedDrain = false; | ||
this.emit('connect'); | ||
try { | ||
await this.#initiator(); | ||
} | ||
catch (err) { | ||
this.#socket.destroy(); | ||
this.#socket = undefined; | ||
throw err; | ||
} | ||
this.#isReady = true; | ||
this.emit('ready'); | ||
} | ||
catch (err) { | ||
const retryIn = this.#shouldReconnect(retries++, err); | ||
if (typeof retryIn !== 'number') { | ||
throw retryIn; | ||
} | ||
this.emit('error', err); | ||
await (0, utils_1.promiseTimeout)(retryIn); | ||
this.emit('reconnecting'); | ||
} | ||
} while (this.#isOpen && !this.#isReady); | ||
} | ||
#createSocket() { | ||
return new Promise((resolve, reject) => { | ||
const { connectEvent, socket } = _a.#isTlsSocket(this.#options) ? | ||
this.#createTlsSocket() : | ||
this.#createNetSocket(); | ||
if (this.#options.connectTimeout) { | ||
socket.setTimeout(this.#options.connectTimeout, () => socket.destroy(new errors_1.ConnectionTimeoutError())); | ||
} | ||
if (this.#isSocketUnrefed) { | ||
socket.unref(); | ||
} | ||
socket | ||
.setNoDelay(this.#options.noDelay) | ||
.once('error', reject) | ||
.once(connectEvent, () => { | ||
socket | ||
.setTimeout(0) | ||
// https://github.com/nodejs/node/issues/31663 | ||
.setKeepAlive(this.#options.keepAlive !== false, this.#options.keepAlive || 0) | ||
.off('error', reject) | ||
.once('error', (err) => this.#onSocketError(err)) | ||
.once('close', hadError => { | ||
if (!hadError && this.#isReady && this.#socket === socket) { | ||
this.#onSocketError(new errors_1.SocketClosedUnexpectedlyError()); | ||
} | ||
}) | ||
.on('drain', () => { | ||
this.#writableNeedDrain = false; | ||
this.emit('drain'); | ||
}) | ||
.on('data', data => this.emit('data', data)); | ||
resolve(socket); | ||
}); | ||
}); | ||
} | ||
#createNetSocket() { | ||
return { | ||
connectEvent: 'connect', | ||
socket: net.connect(this.#options) // TODO | ||
}; | ||
} | ||
#createTlsSocket() { | ||
return { | ||
connectEvent: 'secureConnect', | ||
socket: tls.connect(this.#options) // TODO | ||
}; | ||
} | ||
#onSocketError(err) { | ||
this.#isReady = false; | ||
this.emit('error', err); | ||
if (!this.#isOpen || typeof this.#shouldReconnect(0, err) !== 'number') | ||
return; | ||
this.emit('reconnecting'); | ||
this.#connect().catch(() => { | ||
// the error was already emitted, silently ignore it | ||
}); | ||
} | ||
writeCommand(args) { | ||
if (!this.#socket) { | ||
if (!__classPrivateFieldGet(this, _RedisSocket_socket, "f")) { | ||
throw new errors_1.ClientClosedError(); | ||
} | ||
for (const toWrite of args) { | ||
this.#writableNeedDrain = !this.#socket.write(toWrite); | ||
__classPrivateFieldSet(this, _RedisSocket_writableNeedDrain, !__classPrivateFieldGet(this, _RedisSocket_socket, "f").write(toWrite), "f"); | ||
} | ||
} | ||
disconnect() { | ||
if (!this.#isOpen) { | ||
if (!__classPrivateFieldGet(this, _RedisSocket_isOpen, "f")) { | ||
throw new errors_1.ClientClosedError(); | ||
} | ||
this.#isOpen = false; | ||
this.#disconnect(); | ||
__classPrivateFieldSet(this, _RedisSocket_isOpen, false, "f"); | ||
__classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_disconnect).call(this); | ||
} | ||
#disconnect() { | ||
this.#isReady = false; | ||
if (this.#socket) { | ||
this.#socket.destroy(); | ||
this.#socket = undefined; | ||
} | ||
this.emit('end'); | ||
} | ||
async quit(fn) { | ||
if (!this.#isOpen) { | ||
if (!__classPrivateFieldGet(this, _RedisSocket_isOpen, "f")) { | ||
throw new errors_1.ClientClosedError(); | ||
} | ||
this.#isOpen = false; | ||
__classPrivateFieldSet(this, _RedisSocket_isOpen, false, "f"); | ||
const reply = await fn(); | ||
this.#disconnect(); | ||
__classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_disconnect).call(this); | ||
return reply; | ||
} | ||
#isCorked = false; | ||
cork() { | ||
if (!this.#socket || this.#isCorked) { | ||
if (!__classPrivateFieldGet(this, _RedisSocket_socket, "f") || __classPrivateFieldGet(this, _RedisSocket_isCorked, "f")) { | ||
return; | ||
} | ||
this.#socket.cork(); | ||
this.#isCorked = true; | ||
__classPrivateFieldGet(this, _RedisSocket_socket, "f").cork(); | ||
__classPrivateFieldSet(this, _RedisSocket_isCorked, true, "f"); | ||
setImmediate(() => { | ||
this.#socket?.uncork(); | ||
this.#isCorked = false; | ||
__classPrivateFieldGet(this, _RedisSocket_socket, "f")?.uncork(); | ||
__classPrivateFieldSet(this, _RedisSocket_isCorked, false, "f"); | ||
}); | ||
} | ||
ref() { | ||
this.#isSocketUnrefed = false; | ||
this.#socket?.ref(); | ||
__classPrivateFieldSet(this, _RedisSocket_isSocketUnrefed, false, "f"); | ||
__classPrivateFieldGet(this, _RedisSocket_socket, "f")?.ref(); | ||
} | ||
unref() { | ||
this.#isSocketUnrefed = true; | ||
this.#socket?.unref(); | ||
__classPrivateFieldSet(this, _RedisSocket_isSocketUnrefed, true, "f"); | ||
__classPrivateFieldGet(this, _RedisSocket_socket, "f")?.unref(); | ||
} | ||
} | ||
_a = RedisSocket; | ||
_a = RedisSocket, _RedisSocket_initiator = new WeakMap(), _RedisSocket_options = new WeakMap(), _RedisSocket_socket = new WeakMap(), _RedisSocket_isOpen = new WeakMap(), _RedisSocket_isReady = new WeakMap(), _RedisSocket_writableNeedDrain = new WeakMap(), _RedisSocket_isSocketUnrefed = new WeakMap(), _RedisSocket_isCorked = new WeakMap(), _RedisSocket_instances = new WeakSet(), _RedisSocket_initiateOptions = function _RedisSocket_initiateOptions(options) { | ||
var _b, _c; | ||
options ?? (options = {}); | ||
if (!options.path) { | ||
(_b = options).port ?? (_b.port = 6379); | ||
(_c = options).host ?? (_c.host = 'localhost'); | ||
} | ||
options.connectTimeout ?? (options.connectTimeout = 5000); | ||
options.keepAlive ?? (options.keepAlive = 5000); | ||
options.noDelay ?? (options.noDelay = true); | ||
return options; | ||
}, _RedisSocket_isTlsSocket = function _RedisSocket_isTlsSocket(options) { | ||
return options.tls === true; | ||
}, _RedisSocket_reconnectStrategy = function _RedisSocket_reconnectStrategy(retries, cause) { | ||
if (__classPrivateFieldGet(this, _RedisSocket_options, "f").reconnectStrategy === false) { | ||
return false; | ||
} | ||
else if (typeof __classPrivateFieldGet(this, _RedisSocket_options, "f").reconnectStrategy === 'number') { | ||
return __classPrivateFieldGet(this, _RedisSocket_options, "f").reconnectStrategy; | ||
} | ||
else if (__classPrivateFieldGet(this, _RedisSocket_options, "f").reconnectStrategy) { | ||
try { | ||
const retryIn = __classPrivateFieldGet(this, _RedisSocket_options, "f").reconnectStrategy(retries, cause); | ||
if (retryIn !== false && !(retryIn instanceof Error) && typeof retryIn !== 'number') { | ||
throw new TypeError(`Reconnect strategy should return \`false | Error | number\`, got ${retryIn} instead`); | ||
} | ||
return retryIn; | ||
} | ||
catch (err) { | ||
this.emit('error', err); | ||
} | ||
} | ||
return Math.min(retries * 50, 500); | ||
}, _RedisSocket_shouldReconnect = function _RedisSocket_shouldReconnect(retries, cause) { | ||
const retryIn = __classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_reconnectStrategy).call(this, retries, cause); | ||
if (retryIn === false) { | ||
__classPrivateFieldSet(this, _RedisSocket_isOpen, false, "f"); | ||
this.emit('error', cause); | ||
return cause; | ||
} | ||
else if (retryIn instanceof Error) { | ||
__classPrivateFieldSet(this, _RedisSocket_isOpen, false, "f"); | ||
this.emit('error', cause); | ||
return new errors_1.ReconnectStrategyError(retryIn, cause); | ||
} | ||
return retryIn; | ||
}, _RedisSocket_connect = async function _RedisSocket_connect() { | ||
let retries = 0; | ||
do { | ||
try { | ||
__classPrivateFieldSet(this, _RedisSocket_socket, await __classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_createSocket).call(this), "f"); | ||
__classPrivateFieldSet(this, _RedisSocket_writableNeedDrain, false, "f"); | ||
this.emit('connect'); | ||
try { | ||
await __classPrivateFieldGet(this, _RedisSocket_initiator, "f").call(this); | ||
} | ||
catch (err) { | ||
__classPrivateFieldGet(this, _RedisSocket_socket, "f").destroy(); | ||
__classPrivateFieldSet(this, _RedisSocket_socket, undefined, "f"); | ||
throw err; | ||
} | ||
__classPrivateFieldSet(this, _RedisSocket_isReady, true, "f"); | ||
this.emit('ready'); | ||
} | ||
catch (err) { | ||
const retryIn = __classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_shouldReconnect).call(this, retries++, err); | ||
if (typeof retryIn !== 'number') { | ||
throw retryIn; | ||
} | ||
this.emit('error', err); | ||
await (0, utils_1.promiseTimeout)(retryIn); | ||
this.emit('reconnecting'); | ||
} | ||
} while (__classPrivateFieldGet(this, _RedisSocket_isOpen, "f") && !__classPrivateFieldGet(this, _RedisSocket_isReady, "f")); | ||
}, _RedisSocket_createSocket = function _RedisSocket_createSocket() { | ||
return new Promise((resolve, reject) => { | ||
const { connectEvent, socket } = __classPrivateFieldGet(_a, _a, "m", _RedisSocket_isTlsSocket).call(_a, __classPrivateFieldGet(this, _RedisSocket_options, "f")) ? | ||
__classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_createTlsSocket).call(this) : | ||
__classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_createNetSocket).call(this); | ||
if (__classPrivateFieldGet(this, _RedisSocket_options, "f").connectTimeout) { | ||
socket.setTimeout(__classPrivateFieldGet(this, _RedisSocket_options, "f").connectTimeout, () => socket.destroy(new errors_1.ConnectionTimeoutError())); | ||
} | ||
if (__classPrivateFieldGet(this, _RedisSocket_isSocketUnrefed, "f")) { | ||
socket.unref(); | ||
} | ||
socket | ||
.setNoDelay(__classPrivateFieldGet(this, _RedisSocket_options, "f").noDelay) | ||
.once('error', reject) | ||
.once(connectEvent, () => { | ||
socket | ||
.setTimeout(0) | ||
// https://github.com/nodejs/node/issues/31663 | ||
.setKeepAlive(__classPrivateFieldGet(this, _RedisSocket_options, "f").keepAlive !== false, __classPrivateFieldGet(this, _RedisSocket_options, "f").keepAlive || 0) | ||
.off('error', reject) | ||
.once('error', (err) => __classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_onSocketError).call(this, err)) | ||
.once('close', hadError => { | ||
if (!hadError && __classPrivateFieldGet(this, _RedisSocket_isReady, "f") && __classPrivateFieldGet(this, _RedisSocket_socket, "f") === socket) { | ||
__classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_onSocketError).call(this, new errors_1.SocketClosedUnexpectedlyError()); | ||
} | ||
}) | ||
.on('drain', () => { | ||
__classPrivateFieldSet(this, _RedisSocket_writableNeedDrain, false, "f"); | ||
this.emit('drain'); | ||
}) | ||
.on('data', data => this.emit('data', data)); | ||
resolve(socket); | ||
}); | ||
}); | ||
}, _RedisSocket_createNetSocket = function _RedisSocket_createNetSocket() { | ||
return { | ||
connectEvent: 'connect', | ||
socket: net.connect(__classPrivateFieldGet(this, _RedisSocket_options, "f")) // TODO | ||
}; | ||
}, _RedisSocket_createTlsSocket = function _RedisSocket_createTlsSocket() { | ||
return { | ||
connectEvent: 'secureConnect', | ||
socket: tls.connect(__classPrivateFieldGet(this, _RedisSocket_options, "f")) // TODO | ||
}; | ||
}, _RedisSocket_onSocketError = function _RedisSocket_onSocketError(err) { | ||
__classPrivateFieldSet(this, _RedisSocket_isReady, false, "f"); | ||
this.emit('error', err); | ||
if (!__classPrivateFieldGet(this, _RedisSocket_isOpen, "f") || typeof __classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_shouldReconnect).call(this, 0, err) !== 'number') | ||
return; | ||
this.emit('reconnecting'); | ||
__classPrivateFieldGet(this, _RedisSocket_instances, "m", _RedisSocket_connect).call(this).catch(() => { | ||
// the error was already emitted, silently ignore it | ||
}); | ||
}, _RedisSocket_disconnect = function _RedisSocket_disconnect() { | ||
__classPrivateFieldSet(this, _RedisSocket_isReady, false, "f"); | ||
if (__classPrivateFieldGet(this, _RedisSocket_socket, "f")) { | ||
__classPrivateFieldGet(this, _RedisSocket_socket, "f").destroy(); | ||
__classPrivateFieldSet(this, _RedisSocket_socket, undefined, "f"); | ||
} | ||
this.emit('end'); | ||
}; | ||
exports.default = RedisSocket; |
"use strict"; | ||
var _a; | ||
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); | ||
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); | ||
}; | ||
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
if (kind === "m") throw new TypeError("Private method is not writable"); | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); | ||
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; | ||
}; | ||
var _RedisClusterSlots_instances, _a, _RedisClusterSlots_SLOTS, _RedisClusterSlots_options, _RedisClusterSlots_Client, _RedisClusterSlots_emit, _RedisClusterSlots_isOpen, _RedisClusterSlots_discoverWithRootNodes, _RedisClusterSlots_resetSlots, _RedisClusterSlots_discover, _RedisClusterSlots_getShards, _RedisClusterSlots_getNodeAddress, _RedisClusterSlots_clientOptionsDefaults, _RedisClusterSlots_initiateSlotNode, _RedisClusterSlots_createClient, _RedisClusterSlots_createNodeClient, _RedisClusterSlots_runningRediscoverPromise, _RedisClusterSlots_rediscover, _RedisClusterSlots_destroy, _RedisClusterSlots_execOnNodeClient, _RedisClusterSlots_iterateAllNodes, _RedisClusterSlots_randomNodeIterator, _RedisClusterSlots_slotNodesIterator, _RedisClusterSlots_initiatePubSubClient, _RedisClusterSlots_initiateShardedPubSubClient; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -13,252 +24,80 @@ const client_1 = require("../client"); | ||
class RedisClusterSlots { | ||
static #SLOTS = 16384; | ||
#options; | ||
#Client; | ||
#emit; | ||
slots = new Array(_a.#SLOTS); | ||
shards = new Array(); | ||
masters = new Array(); | ||
replicas = new Array(); | ||
nodeByAddress = new Map(); | ||
pubSubNode; | ||
#isOpen = false; | ||
get isOpen() { | ||
return this.#isOpen; | ||
return __classPrivateFieldGet(this, _RedisClusterSlots_isOpen, "f"); | ||
} | ||
constructor(options, emit) { | ||
this.#options = options; | ||
this.#Client = client_1.default.extend(options); | ||
this.#emit = emit; | ||
_RedisClusterSlots_instances.add(this); | ||
_RedisClusterSlots_options.set(this, void 0); | ||
_RedisClusterSlots_Client.set(this, void 0); | ||
_RedisClusterSlots_emit.set(this, void 0); | ||
Object.defineProperty(this, "slots", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: new Array(__classPrivateFieldGet(_a, _a, "f", _RedisClusterSlots_SLOTS)) | ||
}); | ||
Object.defineProperty(this, "shards", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: new Array() | ||
}); | ||
Object.defineProperty(this, "masters", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: new Array() | ||
}); | ||
Object.defineProperty(this, "replicas", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: new Array() | ||
}); | ||
Object.defineProperty(this, "nodeByAddress", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: new Map() | ||
}); | ||
Object.defineProperty(this, "pubSubNode", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
_RedisClusterSlots_isOpen.set(this, false); | ||
_RedisClusterSlots_runningRediscoverPromise.set(this, void 0); | ||
_RedisClusterSlots_randomNodeIterator.set(this, void 0); | ||
__classPrivateFieldSet(this, _RedisClusterSlots_options, options, "f"); | ||
__classPrivateFieldSet(this, _RedisClusterSlots_Client, client_1.default.extend(options), "f"); | ||
__classPrivateFieldSet(this, _RedisClusterSlots_emit, emit, "f"); | ||
} | ||
async connect() { | ||
if (this.#isOpen) { | ||
if (__classPrivateFieldGet(this, _RedisClusterSlots_isOpen, "f")) { | ||
throw new Error('Cluster already open'); | ||
} | ||
this.#isOpen = true; | ||
__classPrivateFieldSet(this, _RedisClusterSlots_isOpen, true, "f"); | ||
try { | ||
await this.#discoverWithRootNodes(); | ||
await __classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_discoverWithRootNodes).call(this); | ||
} | ||
catch (err) { | ||
this.#isOpen = false; | ||
__classPrivateFieldSet(this, _RedisClusterSlots_isOpen, false, "f"); | ||
throw err; | ||
} | ||
} | ||
async #discoverWithRootNodes() { | ||
let start = Math.floor(Math.random() * this.#options.rootNodes.length); | ||
for (let i = start; i < this.#options.rootNodes.length; i++) { | ||
if (await this.#discover(this.#options.rootNodes[i])) | ||
return; | ||
} | ||
for (let i = 0; i < start; i++) { | ||
if (await this.#discover(this.#options.rootNodes[i])) | ||
return; | ||
} | ||
throw new errors_1.RootNodesUnavailableError(); | ||
} | ||
#resetSlots() { | ||
this.slots = new Array(_a.#SLOTS); | ||
this.shards = []; | ||
this.masters = []; | ||
this.replicas = []; | ||
this.#randomNodeIterator = undefined; | ||
} | ||
async #discover(rootNode) { | ||
this.#resetSlots(); | ||
const addressesInUse = new Set(); | ||
try { | ||
const shards = await this.#getShards(rootNode), promises = [], eagerConnect = this.#options.minimizeConnections !== true; | ||
for (const { from, to, master, replicas } of shards) { | ||
const shard = { | ||
master: this.#initiateSlotNode(master, false, eagerConnect, addressesInUse, promises) | ||
}; | ||
if (this.#options.useReplicas) { | ||
shard.replicas = replicas.map(replica => this.#initiateSlotNode(replica, true, eagerConnect, addressesInUse, promises)); | ||
} | ||
this.shards.push(shard); | ||
for (let i = from; i <= to; i++) { | ||
this.slots[i] = shard; | ||
} | ||
} | ||
if (this.pubSubNode && !addressesInUse.has(this.pubSubNode.address)) { | ||
if (util_1.types.isPromise(this.pubSubNode.client)) { | ||
promises.push(this.pubSubNode.client.then(client => client.disconnect())); | ||
this.pubSubNode = undefined; | ||
} | ||
else { | ||
promises.push(this.pubSubNode.client.disconnect()); | ||
const channelsListeners = this.pubSubNode.client.getPubSubListeners(pub_sub_1.PubSubType.CHANNELS), patternsListeners = this.pubSubNode.client.getPubSubListeners(pub_sub_1.PubSubType.PATTERNS); | ||
if (channelsListeners.size || patternsListeners.size) { | ||
promises.push(this.#initiatePubSubClient({ | ||
[pub_sub_1.PubSubType.CHANNELS]: channelsListeners, | ||
[pub_sub_1.PubSubType.PATTERNS]: patternsListeners | ||
})); | ||
} | ||
} | ||
} | ||
for (const [address, node] of this.nodeByAddress.entries()) { | ||
if (addressesInUse.has(address)) | ||
continue; | ||
if (node.client) { | ||
promises.push(this.#execOnNodeClient(node.client, client => client.disconnect())); | ||
} | ||
const { pubSubClient } = node; | ||
if (pubSubClient) { | ||
promises.push(this.#execOnNodeClient(pubSubClient, client => client.disconnect())); | ||
} | ||
this.nodeByAddress.delete(address); | ||
} | ||
await Promise.all(promises); | ||
return true; | ||
} | ||
catch (err) { | ||
this.#emit('error', err); | ||
return false; | ||
} | ||
} | ||
async #getShards(rootNode) { | ||
const client = new this.#Client(this.#clientOptionsDefaults(rootNode, true)); | ||
client.on('error', err => this.#emit('error', err)); | ||
await client.connect(); | ||
try { | ||
// using `CLUSTER SLOTS` and not `CLUSTER SHARDS` to support older versions | ||
return await client.clusterSlots(); | ||
} | ||
finally { | ||
await client.disconnect(); | ||
} | ||
} | ||
#getNodeAddress(address) { | ||
switch (typeof this.#options.nodeAddressMap) { | ||
case 'object': | ||
return this.#options.nodeAddressMap[address]; | ||
case 'function': | ||
return this.#options.nodeAddressMap(address); | ||
} | ||
} | ||
#clientOptionsDefaults(options, disableReconnect) { | ||
let result; | ||
if (this.#options.defaults) { | ||
let socket; | ||
if (this.#options.defaults.socket) { | ||
socket = options?.socket ? { | ||
...this.#options.defaults.socket, | ||
...options.socket | ||
} : this.#options.defaults.socket; | ||
} | ||
else { | ||
socket = options?.socket; | ||
} | ||
result = { | ||
...this.#options.defaults, | ||
...options, | ||
socket | ||
}; | ||
} | ||
else { | ||
result = options; | ||
} | ||
if (disableReconnect) { | ||
result ??= {}; | ||
result.socket ??= {}; | ||
result.socket.reconnectStrategy = false; | ||
} | ||
return result; | ||
} | ||
#initiateSlotNode({ id, ip, port }, readonly, eagerConnent, addressesInUse, promises) { | ||
const address = `${ip}:${port}`; | ||
addressesInUse.add(address); | ||
let node = this.nodeByAddress.get(address); | ||
if (!node) { | ||
node = { | ||
id, | ||
host: ip, | ||
port, | ||
address, | ||
readonly, | ||
client: undefined | ||
}; | ||
if (eagerConnent) { | ||
promises.push(this.#createNodeClient(node)); | ||
} | ||
this.nodeByAddress.set(address, node); | ||
} | ||
(readonly ? this.replicas : this.masters).push(node); | ||
return node; | ||
} | ||
async #createClient(node, readonly = node.readonly) { | ||
const client = new this.#Client(this.#clientOptionsDefaults({ | ||
socket: this.#getNodeAddress(node.address) ?? { | ||
host: node.host, | ||
port: node.port | ||
}, | ||
readonly | ||
})); | ||
client.on('error', err => this.#emit('error', err)); | ||
await client.connect(); | ||
return client; | ||
} | ||
#createNodeClient(node) { | ||
const promise = this.#createClient(node) | ||
.then(client => { | ||
node.client = client; | ||
return client; | ||
}) | ||
.catch(err => { | ||
node.client = undefined; | ||
throw err; | ||
}); | ||
node.client = promise; | ||
return promise; | ||
} | ||
nodeClient(node) { | ||
return node.client ?? this.#createNodeClient(node); | ||
return node.client ?? __classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_createNodeClient).call(this, node); | ||
} | ||
#runningRediscoverPromise; | ||
async rediscover(startWith) { | ||
this.#runningRediscoverPromise ??= this.#rediscover(startWith) | ||
.finally(() => this.#runningRediscoverPromise = undefined); | ||
return this.#runningRediscoverPromise; | ||
__classPrivateFieldSet(this, _RedisClusterSlots_runningRediscoverPromise, __classPrivateFieldGet(this, _RedisClusterSlots_runningRediscoverPromise, "f") ?? __classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_rediscover).call(this, startWith) | ||
.finally(() => __classPrivateFieldSet(this, _RedisClusterSlots_runningRediscoverPromise, undefined, "f")), "f"); | ||
return __classPrivateFieldGet(this, _RedisClusterSlots_runningRediscoverPromise, "f"); | ||
} | ||
async #rediscover(startWith) { | ||
if (await this.#discover(startWith.options)) | ||
return; | ||
return this.#discoverWithRootNodes(); | ||
} | ||
quit() { | ||
return this.#destroy(client => client.quit()); | ||
return __classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_destroy).call(this, client => client.quit()); | ||
} | ||
disconnect() { | ||
return this.#destroy(client => client.disconnect()); | ||
return __classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_destroy).call(this, client => client.disconnect()); | ||
} | ||
async #destroy(fn) { | ||
this.#isOpen = false; | ||
const promises = []; | ||
for (const { master, replicas } of this.shards) { | ||
if (master.client) { | ||
promises.push(this.#execOnNodeClient(master.client, fn)); | ||
} | ||
if (master.pubSubClient) { | ||
promises.push(this.#execOnNodeClient(master.pubSubClient, fn)); | ||
} | ||
if (replicas) { | ||
for (const { client } of replicas) { | ||
if (client) { | ||
promises.push(this.#execOnNodeClient(client, fn)); | ||
} | ||
} | ||
} | ||
} | ||
if (this.pubSubNode) { | ||
promises.push(this.#execOnNodeClient(this.pubSubNode.client, fn)); | ||
this.pubSubNode = undefined; | ||
} | ||
this.#resetSlots(); | ||
this.nodeByAddress.clear(); | ||
await Promise.allSettled(promises); | ||
} | ||
#execOnNodeClient(client, fn) { | ||
return util_1.types.isPromise(client) ? | ||
client.then(fn) : | ||
fn(client); | ||
} | ||
getClient(firstKey, isReadonly) { | ||
@@ -274,46 +113,6 @@ if (!firstKey) { | ||
} | ||
*#iterateAllNodes() { | ||
let i = Math.floor(Math.random() * (this.masters.length + this.replicas.length)); | ||
if (i < this.masters.length) { | ||
do { | ||
yield this.masters[i]; | ||
} while (++i < this.masters.length); | ||
for (const replica of this.replicas) { | ||
yield replica; | ||
} | ||
} | ||
else { | ||
i -= this.masters.length; | ||
do { | ||
yield this.replicas[i]; | ||
} while (++i < this.replicas.length); | ||
} | ||
while (true) { | ||
for (const master of this.masters) { | ||
yield master; | ||
} | ||
for (const replica of this.replicas) { | ||
yield replica; | ||
} | ||
} | ||
} | ||
#randomNodeIterator; | ||
getRandomNode() { | ||
this.#randomNodeIterator ??= this.#iterateAllNodes(); | ||
return this.#randomNodeIterator.next().value; | ||
__classPrivateFieldSet(this, _RedisClusterSlots_randomNodeIterator, __classPrivateFieldGet(this, _RedisClusterSlots_randomNodeIterator, "f") ?? __classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_iterateAllNodes).call(this), "f"); | ||
return __classPrivateFieldGet(this, _RedisClusterSlots_randomNodeIterator, "f").next().value; | ||
} | ||
*#slotNodesIterator(slot) { | ||
let i = Math.floor(Math.random() * (1 + slot.replicas.length)); | ||
if (i < slot.replicas.length) { | ||
do { | ||
yield slot.replicas[i]; | ||
} while (++i < slot.replicas.length); | ||
} | ||
while (true) { | ||
yield slot.master; | ||
for (const replica of slot.replicas) { | ||
yield replica; | ||
} | ||
} | ||
} | ||
getSlotRandomNode(slotNumber) { | ||
@@ -324,3 +123,3 @@ const slot = this.slots[slotNumber]; | ||
} | ||
slot.nodesIterator ??= this.#slotNodesIterator(slot); | ||
slot.nodesIterator ?? (slot.nodesIterator = __classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_slotNodesIterator).call(this, slot)); | ||
return slot.nodesIterator.next().value; | ||
@@ -337,28 +136,4 @@ } | ||
this.pubSubNode.client : | ||
this.#initiatePubSubClient(); | ||
__classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_initiatePubSubClient).call(this); | ||
} | ||
async #initiatePubSubClient(toResubscribe) { | ||
const index = Math.floor(Math.random() * (this.masters.length + this.replicas.length)), node = index < this.masters.length ? | ||
this.masters[index] : | ||
this.replicas[index - this.masters.length]; | ||
this.pubSubNode = { | ||
address: node.address, | ||
client: this.#createClient(node, true) | ||
.then(async (client) => { | ||
if (toResubscribe) { | ||
await Promise.all([ | ||
client.extendPubSubListeners(pub_sub_1.PubSubType.CHANNELS, toResubscribe[pub_sub_1.PubSubType.CHANNELS]), | ||
client.extendPubSubListeners(pub_sub_1.PubSubType.PATTERNS, toResubscribe[pub_sub_1.PubSubType.PATTERNS]) | ||
]); | ||
} | ||
this.pubSubNode.client = client; | ||
return client; | ||
}) | ||
.catch(err => { | ||
this.pubSubNode = undefined; | ||
throw err; | ||
}) | ||
}; | ||
return this.pubSubNode.client; | ||
} | ||
async executeUnsubscribeCommand(unsubscribe) { | ||
@@ -374,27 +149,4 @@ const client = await this.getPubSubClient(); | ||
const { master } = this.slots[calculateSlot(channel)]; | ||
return master.pubSubClient ?? this.#initiateShardedPubSubClient(master); | ||
return master.pubSubClient ?? __classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_initiateShardedPubSubClient).call(this, master); | ||
} | ||
#initiateShardedPubSubClient(master) { | ||
const promise = this.#createClient(master, true) | ||
.then(client => { | ||
client.on('server-sunsubscribe', async (channel, listeners) => { | ||
try { | ||
await this.rediscover(client); | ||
const redirectTo = await this.getShardedPubSubClient(channel); | ||
redirectTo.extendPubSubChannelListeners(pub_sub_1.PubSubType.SHARDED, channel, listeners); | ||
} | ||
catch (err) { | ||
this.#emit('sharded-shannel-moved-error', err, channel, listeners); | ||
} | ||
}); | ||
master.pubSubClient = client; | ||
return client; | ||
}) | ||
.catch(err => { | ||
master.pubSubClient = undefined; | ||
throw err; | ||
}); | ||
master.pubSubClient = promise; | ||
return promise; | ||
} | ||
async executeShardedUnsubscribeCommand(channel, unsubscribe) { | ||
@@ -412,3 +164,277 @@ const { master } = this.slots[calculateSlot(channel)]; | ||
} | ||
_a = RedisClusterSlots; | ||
_a = RedisClusterSlots, _RedisClusterSlots_options = new WeakMap(), _RedisClusterSlots_Client = new WeakMap(), _RedisClusterSlots_emit = new WeakMap(), _RedisClusterSlots_isOpen = new WeakMap(), _RedisClusterSlots_runningRediscoverPromise = new WeakMap(), _RedisClusterSlots_randomNodeIterator = new WeakMap(), _RedisClusterSlots_instances = new WeakSet(), _RedisClusterSlots_discoverWithRootNodes = async function _RedisClusterSlots_discoverWithRootNodes() { | ||
let start = Math.floor(Math.random() * __classPrivateFieldGet(this, _RedisClusterSlots_options, "f").rootNodes.length); | ||
for (let i = start; i < __classPrivateFieldGet(this, _RedisClusterSlots_options, "f").rootNodes.length; i++) { | ||
if (await __classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_discover).call(this, __classPrivateFieldGet(this, _RedisClusterSlots_options, "f").rootNodes[i])) | ||
return; | ||
} | ||
for (let i = 0; i < start; i++) { | ||
if (await __classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_discover).call(this, __classPrivateFieldGet(this, _RedisClusterSlots_options, "f").rootNodes[i])) | ||
return; | ||
} | ||
throw new errors_1.RootNodesUnavailableError(); | ||
}, _RedisClusterSlots_resetSlots = function _RedisClusterSlots_resetSlots() { | ||
this.slots = new Array(__classPrivateFieldGet(_a, _a, "f", _RedisClusterSlots_SLOTS)); | ||
this.shards = []; | ||
this.masters = []; | ||
this.replicas = []; | ||
__classPrivateFieldSet(this, _RedisClusterSlots_randomNodeIterator, undefined, "f"); | ||
}, _RedisClusterSlots_discover = async function _RedisClusterSlots_discover(rootNode) { | ||
__classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_resetSlots).call(this); | ||
const addressesInUse = new Set(); | ||
try { | ||
const shards = await __classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_getShards).call(this, rootNode), promises = [], eagerConnect = __classPrivateFieldGet(this, _RedisClusterSlots_options, "f").minimizeConnections !== true; | ||
for (const { from, to, master, replicas } of shards) { | ||
const shard = { | ||
master: __classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_initiateSlotNode).call(this, master, false, eagerConnect, addressesInUse, promises) | ||
}; | ||
if (__classPrivateFieldGet(this, _RedisClusterSlots_options, "f").useReplicas) { | ||
shard.replicas = replicas.map(replica => __classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_initiateSlotNode).call(this, replica, true, eagerConnect, addressesInUse, promises)); | ||
} | ||
this.shards.push(shard); | ||
for (let i = from; i <= to; i++) { | ||
this.slots[i] = shard; | ||
} | ||
} | ||
if (this.pubSubNode && !addressesInUse.has(this.pubSubNode.address)) { | ||
if (util_1.types.isPromise(this.pubSubNode.client)) { | ||
promises.push(this.pubSubNode.client.then(client => client.disconnect())); | ||
this.pubSubNode = undefined; | ||
} | ||
else { | ||
promises.push(this.pubSubNode.client.disconnect()); | ||
const channelsListeners = this.pubSubNode.client.getPubSubListeners(pub_sub_1.PubSubType.CHANNELS), patternsListeners = this.pubSubNode.client.getPubSubListeners(pub_sub_1.PubSubType.PATTERNS); | ||
if (channelsListeners.size || patternsListeners.size) { | ||
promises.push(__classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_initiatePubSubClient).call(this, { | ||
[pub_sub_1.PubSubType.CHANNELS]: channelsListeners, | ||
[pub_sub_1.PubSubType.PATTERNS]: patternsListeners | ||
})); | ||
} | ||
} | ||
} | ||
for (const [address, node] of this.nodeByAddress.entries()) { | ||
if (addressesInUse.has(address)) | ||
continue; | ||
if (node.client) { | ||
promises.push(__classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_execOnNodeClient).call(this, node.client, client => client.disconnect())); | ||
} | ||
const { pubSubClient } = node; | ||
if (pubSubClient) { | ||
promises.push(__classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_execOnNodeClient).call(this, pubSubClient, client => client.disconnect())); | ||
} | ||
this.nodeByAddress.delete(address); | ||
} | ||
await Promise.all(promises); | ||
return true; | ||
} | ||
catch (err) { | ||
__classPrivateFieldGet(this, _RedisClusterSlots_emit, "f").call(this, 'error', err); | ||
return false; | ||
} | ||
}, _RedisClusterSlots_getShards = async function _RedisClusterSlots_getShards(rootNode) { | ||
const client = new (__classPrivateFieldGet(this, _RedisClusterSlots_Client, "f"))(__classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_clientOptionsDefaults).call(this, rootNode, true)); | ||
client.on('error', err => __classPrivateFieldGet(this, _RedisClusterSlots_emit, "f").call(this, 'error', err)); | ||
await client.connect(); | ||
try { | ||
// using `CLUSTER SLOTS` and not `CLUSTER SHARDS` to support older versions | ||
return await client.clusterSlots(); | ||
} | ||
finally { | ||
await client.disconnect(); | ||
} | ||
}, _RedisClusterSlots_getNodeAddress = function _RedisClusterSlots_getNodeAddress(address) { | ||
switch (typeof __classPrivateFieldGet(this, _RedisClusterSlots_options, "f").nodeAddressMap) { | ||
case 'object': | ||
return __classPrivateFieldGet(this, _RedisClusterSlots_options, "f").nodeAddressMap[address]; | ||
case 'function': | ||
return __classPrivateFieldGet(this, _RedisClusterSlots_options, "f").nodeAddressMap(address); | ||
} | ||
}, _RedisClusterSlots_clientOptionsDefaults = function _RedisClusterSlots_clientOptionsDefaults(options, disableReconnect) { | ||
let result; | ||
if (__classPrivateFieldGet(this, _RedisClusterSlots_options, "f").defaults) { | ||
let socket; | ||
if (__classPrivateFieldGet(this, _RedisClusterSlots_options, "f").defaults.socket) { | ||
socket = options?.socket ? { | ||
...__classPrivateFieldGet(this, _RedisClusterSlots_options, "f").defaults.socket, | ||
...options.socket | ||
} : __classPrivateFieldGet(this, _RedisClusterSlots_options, "f").defaults.socket; | ||
} | ||
else { | ||
socket = options?.socket; | ||
} | ||
result = { | ||
...__classPrivateFieldGet(this, _RedisClusterSlots_options, "f").defaults, | ||
...options, | ||
socket | ||
}; | ||
} | ||
else { | ||
result = options; | ||
} | ||
if (disableReconnect) { | ||
result ?? (result = {}); | ||
result.socket ?? (result.socket = {}); | ||
result.socket.reconnectStrategy = false; | ||
} | ||
return result; | ||
}, _RedisClusterSlots_initiateSlotNode = function _RedisClusterSlots_initiateSlotNode({ id, ip, port }, readonly, eagerConnent, addressesInUse, promises) { | ||
const address = `${ip}:${port}`; | ||
addressesInUse.add(address); | ||
let node = this.nodeByAddress.get(address); | ||
if (!node) { | ||
node = { | ||
id, | ||
host: ip, | ||
port, | ||
address, | ||
readonly, | ||
client: undefined | ||
}; | ||
if (eagerConnent) { | ||
promises.push(__classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_createNodeClient).call(this, node)); | ||
} | ||
this.nodeByAddress.set(address, node); | ||
} | ||
(readonly ? this.replicas : this.masters).push(node); | ||
return node; | ||
}, _RedisClusterSlots_createClient = async function _RedisClusterSlots_createClient(node, readonly = node.readonly) { | ||
const client = new (__classPrivateFieldGet(this, _RedisClusterSlots_Client, "f"))(__classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_clientOptionsDefaults).call(this, { | ||
socket: __classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_getNodeAddress).call(this, node.address) ?? { | ||
host: node.host, | ||
port: node.port | ||
}, | ||
readonly | ||
})); | ||
client.on('error', err => __classPrivateFieldGet(this, _RedisClusterSlots_emit, "f").call(this, 'error', err)); | ||
await client.connect(); | ||
return client; | ||
}, _RedisClusterSlots_createNodeClient = function _RedisClusterSlots_createNodeClient(node) { | ||
const promise = __classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_createClient).call(this, node) | ||
.then(client => { | ||
node.client = client; | ||
return client; | ||
}) | ||
.catch(err => { | ||
node.client = undefined; | ||
throw err; | ||
}); | ||
node.client = promise; | ||
return promise; | ||
}, _RedisClusterSlots_rediscover = async function _RedisClusterSlots_rediscover(startWith) { | ||
if (await __classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_discover).call(this, startWith.options)) | ||
return; | ||
return __classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_discoverWithRootNodes).call(this); | ||
}, _RedisClusterSlots_destroy = async function _RedisClusterSlots_destroy(fn) { | ||
__classPrivateFieldSet(this, _RedisClusterSlots_isOpen, false, "f"); | ||
const promises = []; | ||
for (const { master, replicas } of this.shards) { | ||
if (master.client) { | ||
promises.push(__classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_execOnNodeClient).call(this, master.client, fn)); | ||
} | ||
if (master.pubSubClient) { | ||
promises.push(__classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_execOnNodeClient).call(this, master.pubSubClient, fn)); | ||
} | ||
if (replicas) { | ||
for (const { client } of replicas) { | ||
if (client) { | ||
promises.push(__classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_execOnNodeClient).call(this, client, fn)); | ||
} | ||
} | ||
} | ||
} | ||
if (this.pubSubNode) { | ||
promises.push(__classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_execOnNodeClient).call(this, this.pubSubNode.client, fn)); | ||
this.pubSubNode = undefined; | ||
} | ||
__classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_resetSlots).call(this); | ||
this.nodeByAddress.clear(); | ||
await Promise.allSettled(promises); | ||
}, _RedisClusterSlots_execOnNodeClient = function _RedisClusterSlots_execOnNodeClient(client, fn) { | ||
return util_1.types.isPromise(client) ? | ||
client.then(fn) : | ||
fn(client); | ||
}, _RedisClusterSlots_iterateAllNodes = function* _RedisClusterSlots_iterateAllNodes() { | ||
let i = Math.floor(Math.random() * (this.masters.length + this.replicas.length)); | ||
if (i < this.masters.length) { | ||
do { | ||
yield this.masters[i]; | ||
} while (++i < this.masters.length); | ||
for (const replica of this.replicas) { | ||
yield replica; | ||
} | ||
} | ||
else { | ||
i -= this.masters.length; | ||
do { | ||
yield this.replicas[i]; | ||
} while (++i < this.replicas.length); | ||
} | ||
while (true) { | ||
for (const master of this.masters) { | ||
yield master; | ||
} | ||
for (const replica of this.replicas) { | ||
yield replica; | ||
} | ||
} | ||
}, _RedisClusterSlots_slotNodesIterator = function* _RedisClusterSlots_slotNodesIterator(slot) { | ||
let i = Math.floor(Math.random() * (1 + slot.replicas.length)); | ||
if (i < slot.replicas.length) { | ||
do { | ||
yield slot.replicas[i]; | ||
} while (++i < slot.replicas.length); | ||
} | ||
while (true) { | ||
yield slot.master; | ||
for (const replica of slot.replicas) { | ||
yield replica; | ||
} | ||
} | ||
}, _RedisClusterSlots_initiatePubSubClient = async function _RedisClusterSlots_initiatePubSubClient(toResubscribe) { | ||
const index = Math.floor(Math.random() * (this.masters.length + this.replicas.length)), node = index < this.masters.length ? | ||
this.masters[index] : | ||
this.replicas[index - this.masters.length]; | ||
this.pubSubNode = { | ||
address: node.address, | ||
client: __classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_createClient).call(this, node, true) | ||
.then(async (client) => { | ||
if (toResubscribe) { | ||
await Promise.all([ | ||
client.extendPubSubListeners(pub_sub_1.PubSubType.CHANNELS, toResubscribe[pub_sub_1.PubSubType.CHANNELS]), | ||
client.extendPubSubListeners(pub_sub_1.PubSubType.PATTERNS, toResubscribe[pub_sub_1.PubSubType.PATTERNS]) | ||
]); | ||
} | ||
this.pubSubNode.client = client; | ||
return client; | ||
}) | ||
.catch(err => { | ||
this.pubSubNode = undefined; | ||
throw err; | ||
}) | ||
}; | ||
return this.pubSubNode.client; | ||
}, _RedisClusterSlots_initiateShardedPubSubClient = function _RedisClusterSlots_initiateShardedPubSubClient(master) { | ||
const promise = __classPrivateFieldGet(this, _RedisClusterSlots_instances, "m", _RedisClusterSlots_createClient).call(this, master, true) | ||
.then(client => { | ||
client.on('server-sunsubscribe', async (channel, listeners) => { | ||
try { | ||
await this.rediscover(client); | ||
const redirectTo = await this.getShardedPubSubClient(channel); | ||
redirectTo.extendPubSubChannelListeners(pub_sub_1.PubSubType.SHARDED, channel, listeners); | ||
} | ||
catch (err) { | ||
__classPrivateFieldGet(this, _RedisClusterSlots_emit, "f").call(this, 'sharded-shannel-moved-error', err, channel, listeners); | ||
} | ||
}); | ||
master.pubSubClient = client; | ||
return client; | ||
}) | ||
.catch(err => { | ||
master.pubSubClient = undefined; | ||
throw err; | ||
}); | ||
master.pubSubClient = promise; | ||
return promise; | ||
}; | ||
_RedisClusterSlots_SLOTS = { value: 16384 }; | ||
exports.default = RedisClusterSlots; |
"use strict"; | ||
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); | ||
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); | ||
}; | ||
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
if (kind === "m") throw new TypeError("Private method is not writable"); | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); | ||
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; | ||
}; | ||
var _RedisCluster_instances, _RedisCluster_options, _RedisCluster_slots, _RedisCluster_Multi, _RedisCluster_execute; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -30,35 +42,78 @@ const commands_1 = require("./commands"); | ||
} | ||
#options; | ||
#slots; | ||
get slots() { | ||
return this.#slots.slots; | ||
return __classPrivateFieldGet(this, _RedisCluster_slots, "f").slots; | ||
} | ||
get shards() { | ||
return this.#slots.shards; | ||
return __classPrivateFieldGet(this, _RedisCluster_slots, "f").shards; | ||
} | ||
get masters() { | ||
return this.#slots.masters; | ||
return __classPrivateFieldGet(this, _RedisCluster_slots, "f").masters; | ||
} | ||
get replicas() { | ||
return this.#slots.replicas; | ||
return __classPrivateFieldGet(this, _RedisCluster_slots, "f").replicas; | ||
} | ||
get nodeByAddress() { | ||
return this.#slots.nodeByAddress; | ||
return __classPrivateFieldGet(this, _RedisCluster_slots, "f").nodeByAddress; | ||
} | ||
get pubSubNode() { | ||
return this.#slots.pubSubNode; | ||
return __classPrivateFieldGet(this, _RedisCluster_slots, "f").pubSubNode; | ||
} | ||
#Multi; | ||
get isOpen() { | ||
return this.#slots.isOpen; | ||
return __classPrivateFieldGet(this, _RedisCluster_slots, "f").isOpen; | ||
} | ||
constructor(options) { | ||
super(); | ||
this.#options = options; | ||
this.#slots = new cluster_slots_1.default(options, this.emit.bind(this)); | ||
this.#Multi = multi_command_1.default.extend(options); | ||
_RedisCluster_instances.add(this); | ||
_RedisCluster_options.set(this, void 0); | ||
_RedisCluster_slots.set(this, void 0); | ||
_RedisCluster_Multi.set(this, void 0); | ||
Object.defineProperty(this, "multi", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: this.MULTI | ||
}); | ||
Object.defineProperty(this, "subscribe", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: this.SUBSCRIBE | ||
}); | ||
Object.defineProperty(this, "unsubscribe", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: this.UNSUBSCRIBE | ||
}); | ||
Object.defineProperty(this, "pSubscribe", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: this.PSUBSCRIBE | ||
}); | ||
Object.defineProperty(this, "pUnsubscribe", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: this.PUNSUBSCRIBE | ||
}); | ||
Object.defineProperty(this, "sSubscribe", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: this.SSUBSCRIBE | ||
}); | ||
Object.defineProperty(this, "sUnsubscribe", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: this.SUNSUBSCRIBE | ||
}); | ||
__classPrivateFieldSet(this, _RedisCluster_options, options, "f"); | ||
__classPrivateFieldSet(this, _RedisCluster_slots, new cluster_slots_1.default(options, this.emit.bind(this)), "f"); | ||
__classPrivateFieldSet(this, _RedisCluster_Multi, multi_command_1.default.extend(options), "f"); | ||
} | ||
duplicate(overrides) { | ||
return new (Object.getPrototypeOf(this).constructor)({ | ||
...this.#options, | ||
...__classPrivateFieldGet(this, _RedisCluster_options, "f"), | ||
...overrides | ||
@@ -68,3 +123,3 @@ }); | ||
connect() { | ||
return this.#slots.connect(); | ||
return __classPrivateFieldGet(this, _RedisCluster_slots, "f").connect(); | ||
} | ||
@@ -76,3 +131,3 @@ async commandsExecutor(command, args) { | ||
async sendCommand(firstKey, isReadonly, args, options) { | ||
return this.#execute(firstKey, isReadonly, client => client.sendCommand(args, options)); | ||
return __classPrivateFieldGet(this, _RedisCluster_instances, "m", _RedisCluster_execute).call(this, firstKey, isReadonly, client => client.sendCommand(args, options)); | ||
} | ||
@@ -84,3 +139,3 @@ async functionsExecutor(fn, args, name) { | ||
async executeFunction(name, fn, originalArgs, redisArgs, options) { | ||
return this.#execute(RedisCluster.extractFirstKey(fn, originalArgs, redisArgs), fn.IS_READ_ONLY, client => client.executeFunction(name, fn, redisArgs, options)); | ||
return __classPrivateFieldGet(this, _RedisCluster_instances, "m", _RedisCluster_execute).call(this, RedisCluster.extractFirstKey(fn, originalArgs, redisArgs), fn.IS_READ_ONLY, client => client.executeFunction(name, fn, redisArgs, options)); | ||
} | ||
@@ -92,65 +147,26 @@ async scriptsExecutor(script, args) { | ||
async executeScript(script, originalArgs, redisArgs, options) { | ||
return this.#execute(RedisCluster.extractFirstKey(script, originalArgs, redisArgs), script.IS_READ_ONLY, client => client.executeScript(script, redisArgs, options)); | ||
return __classPrivateFieldGet(this, _RedisCluster_instances, "m", _RedisCluster_execute).call(this, RedisCluster.extractFirstKey(script, originalArgs, redisArgs), script.IS_READ_ONLY, client => client.executeScript(script, redisArgs, options)); | ||
} | ||
async #execute(firstKey, isReadonly, executor) { | ||
const maxCommandRedirections = this.#options.maxCommandRedirections ?? 16; | ||
let client = await this.#slots.getClient(firstKey, isReadonly); | ||
for (let i = 0;; i++) { | ||
try { | ||
return await executor(client); | ||
} | ||
catch (err) { | ||
if (++i > maxCommandRedirections || !(err instanceof errors_1.ErrorReply)) { | ||
throw err; | ||
} | ||
if (err.message.startsWith('ASK')) { | ||
const address = err.message.substring(err.message.lastIndexOf(' ') + 1); | ||
let redirectTo = await this.#slots.getMasterByAddress(address); | ||
if (!redirectTo) { | ||
await this.#slots.rediscover(client); | ||
redirectTo = await this.#slots.getMasterByAddress(address); | ||
} | ||
if (!redirectTo) { | ||
throw new Error(`Cannot find node ${address}`); | ||
} | ||
await redirectTo.asking(); | ||
client = redirectTo; | ||
continue; | ||
} | ||
else if (err.message.startsWith('MOVED')) { | ||
await this.#slots.rediscover(client); | ||
client = await this.#slots.getClient(firstKey, isReadonly); | ||
continue; | ||
} | ||
throw err; | ||
} | ||
} | ||
} | ||
MULTI(routing) { | ||
return new this.#Multi((commands, firstKey, chainId) => { | ||
return this.#execute(firstKey, false, client => client.multiExecutor(commands, undefined, chainId)); | ||
return new (__classPrivateFieldGet(this, _RedisCluster_Multi, "f"))((commands, firstKey, chainId) => { | ||
return __classPrivateFieldGet(this, _RedisCluster_instances, "m", _RedisCluster_execute).call(this, firstKey, false, client => client.multiExecutor(commands, undefined, chainId)); | ||
}, routing); | ||
} | ||
multi = this.MULTI; | ||
async SUBSCRIBE(channels, listener, bufferMode) { | ||
return (await this.#slots.getPubSubClient()) | ||
return (await __classPrivateFieldGet(this, _RedisCluster_slots, "f").getPubSubClient()) | ||
.SUBSCRIBE(channels, listener, bufferMode); | ||
} | ||
subscribe = this.SUBSCRIBE; | ||
async UNSUBSCRIBE(channels, listener, bufferMode) { | ||
return this.#slots.executeUnsubscribeCommand(client => client.UNSUBSCRIBE(channels, listener, bufferMode)); | ||
return __classPrivateFieldGet(this, _RedisCluster_slots, "f").executeUnsubscribeCommand(client => client.UNSUBSCRIBE(channels, listener, bufferMode)); | ||
} | ||
unsubscribe = this.UNSUBSCRIBE; | ||
async PSUBSCRIBE(patterns, listener, bufferMode) { | ||
return (await this.#slots.getPubSubClient()) | ||
return (await __classPrivateFieldGet(this, _RedisCluster_slots, "f").getPubSubClient()) | ||
.PSUBSCRIBE(patterns, listener, bufferMode); | ||
} | ||
pSubscribe = this.PSUBSCRIBE; | ||
async PUNSUBSCRIBE(patterns, listener, bufferMode) { | ||
return this.#slots.executeUnsubscribeCommand(client => client.PUNSUBSCRIBE(patterns, listener, bufferMode)); | ||
return __classPrivateFieldGet(this, _RedisCluster_slots, "f").executeUnsubscribeCommand(client => client.PUNSUBSCRIBE(patterns, listener, bufferMode)); | ||
} | ||
pUnsubscribe = this.PUNSUBSCRIBE; | ||
async SSUBSCRIBE(channels, listener, bufferMode) { | ||
const maxCommandRedirections = this.#options.maxCommandRedirections ?? 16, firstChannel = Array.isArray(channels) ? channels[0] : channels; | ||
let client = await this.#slots.getShardedPubSubClient(firstChannel); | ||
const maxCommandRedirections = __classPrivateFieldGet(this, _RedisCluster_options, "f").maxCommandRedirections ?? 16, firstChannel = Array.isArray(channels) ? channels[0] : channels; | ||
let client = await __classPrivateFieldGet(this, _RedisCluster_slots, "f").getShardedPubSubClient(firstChannel); | ||
for (let i = 0;; i++) { | ||
@@ -165,4 +181,4 @@ try { | ||
if (err.message.startsWith('MOVED')) { | ||
await this.#slots.rediscover(client); | ||
client = await this.#slots.getShardedPubSubClient(firstChannel); | ||
await __classPrivateFieldGet(this, _RedisCluster_slots, "f").rediscover(client); | ||
client = await __classPrivateFieldGet(this, _RedisCluster_slots, "f").getShardedPubSubClient(firstChannel); | ||
continue; | ||
@@ -174,21 +190,19 @@ } | ||
} | ||
sSubscribe = this.SSUBSCRIBE; | ||
SUNSUBSCRIBE(channels, listener, bufferMode) { | ||
return this.#slots.executeShardedUnsubscribeCommand(Array.isArray(channels) ? channels[0] : channels, client => client.SUNSUBSCRIBE(channels, listener, bufferMode)); | ||
return __classPrivateFieldGet(this, _RedisCluster_slots, "f").executeShardedUnsubscribeCommand(Array.isArray(channels) ? channels[0] : channels, client => client.SUNSUBSCRIBE(channels, listener, bufferMode)); | ||
} | ||
sUnsubscribe = this.SUNSUBSCRIBE; | ||
quit() { | ||
return this.#slots.quit(); | ||
return __classPrivateFieldGet(this, _RedisCluster_slots, "f").quit(); | ||
} | ||
disconnect() { | ||
return this.#slots.disconnect(); | ||
return __classPrivateFieldGet(this, _RedisCluster_slots, "f").disconnect(); | ||
} | ||
nodeClient(node) { | ||
return this.#slots.nodeClient(node); | ||
return __classPrivateFieldGet(this, _RedisCluster_slots, "f").nodeClient(node); | ||
} | ||
getRandomNode() { | ||
return this.#slots.getRandomNode(); | ||
return __classPrivateFieldGet(this, _RedisCluster_slots, "f").getRandomNode(); | ||
} | ||
getSlotRandomNode(slot) { | ||
return this.#slots.getSlotRandomNode(slot); | ||
return __classPrivateFieldGet(this, _RedisCluster_slots, "f").getSlotRandomNode(slot); | ||
} | ||
@@ -208,2 +222,36 @@ /** | ||
} | ||
_RedisCluster_options = new WeakMap(), _RedisCluster_slots = new WeakMap(), _RedisCluster_Multi = new WeakMap(), _RedisCluster_instances = new WeakSet(), _RedisCluster_execute = async function _RedisCluster_execute(firstKey, isReadonly, executor) { | ||
const maxCommandRedirections = __classPrivateFieldGet(this, _RedisCluster_options, "f").maxCommandRedirections ?? 16; | ||
let client = await __classPrivateFieldGet(this, _RedisCluster_slots, "f").getClient(firstKey, isReadonly); | ||
for (let i = 0;; i++) { | ||
try { | ||
return await executor(client); | ||
} | ||
catch (err) { | ||
if (++i > maxCommandRedirections || !(err instanceof errors_1.ErrorReply)) { | ||
throw err; | ||
} | ||
if (err.message.startsWith('ASK')) { | ||
const address = err.message.substring(err.message.lastIndexOf(' ') + 1); | ||
let redirectTo = await __classPrivateFieldGet(this, _RedisCluster_slots, "f").getMasterByAddress(address); | ||
if (!redirectTo) { | ||
await __classPrivateFieldGet(this, _RedisCluster_slots, "f").rediscover(client); | ||
redirectTo = await __classPrivateFieldGet(this, _RedisCluster_slots, "f").getMasterByAddress(address); | ||
} | ||
if (!redirectTo) { | ||
throw new Error(`Cannot find node ${address}`); | ||
} | ||
await redirectTo.asking(); | ||
client = redirectTo; | ||
continue; | ||
} | ||
else if (err.message.startsWith('MOVED')) { | ||
await __classPrivateFieldGet(this, _RedisCluster_slots, "f").rediscover(client); | ||
client = await __classPrivateFieldGet(this, _RedisCluster_slots, "f").getClient(firstKey, isReadonly); | ||
continue; | ||
} | ||
throw err; | ||
} | ||
} | ||
}; | ||
exports.default = RedisCluster; | ||
@@ -210,0 +258,0 @@ (0, commander_1.attachCommands)({ |
"use strict"; | ||
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
if (kind === "m") throw new TypeError("Private method is not writable"); | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); | ||
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; | ||
}; | ||
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); | ||
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); | ||
}; | ||
var _RedisClusterMultiCommand_multi, _RedisClusterMultiCommand_executor, _RedisClusterMultiCommand_firstKey; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -8,5 +20,2 @@ const commands_1 = require("./commands"); | ||
class RedisClusterMultiCommand { | ||
#multi = new multi_command_1.default(); | ||
#executor; | ||
#firstKey; | ||
static extend(extensions) { | ||
@@ -24,23 +33,32 @@ return (0, commander_1.attachExtensions)({ | ||
constructor(executor, firstKey) { | ||
this.#executor = executor; | ||
this.#firstKey = firstKey; | ||
_RedisClusterMultiCommand_multi.set(this, new multi_command_1.default()); | ||
_RedisClusterMultiCommand_executor.set(this, void 0); | ||
_RedisClusterMultiCommand_firstKey.set(this, void 0); | ||
Object.defineProperty(this, "EXEC", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: this.exec | ||
}); | ||
__classPrivateFieldSet(this, _RedisClusterMultiCommand_executor, executor, "f"); | ||
__classPrivateFieldSet(this, _RedisClusterMultiCommand_firstKey, firstKey, "f"); | ||
} | ||
commandsExecutor(command, args) { | ||
const transformedArguments = command.transformArguments(...args); | ||
this.#firstKey ??= _1.default.extractFirstKey(command, args, transformedArguments); | ||
__classPrivateFieldSet(this, _RedisClusterMultiCommand_firstKey, __classPrivateFieldGet(this, _RedisClusterMultiCommand_firstKey, "f") ?? _1.default.extractFirstKey(command, args, transformedArguments), "f"); | ||
return this.addCommand(undefined, transformedArguments, command.transformReply); | ||
} | ||
addCommand(firstKey, args, transformReply) { | ||
this.#firstKey ??= firstKey; | ||
this.#multi.addCommand(args, transformReply); | ||
__classPrivateFieldSet(this, _RedisClusterMultiCommand_firstKey, __classPrivateFieldGet(this, _RedisClusterMultiCommand_firstKey, "f") ?? firstKey, "f"); | ||
__classPrivateFieldGet(this, _RedisClusterMultiCommand_multi, "f").addCommand(args, transformReply); | ||
return this; | ||
} | ||
functionsExecutor(fn, args, name) { | ||
const transformedArguments = this.#multi.addFunction(name, fn, args); | ||
this.#firstKey ??= _1.default.extractFirstKey(fn, args, transformedArguments); | ||
const transformedArguments = __classPrivateFieldGet(this, _RedisClusterMultiCommand_multi, "f").addFunction(name, fn, args); | ||
__classPrivateFieldSet(this, _RedisClusterMultiCommand_firstKey, __classPrivateFieldGet(this, _RedisClusterMultiCommand_firstKey, "f") ?? _1.default.extractFirstKey(fn, args, transformedArguments), "f"); | ||
return this; | ||
} | ||
scriptsExecutor(script, args) { | ||
const transformedArguments = this.#multi.addScript(script, args); | ||
this.#firstKey ??= _1.default.extractFirstKey(script, args, transformedArguments); | ||
const transformedArguments = __classPrivateFieldGet(this, _RedisClusterMultiCommand_multi, "f").addScript(script, args); | ||
__classPrivateFieldSet(this, _RedisClusterMultiCommand_firstKey, __classPrivateFieldGet(this, _RedisClusterMultiCommand_firstKey, "f") ?? _1.default.extractFirstKey(script, args, transformedArguments), "f"); | ||
return this; | ||
@@ -52,9 +70,9 @@ } | ||
} | ||
return this.#multi.handleExecReplies(await this.#executor(this.#multi.queue, this.#firstKey, multi_command_1.default.generateChainId())); | ||
return __classPrivateFieldGet(this, _RedisClusterMultiCommand_multi, "f").handleExecReplies(await __classPrivateFieldGet(this, _RedisClusterMultiCommand_executor, "f").call(this, __classPrivateFieldGet(this, _RedisClusterMultiCommand_multi, "f").queue, __classPrivateFieldGet(this, _RedisClusterMultiCommand_firstKey, "f"), multi_command_1.default.generateChainId())); | ||
} | ||
EXEC = this.exec; | ||
async execAsPipeline() { | ||
return this.#multi.transformReplies(await this.#executor(this.#multi.queue, this.#firstKey)); | ||
return __classPrivateFieldGet(this, _RedisClusterMultiCommand_multi, "f").transformReplies(await __classPrivateFieldGet(this, _RedisClusterMultiCommand_executor, "f").call(this, __classPrivateFieldGet(this, _RedisClusterMultiCommand_multi, "f").queue, __classPrivateFieldGet(this, _RedisClusterMultiCommand_firstKey, "f"))); | ||
} | ||
} | ||
_RedisClusterMultiCommand_multi = new WeakMap(), _RedisClusterMultiCommand_executor = new WeakMap(), _RedisClusterMultiCommand_firstKey = new WeakMap(); | ||
exports.default = RedisClusterMultiCommand; | ||
@@ -61,0 +79,0 @@ (0, commander_1.attachCommands)({ |
@@ -30,4 +30,4 @@ "use strict"; | ||
if (config.scripts) { | ||
Commander ??= class extends config.BaseClass { | ||
}; | ||
Commander ?? (Commander = class extends config.BaseClass { | ||
}); | ||
attachCommands({ | ||
@@ -34,0 +34,0 @@ BaseClass: Commander, |
@@ -53,6 +53,16 @@ "use strict"; | ||
class ReconnectStrategyError extends Error { | ||
originalError; | ||
socketError; | ||
constructor(originalError, socketError) { | ||
super(originalError.message); | ||
Object.defineProperty(this, "originalError", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "socketError", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
this.originalError = originalError; | ||
@@ -59,0 +69,0 @@ this.socketError = socketError; |
@@ -6,7 +6,19 @@ "use strict"; | ||
class RedisMultiCommand { | ||
constructor() { | ||
Object.defineProperty(this, "queue", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: [] | ||
}); | ||
Object.defineProperty(this, "scriptsInUse", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: new Set() | ||
}); | ||
} | ||
static generateChainId() { | ||
return Symbol('RedisMultiCommand Chain Id'); | ||
} | ||
queue = []; | ||
scriptsInUse = new Set(); | ||
addCommand(args, transformReply) { | ||
@@ -13,0 +25,0 @@ this.queue.push({ |
{ | ||
"name": "@redis/client", | ||
"version": "1.5.10", | ||
"version": "1.5.11", | ||
"license": "MIT", | ||
@@ -39,3 +39,3 @@ "main": "./dist/index.js", | ||
"engines": { | ||
"node": ">=18" | ||
"node": ">=14" | ||
}, | ||
@@ -42,0 +42,0 @@ "repository": { |
594047
13241