Skip to content

fix(client): bring disableClientInfo option back #2959

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 47 additions & 1 deletion packages/client/lib/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { BasicAuth, CredentialsError, CredentialsProvider, StreamingCredentialsP
import RedisCommandsQueue, { CommandOptions } from './commands-queue';
import { EventEmitter } from 'node:events';
import { attachConfig, functionArgumentsPrefix, getTransformReply, scriptArgumentsPrefix } from '../commander';
import { ClientClosedError, ClientOfflineError, DisconnectsClientError, WatchError } from '../errors';
import { ClientClosedError, ClientOfflineError, DisconnectsClientError, SimpleError, WatchError } from '../errors';
import { URL } from 'node:url';
import { TcpSocketConnectOpts } from 'node:net';
import { PUBSUB_TYPE, PubSubType, PubSubListener, PubSubTypeListeners, ChannelListeners } from './pub-sub';
Expand All @@ -18,6 +18,7 @@ import { RedisPoolOptions, RedisClientPool } from './pool';
import { RedisVariadicArgument, parseArgs, pushVariadicArguments } from '../commands/generic-transformers';
import { BasicCommandParser, CommandParser } from './parser';
import SingleEntryCache from '../single-entry-cache';
import { version } from '../../package.json'

export interface RedisClientOptions<
M extends RedisModules = RedisModules,
Expand Down Expand Up @@ -81,6 +82,14 @@ export interface RedisClientOptions<
* TODO
*/
commandOptions?: CommandOptions<TYPE_MAPPING>;
/**
* If set to true, disables sending client identifier (user-agent like message) to the redis server
*/
disableClientInfo?: boolean;
/**
* Tag to append to library name that is sent to the Redis server
*/
clientInfoTag?: string;
}

type WithCommands<
Expand Down Expand Up @@ -548,6 +557,43 @@ export default class RedisClient<
);
}

if (!this.#options?.disableClientInfo) {
promises.push(
this.#queue.addCommand([
'CLIENT',
'SETINFO',
'LIB-NAME',
this.#options?.clientInfoTag
? `node-redis(${this.#options.clientInfoTag})` : 'node-redis'
], {
chainId,
asap: true
}).catch(err => {
// Only throw if not a SimpleError - unknown subcommand
// Client libraries are expected to ignore failures
// of type SimpleError - unknown subcommand, which are
// expected from older servers ( < v7 )
if (!(err instanceof SimpleError) || !err.isUnknownSubcommand()) {
throw err;
}
})
);
promises.push(
this.#queue.addCommand(['CLIENT', 'SETINFO', 'LIB-VER', version],{
chainId,
asap: true
}).catch(err => {
// Only throw if not a SimpleError - unknown subcommand
// Client libraries are expected to ignore failures
// of type SimpleError - unknown subcommand, which are
// expected from older servers ( < v7 )
if (!(err instanceof SimpleError) || !err.isUnknownSubcommand()) {
throw err;
}
})
);
}

