1
0
mirror of https://github.com/redis/node-redis.git synced 2025-08-09 00:22:08 +03:00

fix #1659 - add support for db-number in client options url

This commit is contained in:
leibale
2021-09-21 15:30:25 -04:00
parent d79bc55df6
commit 1819b9c1c4
5 changed files with 149 additions and 60 deletions

View File

@@ -1,4 +1,4 @@
import RedisSocket, { RedisSocketOptions } from './socket';
import RedisSocket, { RedisSocketOptions, RedisNetSocketOptions, RedisTlsSocketOptions } from './socket';
import RedisCommandsQueue, { PubSubListener, PubSubSubscribeCommands, PubSubUnsubscribeCommands, QueueCommandOptions } from './commands-queue';
import COMMANDS, { TransformArgumentsReply } from './commands';
import { RedisCommand, RedisModules, RedisReply } from './commands';
@@ -12,9 +12,14 @@ import { HScanTuple } from './commands/HSCAN';
import { encodeCommand, extendWithDefaultCommands, extendWithModulesAndScripts, transformCommandArguments } from './commander';
import { Pool, Options as PoolOptions, createPool } from 'generic-pool';
import { ClientClosedError } from './errors';
import { URL } from 'url';
export interface RedisClientOptions<M, S> {
url?: string;
socket?: RedisSocketOptions;
username?: string;
password?: string;
database?: number;
modules?: M;
scripts?: S;
commandsQueueMaxLength?: number;
@@ -71,6 +76,45 @@ export default class RedisClient<M extends RedisModules, S extends RedisLuaScrip
return new Client(options);
}
static parseURL(url: string): RedisClientOptions<{}, {}> {
// https://www.iana.org/assignments/uri-schemes/prov/redis
const { hostname, port, protocol, username, password, pathname } = new URL(url),
parsed: RedisClientOptions<{}, {}> = {
socket: {
host: hostname
}
};
if (protocol === 'rediss:') {
(parsed.socket as RedisTlsSocketOptions).tls = true;
} else if (protocol !== 'redis:') {
throw new TypeError('Invalid protocol');
}
if (port) {
(parsed.socket as RedisNetSocketOptions).port = Number(port);
}
if (username) {
parsed.username = username;
}
if (password) {
parsed.password = password;
}
if (pathname.length > 1) {
const database = Number(pathname.substring(1));
if (isNaN(database)) {
throw new TypeError('Invalid pathname');
}
parsed.database = database;
}
return parsed;
}
readonly #options?: RedisClientOptions<M, S>;
readonly #socket: RedisSocket;
readonly #queue: RedisCommandsQueue;
@@ -96,7 +140,7 @@ export default class RedisClient<M extends RedisModules, S extends RedisLuaScrip
constructor(options?: RedisClientOptions<M, S>) {
super();
this.#options = options;
this.#options = this.#initiateOptions(options);
this.#socket = this.#initiateSocket();
this.#queue = this.#initiateQueue();
this.#isolationPool = createPool({
@@ -110,6 +154,23 @@ export default class RedisClient<M extends RedisModules, S extends RedisLuaScrip
this.#legacyMode();
}
#initiateOptions(options?: RedisClientOptions<M, S>): RedisClientOptions<M, S> | undefined {
if (options?.url) {
const parsed = RedisClient.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;
}
#initiateSocket(): RedisSocket {
const socketInitiator = async (): Promise<void> => {
const v4Commands = this.#options?.legacyMode ? this.#v4 : this,
@@ -123,8 +184,8 @@ export default class RedisClient<M extends RedisModules, S extends RedisLuaScrip
promises.push(v4Commands.readonly(RedisClient.commandOptions({ asap: true })));
}
if (this.#options?.socket?.username || this.#options?.socket?.password) {
promises.push(v4Commands.auth(RedisClient.commandOptions({ asap: true }), this.#options.socket));
if (this.#options?.username || this.#options?.password) {
promises.push(v4Commands.auth(RedisClient.commandOptions({ asap: true }), this.#options));
}
const resubscribePromise = this.#queue.resubscribe();