const commands = await this.#handshake(this.#selectedDB);
for (let i = commands.length - 1; i >= 0; --i) {
promises.push(
Expand Down
86 changes: 86 additions & 0 deletions packages/client/lib/commands/CLIENT_INFO.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { strict as assert } from 'node:assert';
import CLIENT_INFO from './CLIENT_INFO';
import testUtils, { GLOBAL } from '../test-utils';
import { parseArgs } from './generic-transformers';
import { version } from '../../package.json';

describe('CLIENT INFO', () => {
testUtils.isVersionGreaterThanHook([6, 2]);
Expand Down Expand Up @@ -48,4 +49,89 @@ describe('CLIENT INFO', () => {
}
}
}, GLOBAL.SERVERS.OPEN);

testUtils.testWithClient('client.clientInfo Redis < 7', async client => {
const reply = await client.clientInfo();
if (!testUtils.isVersionGreaterThan([7])) {
assert.strictEqual(reply.libName, undefined, 'LibName should be undefined for Redis < 7');
assert.strictEqual(reply.libVer, undefined, 'LibVer should be undefined for Redis < 7');
}
}, GLOBAL.SERVERS.OPEN);

testUtils.testWithClientIfVersionWithinRange([[7], 'LATEST'], 'client.clientInfo Redis>=7 info disabled', async client => {
const reply = await client.clientInfo();
assert.equal(reply.libName, '');
assert.equal(reply.libVer, '');
}, {
...GLOBAL.SERVERS.OPEN,
clientOptions: {
disableClientInfo: true
}
});

testUtils.testWithClientIfVersionWithinRange([[7], 'LATEST'], 'client.clientInfo Redis>=7 resp unset, info enabled, tag set', async client => {
const reply = await client.clientInfo();
assert.equal(reply.libName, 'node-redis(client1)');
assert.equal(reply.libVer, version);
}, {
...GLOBAL.SERVERS.OPEN,
clientOptions: {
clientInfoTag: 'client1'
}
});

testUtils.testWithClientIfVersionWithinRange([[7], 'LATEST'], 'client.clientInfo Redis>=7 resp unset, info enabled, tag unset', async client => {
const reply = await client.clientInfo();
assert.equal(reply.libName, 'node-redis');
assert.equal(reply.libVer, version);
}, GLOBAL.SERVERS.OPEN);

testUtils.testWithClientIfVersionWithinRange([[7], 'LATEST'], 'client.clientInfo Redis>=7 resp2 info enabled', async client => {
const reply = await client.clientInfo();
assert.equal(reply.libName, 'node-redis(client1)');
assert.equal(reply.libVer, version);
}, {
...GLOBAL.SERVERS.OPEN,
clientOptions: {
RESP: 2,
clientInfoTag: 'client1'
}
});

testUtils.testWithClientIfVersionWithinRange([[7], 'LATEST'], 'client.clientInfo Redis>=7 resp2 info disabled', async client => {
const reply = await client.clientInfo();
assert.equal(reply.libName, '');
assert.equal(reply.libVer, '');
}, {
...GLOBAL.SERVERS.OPEN,
clientOptions: {
disableClientInfo: true,
RESP: 2
}
});

testUtils.testWithClientIfVersionWithinRange([[7], 'LATEST'], 'client.clientInfo Redis>=7 resp3 info enabled', async client => {
const reply = await client.clientInfo();
assert.equal(reply.libName, 'node-redis(client1)');
assert.equal(reply.libVer, version);
}, {
...GLOBAL.SERVERS.OPEN,
clientOptions: {
RESP: 3,
clientInfoTag: 'client1'
}
});

testUtils.testWithClientIfVersionWithinRange([[7], 'LATEST'], 'client.clientInfo Redis>=7 resp3 info disabled', async client => {
const reply = await client.clientInfo();
assert.equal(reply.libName, '');
assert.equal(reply.libVer, '');
}, {
...GLOBAL.SERVERS.OPEN,
clientOptions: {
disableClientInfo: true,
RESP: 3
}
});

});
13 changes: 11 additions & 2 deletions packages/client/lib/commands/CLIENT_INFO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ export interface ClientInfoReply {
* available since 7.0
*/
resp?: number;
/**
* available since 7.0
*/
libName?: string;
/**
* available since 7.0
*/
libVer?: string;
}

const CLIENT_INFO_REGEX = /([^\s=]+)=([^\s]*)/g;
Expand All @@ -67,7 +75,6 @@ export default {
for (const item of rawReply.toString().matchAll(CLIENT_INFO_REGEX)) {
map[item[1]] = item[2];
}

const reply: ClientInfoReply = {
id: Number(map.id),
addr: map.addr,
Expand All @@ -89,7 +96,9 @@ export default {
totMem: Number(map['tot-mem']),
events: map.events,
cmd: map.cmd,
user: map.user
user: map.user,
libName: map['lib-name'],
libVer: map['lib-ver']
};

if (map.laddr !== undefined) {
Expand Down
6 changes: 5 additions & 1 deletion packages/client/lib/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ export class ErrorReply extends Error {
}
}

export class SimpleError extends ErrorReply {}
export class SimpleError extends ErrorReply {
isUnknownSubcommand(): boolean {
return this.message.toLowerCase().indexOf('err unknown subcommand') !== -1;
}
}

export class BlobError extends ErrorReply {}

Expand Down
7 changes: 4 additions & 3 deletions packages/client/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist"
"outDir": "./dist",
},
"include": [
"./index.ts",
"./lib/**/*.ts"
"./lib/**/*.ts",
"./package.json"
],
"exclude": [
"./lib/test-utils.ts",
Expand All @@ -18,6 +19,6 @@
"./lib"
],
"entryPointStrategy": "expand",
"out": "../../documentation/client"
"out": "../../documentation/client",
}
}
3 changes: 2 additions & 1 deletion tsconfig.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"sourceMap": true,
"declaration": true,
"declarationMap": true,
"allowJs": true
"allowJs": true,
"resolveJsonModule": true
}
}
Loading