From 5596277f6f6249f397575f6b60c2285b5bc44b25 Mon Sep 17 00:00:00 2001 From: Ananda NORINDR Date: Thu, 5 Jan 2023 17:48:26 +0100 Subject: [PATCH 1/7] fix client info --- .../client/lib/commands/CLIENT_INFO.spec.ts | 48 ++++++++++- packages/client/lib/commands/CLIENT_INFO.ts | 82 +------------------ .../lib/commands/generic-transformers.ts | 80 ++++++++++++++++++ 3 files changed, 129 insertions(+), 81 deletions(-) diff --git a/packages/client/lib/commands/CLIENT_INFO.spec.ts b/packages/client/lib/commands/CLIENT_INFO.spec.ts index ee87df4a199..e8500fb5bcf 100644 --- a/packages/client/lib/commands/CLIENT_INFO.spec.ts +++ b/packages/client/lib/commands/CLIENT_INFO.spec.ts @@ -1,5 +1,6 @@ import { strict as assert } from 'assert'; import { transformArguments, transformReply } from './CLIENT_INFO'; +import testUtils, { GLOBAL } from '../test-utils'; describe('CLIENT INFO', () => { it('transformArguments', () => { @@ -11,7 +12,7 @@ describe('CLIENT INFO', () => { it('transformReply', () => { assert.deepEqual( - transformReply('id=526512 addr=127.0.0.1:36244 laddr=127.0.0.1:6379 fd=8 name= age=11213 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=40928 argv-mem=10 obl=0 oll=0 omem=0 tot-mem=61466 events=r cmd=client user=default redir=-1\n'), + transformReply('id=526512 addr=127.0.0.1:36244 laddr=127.0.0.1:6379 fd=8 name= age=11213 idle=0 flags=N db=0 sub=0 psub=0 ssub=0 multi=-1 qbuf=26 qbuf-free=40928 argv-mem=10 multi-mem=0 rbs=1024 rbp=0 obl=0 oll=0 omem=0 tot-mem=61466 events=r cmd=client user=default redir=-1 resp=2\n'), { id: 526512, addr: '127.0.0.1:36244', @@ -24,7 +25,9 @@ describe('CLIENT INFO', () => { db: 0, sub: 0, psub: 0, + ssub: 0, multi: -1, + multiMem: 0, qbuf: 26, qbufFree: 40928, argvMem: 10, @@ -35,8 +38,49 @@ describe('CLIENT INFO', () => { events: 'r', cmd: 'client', user: 'default', - redir: -1 + redir: -1, + resp: 2 } ); }); + + testUtils.testWithClient( + 'client.clientInfo', + async (client) => { + const reply = await client.clientInfo(); + assert.equal(typeof reply.id, 'number'); + assert.equal(typeof reply.addr, 'string'); + assert.equal(typeof reply.laddr, 'string'); + assert.equal(typeof reply.fd, 'number'); + assert.equal(typeof reply.name, 'string'); + assert.equal(typeof reply.age, 'number'); + assert.equal(typeof reply.idle, 'number'); + assert.equal(typeof reply.flags, 'string'); + assert.equal(typeof reply.db, 'number'); + assert.equal(typeof reply.sub, 'number'); + assert.equal(typeof reply.psub, 'number'); + assert.equal(typeof reply.multi, 'number'); + assert.equal(typeof reply.qbuf, 'number'); + assert.equal(typeof reply.qbufFree, 'number'); + assert.equal(typeof reply.argvMem, 'number'); + assert.equal(typeof reply.obl, 'number'); + assert.equal(typeof reply.oll, 'number'); + assert.equal(typeof reply.omem, 'number'); + assert.equal(typeof reply.totMem, 'number'); + assert.equal(typeof reply.events, 'string'); + assert.equal(typeof reply.cmd, 'string'); + assert.equal(typeof reply.user, 'string'); + assert.equal(typeof reply.redir, 'number'); + + if (testUtils.isVersionGreaterThan([7, 0])) { + assert.equal(typeof reply.multiMem, 'number'); + assert.equal(typeof reply.resp, 'number'); + } + + if (testUtils.isVersionGreaterThan([7, 0, 3])) { + assert.equal(typeof reply.ssub, 'number'); + } + }, + GLOBAL.SERVERS.OPEN + ); }); diff --git a/packages/client/lib/commands/CLIENT_INFO.ts b/packages/client/lib/commands/CLIENT_INFO.ts index 8dd30b70590..e7e3d2e38a8 100644 --- a/packages/client/lib/commands/CLIENT_INFO.ts +++ b/packages/client/lib/commands/CLIENT_INFO.ts @@ -1,85 +1,9 @@ +import { ClientInfoReply, transformClientInfoReply } from './generic-transformers'; + export function transformArguments(): Array { return ['CLIENT', 'INFO']; } -interface ClientInfoReply { - id: number; - addr: string; - laddr: string; - fd: number; - name: string; - age: number; - idle: number; - flags: string; - db: number; - sub: number; - psub: number; - multi: number; - qbuf: number; - qbufFree: number; - argvMem: number; - obl: number; - oll: number; - omem: number; - totMem: number; - events: string; - cmd: string; - user: string; - redir: number; -} - -const REGEX = /=([^\s]*)/g; - export function transformReply(reply: string): ClientInfoReply { - const [ - [, id], - [, addr], - [, laddr], - [, fd], - [, name], - [, age], - [, idle], - [, flags], - [, db], - [, sub], - [, psub], - [, multi], - [, qbuf], - [, qbufFree], - [, argvMem], - [, obl], - [, oll], - [, omem], - [, totMem], - [, events], - [, cmd], - [, user], - [, redir] - ] = [...reply.matchAll(REGEX)]; - - return { - id: Number(id), - addr, - laddr, - fd: Number(fd), - name, - age: Number(age), - idle: Number(idle), - flags, - db: Number(db), - sub: Number(sub), - psub: Number(psub), - multi: Number(multi), - qbuf: Number(qbuf), - qbufFree: Number(qbufFree), - argvMem: Number(argvMem), - obl: Number(obl), - oll: Number(oll), - omem: Number(omem), - totMem: Number(totMem), - events, - cmd, - user, - redir: Number(redir) - }; + return transformClientInfoReply(reply); } diff --git a/packages/client/lib/commands/generic-transformers.ts b/packages/client/lib/commands/generic-transformers.ts index d3a57a9346b..a6758deb410 100644 --- a/packages/client/lib/commands/generic-transformers.ts +++ b/packages/client/lib/commands/generic-transformers.ts @@ -688,3 +688,83 @@ export function transformRangeReply([start, end]: RawRangeReply): RangeReply { end }; } + +export type ClientInfoReply = { + id: number; + addr: string; + laddr: string; + fd: number; + name: string; + age: number; + idle: number; + flags: string; + db: number; + sub: number; + psub: number; + ssub?: number; // 7.0.3 + multi: number; + qbuf: number; + qbufFree: number; + argvMem: number; + multiMem?: number; // 7.0 + obl: number; + oll: number; + omem: number; + totMem: number; + events: string; + cmd: string; + user: string; + redir: number; + resp?: number; // 7.0 +}; + +export function transformClientInfoReply(reply: string): ClientInfoReply { + const REGEX = /([^\s=]+)=([^\s]*)/g; + const items = [...reply.matchAll(REGEX)]; + + const map: { [key: string]: string } = {}; + for (const item of items) { + const key = item[1].replace(/-([a-z])/g, (g) => g[1].toUpperCase()); + map[key] = item[2]; + } + + const clientInfoReply: ClientInfoReply = { + id: Number(map.id), + addr: map.addr, + laddr: map.laddr, + fd: Number(map.fd), + name: map.name, + age: Number(map.age), + idle: Number(map.idle), + flags: map.flags, + db: Number(map.db), + sub: Number(map.sub), + psub: Number(map.psub), + multi: Number(map.multi), + qbuf: Number(map.qbuf), + qbufFree: Number(map.qbufFree), + argvMem: Number(map.argvMem), + obl: Number(map.obl), + oll: Number(map.oll), + omem: Number(map.omem), + totMem: Number(map.totMem), + events: map.events, + cmd: map.cmd, + user: map.user, + redir: Number(map.redir) + }; + + if (map.ssub) { + clientInfoReply.ssub = Number(map.ssub); + } + + if (map.multiMem) { + clientInfoReply.multiMem = Number(map.multiMem); + } + + if (map.resp) { + clientInfoReply.resp = Number(map.resp); + } + + return clientInfoReply; +} From 00704abd3321d2435371246e110ffcf2edce6e05 Mon Sep 17 00:00:00 2001 From: Ananda NORINDR Date: Thu, 5 Jan 2023 17:48:36 +0100 Subject: [PATCH 2/7] add client list --- packages/client/lib/client/commands.ts | 3 + .../client/lib/commands/CLIENT_LIST.spec.ts | 127 ++++++++++++++++++ packages/client/lib/commands/CLIENT_LIST.ts | 43 ++++++ 3 files changed, 173 insertions(+) create mode 100644 packages/client/lib/commands/CLIENT_LIST.spec.ts create mode 100644 packages/client/lib/commands/CLIENT_LIST.ts diff --git a/packages/client/lib/client/commands.ts b/packages/client/lib/client/commands.ts index e164639ae91..e0a607cd525 100644 --- a/packages/client/lib/client/commands.ts +++ b/packages/client/lib/client/commands.ts @@ -21,6 +21,7 @@ import * as CLIENT_GETNAME from '../commands/CLIENT_GETNAME'; import * as CLIENT_GETREDIR from '../commands/CLIENT_GETREDIR'; import * as CLIENT_ID from '../commands/CLIENT_ID'; import * as CLIENT_KILL from '../commands/CLIENT_KILL'; +import * as CLIENT_LIST from '../commands/CLIENT_LIST'; import * as CLIENT_NO_EVICT from '../commands/CLIENT_NO-EVICT'; import * as CLIENT_PAUSE from '../commands/CLIENT_PAUSE'; import * as CLIENT_SETNAME from '../commands/CLIENT_SETNAME'; @@ -163,6 +164,8 @@ export default { clientKill: CLIENT_KILL, 'CLIENT_NO-EVICT': CLIENT_NO_EVICT, clientNoEvict: CLIENT_NO_EVICT, + CLIENT_LIST, + clientList: CLIENT_LIST, CLIENT_PAUSE, clientPause: CLIENT_PAUSE, CLIENT_SETNAME, diff --git a/packages/client/lib/commands/CLIENT_LIST.spec.ts b/packages/client/lib/commands/CLIENT_LIST.spec.ts new file mode 100644 index 00000000000..34458211ddb --- /dev/null +++ b/packages/client/lib/commands/CLIENT_LIST.spec.ts @@ -0,0 +1,127 @@ +import { strict as assert } from 'assert'; +import { transformArguments, transformReply } from './CLIENT_LIST'; +import testUtils, { GLOBAL } from '../test-utils'; + +describe('CLIENT LIST', () => { + describe('transformArguments', () => { + it('simple', () => { + assert.deepEqual(transformArguments(), ['CLIENT', 'LIST']); + }); + + it('with type', () => { + assert.deepEqual(transformArguments({ type: 'normal' }), ['CLIENT', 'LIST', 'TYPE', 'normal']); + }); + + it('with client id', () => { + assert.deepEqual(transformArguments({ id: ['1', '2'] }), ['CLIENT', 'LIST', 'ID', '1', '2']); + }); + }); + + it('transformReply', () => { + assert.deepEqual( + transformReply( + 'id=526512 addr=127.0.0.1:36244 laddr=127.0.0.1:6379 fd=8 name= age=11213 idle=0 flags=N db=0 sub=0 psub=0 ssub=0 multi=-1 qbuf=26 qbuf-free=40928 argv-mem=10 multi-mem=0 rbs=1024 rbp=0 obl=0 oll=0 omem=0 tot-mem=61466 events=r cmd=client user=default redir=-1 resp=2\nid=526513 addr=127.0.0.1:36244 laddr=127.0.0.1:6379 fd=8 name= age=11213 idle=0 flags=N db=0 sub=0 psub=0 ssub=0 multi=-1 qbuf=26 qbuf-free=40928 argv-mem=10 multi-mem=0 rbs=1024 rbp=0 obl=0 oll=0 omem=0 tot-mem=61466 events=r cmd=client user=default redir=-1 resp=2\n' + ), + [ + { + id: 526512, + addr: '127.0.0.1:36244', + laddr: '127.0.0.1:6379', + fd: 8, + name: '', + age: 11213, + idle: 0, + flags: 'N', + db: 0, + sub: 0, + psub: 0, + ssub: 0, + multi: -1, + multiMem: 0, + qbuf: 26, + qbufFree: 40928, + argvMem: 10, + obl: 0, + oll: 0, + omem: 0, + totMem: 61466, + events: 'r', + cmd: 'client', + user: 'default', + redir: -1, + resp: 2 + }, + { + id: 526513, + addr: '127.0.0.1:36244', + laddr: '127.0.0.1:6379', + fd: 8, + name: '', + age: 11213, + idle: 0, + flags: 'N', + db: 0, + sub: 0, + psub: 0, + ssub: 0, + multi: -1, + multiMem: 0, + qbuf: 26, + qbufFree: 40928, + argvMem: 10, + obl: 0, + oll: 0, + omem: 0, + totMem: 61466, + events: 'r', + cmd: 'client', + user: 'default', + redir: -1, + resp: 2 + } + ] + ); + }); + + testUtils.testWithClient( + 'client.clientList', + async (client) => { + const reply = await client.clientList(); + assert.ok(Array.isArray(reply)); + + assert.equal(typeof reply[0].id, 'number'); + assert.equal(typeof reply[0].addr, 'string'); + assert.equal(typeof reply[0].laddr, 'string'); + assert.equal(typeof reply[0].fd, 'number'); + assert.equal(typeof reply[0].name, 'string'); + assert.equal(typeof reply[0].age, 'number'); + assert.equal(typeof reply[0].idle, 'number'); + assert.equal(typeof reply[0].flags, 'string'); + assert.equal(typeof reply[0].db, 'number'); + assert.equal(typeof reply[0].sub, 'number'); + assert.equal(typeof reply[0].psub, 'number'); + assert.equal(typeof reply[0].multi, 'number'); + assert.equal(typeof reply[0].qbuf, 'number'); + assert.equal(typeof reply[0].qbufFree, 'number'); + assert.equal(typeof reply[0].argvMem, 'number'); + assert.equal(typeof reply[0].obl, 'number'); + assert.equal(typeof reply[0].oll, 'number'); + assert.equal(typeof reply[0].omem, 'number'); + assert.equal(typeof reply[0].totMem, 'number'); + assert.equal(typeof reply[0].events, 'string'); + assert.equal(typeof reply[0].cmd, 'string'); + assert.equal(typeof reply[0].user, 'string'); + assert.equal(typeof reply[0].redir, 'number'); + + if (testUtils.isVersionGreaterThan([7, 0])) { + assert.equal(typeof reply[0].multiMem, 'number'); + assert.equal(typeof reply[0].resp, 'number'); + } + + if (testUtils.isVersionGreaterThan([7, 0, 3])) { + assert.equal(typeof reply[0].ssub, 'number'); + } + }, + GLOBAL.SERVERS.OPEN + ); +}); diff --git a/packages/client/lib/commands/CLIENT_LIST.ts b/packages/client/lib/commands/CLIENT_LIST.ts new file mode 100644 index 00000000000..0cacd9ffa8d --- /dev/null +++ b/packages/client/lib/commands/CLIENT_LIST.ts @@ -0,0 +1,43 @@ +import { RedisCommandArguments, RedisCommandArgument } from '.'; +import { ClientInfoReply, transformClientInfoReply } from './generic-transformers'; + +interface ListFilterType { + type: 'normal' | 'master' | 'replica' | 'pubsub'; + id?: never; +} +interface ListFilterId { + id: Array; + type?: never; +} + +export type ListFilter = ListFilterType | ListFilterId; + +export function transformArguments(filter?: ListFilter): RedisCommandArguments { + const args: RedisCommandArguments = ['CLIENT', 'LIST']; + + if (filter) { + if (isFilterType(filter)) { + args.push('TYPE', filter.type); + } + + if (isFilterId(filter)) { + args.push('ID', ...filter.id); + } + } + + return args; +} + +function isFilterType(filter?: ListFilter): filter is ListFilterType { + return (filter as ListFilterType)?.type !== undefined; +} + +function isFilterId(filter?: ListFilter): filter is ListFilterId { + return (filter as ListFilterId)?.id !== undefined; +} + +export function transformReply(reply: string): Array { + const REGEX = /([^\n]+)/g; + const items = [...reply.matchAll(REGEX)]; + return items.map((item) => transformClientInfoReply(item[1])); +} From fe69efa1640d213dccbfe3f1b97076295db9d338 Mon Sep 17 00:00:00 2001 From: Ananda NORINDR Date: Thu, 5 Jan 2023 17:54:34 +0100 Subject: [PATCH 3/7] fix key validation in transformClientInfoReply --- packages/client/lib/commands/generic-transformers.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/client/lib/commands/generic-transformers.ts b/packages/client/lib/commands/generic-transformers.ts index a6758deb410..df8ff634d13 100644 --- a/packages/client/lib/commands/generic-transformers.ts +++ b/packages/client/lib/commands/generic-transformers.ts @@ -754,15 +754,15 @@ export function transformClientInfoReply(reply: string): ClientInfoReply { redir: Number(map.redir) }; - if (map.ssub) { + if (map.ssub !== undefined) { clientInfoReply.ssub = Number(map.ssub); } - if (map.multiMem) { + if (map.multiMem !== undefined) { clientInfoReply.multiMem = Number(map.multiMem); } - if (map.resp) { + if (map.resp !== undefined) { clientInfoReply.resp = Number(map.resp); } From cfc1d20712777ce2316464e33175419b7fe25344 Mon Sep 17 00:00:00 2001 From: Ananda NORINDR Date: Thu, 5 Jan 2023 20:38:06 +0100 Subject: [PATCH 4/7] fix issue with field in CLIENT LIST reply --- .../client/lib/commands/CLIENT_INFO.spec.ts | 2 ++ .../client/lib/commands/CLIENT_LIST.spec.ts | 16 +++++++++----- .../lib/commands/generic-transformers.ts | 22 ++++++++++++------- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/packages/client/lib/commands/CLIENT_INFO.spec.ts b/packages/client/lib/commands/CLIENT_INFO.spec.ts index e8500fb5bcf..6e13ec73e22 100644 --- a/packages/client/lib/commands/CLIENT_INFO.spec.ts +++ b/packages/client/lib/commands/CLIENT_INFO.spec.ts @@ -3,6 +3,8 @@ import { transformArguments, transformReply } from './CLIENT_INFO'; import testUtils, { GLOBAL } from '../test-utils'; describe('CLIENT INFO', () => { + testUtils.isVersionGreaterThanHook([6, 2]); + it('transformArguments', () => { assert.deepEqual( transformArguments(), diff --git a/packages/client/lib/commands/CLIENT_LIST.spec.ts b/packages/client/lib/commands/CLIENT_LIST.spec.ts index 34458211ddb..3a19db7e8ce 100644 --- a/packages/client/lib/commands/CLIENT_LIST.spec.ts +++ b/packages/client/lib/commands/CLIENT_LIST.spec.ts @@ -91,7 +91,6 @@ describe('CLIENT LIST', () => { assert.equal(typeof reply[0].id, 'number'); assert.equal(typeof reply[0].addr, 'string'); - assert.equal(typeof reply[0].laddr, 'string'); assert.equal(typeof reply[0].fd, 'number'); assert.equal(typeof reply[0].name, 'string'); assert.equal(typeof reply[0].age, 'number'); @@ -103,15 +102,22 @@ describe('CLIENT LIST', () => { assert.equal(typeof reply[0].multi, 'number'); assert.equal(typeof reply[0].qbuf, 'number'); assert.equal(typeof reply[0].qbufFree, 'number'); - assert.equal(typeof reply[0].argvMem, 'number'); assert.equal(typeof reply[0].obl, 'number'); assert.equal(typeof reply[0].oll, 'number'); assert.equal(typeof reply[0].omem, 'number'); - assert.equal(typeof reply[0].totMem, 'number'); assert.equal(typeof reply[0].events, 'string'); assert.equal(typeof reply[0].cmd, 'string'); - assert.equal(typeof reply[0].user, 'string'); - assert.equal(typeof reply[0].redir, 'number'); + + if (testUtils.isVersionGreaterThan([6, 0])) { + assert.equal(typeof reply[0].argvMem, 'number'); + assert.equal(typeof reply[0].totMem, 'number'); + assert.equal(typeof reply[0].user, 'string'); + } + + if (testUtils.isVersionGreaterThan([6, 2])) { + assert.equal(typeof reply[0].redir, 'number'); + assert.equal(typeof reply[0].laddr, 'string'); + } if (testUtils.isVersionGreaterThan([7, 0])) { assert.equal(typeof reply[0].multiMem, 'number'); diff --git a/packages/client/lib/commands/generic-transformers.ts b/packages/client/lib/commands/generic-transformers.ts index df8ff634d13..3a921858b8a 100644 --- a/packages/client/lib/commands/generic-transformers.ts +++ b/packages/client/lib/commands/generic-transformers.ts @@ -692,7 +692,7 @@ export function transformRangeReply([start, end]: RawRangeReply): RangeReply { export type ClientInfoReply = { id: number; addr: string; - laddr: string; + laddr?: string; // 6.2 fd: number; name: string; age: number; @@ -705,16 +705,16 @@ export type ClientInfoReply = { multi: number; qbuf: number; qbufFree: number; - argvMem: number; + argvMem?: number; // 6.0 multiMem?: number; // 7.0 obl: number; oll: number; omem: number; - totMem: number; + totMem?: number; // 6.0 events: string; cmd: string; - user: string; - redir: number; + user?: string; // 6.0 + redir?: number; // 6.2 resp?: number; // 7.0 }; @@ -731,7 +731,6 @@ export function transformClientInfoReply(reply: string): ClientInfoReply { const clientInfoReply: ClientInfoReply = { id: Number(map.id), addr: map.addr, - laddr: map.laddr, fd: Number(map.fd), name: map.name, age: Number(map.age), @@ -750,10 +749,17 @@ export function transformClientInfoReply(reply: string): ClientInfoReply { totMem: Number(map.totMem), events: map.events, cmd: map.cmd, - user: map.user, - redir: Number(map.redir) + user: map.user }; + if (map.laddr !== undefined) { + clientInfoReply.laddr = map.laddr; + } + + if (map.redir !== undefined) { + clientInfoReply.redir = Number(map.redir); + } + if (map.ssub !== undefined) { clientInfoReply.ssub = Number(map.ssub); } From a235d1b993ad49b23732fbec06281eb1c7da5676 Mon Sep 17 00:00:00 2001 From: Leibale Date: Mon, 23 Jan 2023 17:50:00 -0500 Subject: [PATCH 5/7] clean code --- .../client/lib/commands/CLIENT_INFO.spec.ts | 104 ++++-------- packages/client/lib/commands/CLIENT_INFO.ts | 84 +++++++++- .../client/lib/commands/CLIENT_LIST.spec.ts | 155 ++++++------------ packages/client/lib/commands/CLIENT_LIST.ts | 48 +++--- .../lib/commands/generic-transformers.ts | 86 ---------- 5 files changed, 189 insertions(+), 288 deletions(-) diff --git a/packages/client/lib/commands/CLIENT_INFO.spec.ts b/packages/client/lib/commands/CLIENT_INFO.spec.ts index 6e13ec73e22..ccb99017cf3 100644 --- a/packages/client/lib/commands/CLIENT_INFO.spec.ts +++ b/packages/client/lib/commands/CLIENT_INFO.spec.ts @@ -12,77 +12,39 @@ describe('CLIENT INFO', () => { ); }); - it('transformReply', () => { - assert.deepEqual( - transformReply('id=526512 addr=127.0.0.1:36244 laddr=127.0.0.1:6379 fd=8 name= age=11213 idle=0 flags=N db=0 sub=0 psub=0 ssub=0 multi=-1 qbuf=26 qbuf-free=40928 argv-mem=10 multi-mem=0 rbs=1024 rbp=0 obl=0 oll=0 omem=0 tot-mem=61466 events=r cmd=client user=default redir=-1 resp=2\n'), - { - id: 526512, - addr: '127.0.0.1:36244', - laddr: '127.0.0.1:6379', - fd: 8, - name: '', - age: 11213, - idle: 0, - flags: 'N', - db: 0, - sub: 0, - psub: 0, - ssub: 0, - multi: -1, - multiMem: 0, - qbuf: 26, - qbufFree: 40928, - argvMem: 10, - obl: 0, - oll: 0, - omem: 0, - totMem: 61466, - events: 'r', - cmd: 'client', - user: 'default', - redir: -1, - resp: 2 - } - ); - }); - - testUtils.testWithClient( - 'client.clientInfo', - async (client) => { - const reply = await client.clientInfo(); - assert.equal(typeof reply.id, 'number'); - assert.equal(typeof reply.addr, 'string'); - assert.equal(typeof reply.laddr, 'string'); - assert.equal(typeof reply.fd, 'number'); - assert.equal(typeof reply.name, 'string'); - assert.equal(typeof reply.age, 'number'); - assert.equal(typeof reply.idle, 'number'); - assert.equal(typeof reply.flags, 'string'); - assert.equal(typeof reply.db, 'number'); - assert.equal(typeof reply.sub, 'number'); - assert.equal(typeof reply.psub, 'number'); - assert.equal(typeof reply.multi, 'number'); - assert.equal(typeof reply.qbuf, 'number'); - assert.equal(typeof reply.qbufFree, 'number'); - assert.equal(typeof reply.argvMem, 'number'); - assert.equal(typeof reply.obl, 'number'); - assert.equal(typeof reply.oll, 'number'); - assert.equal(typeof reply.omem, 'number'); - assert.equal(typeof reply.totMem, 'number'); - assert.equal(typeof reply.events, 'string'); - assert.equal(typeof reply.cmd, 'string'); - assert.equal(typeof reply.user, 'string'); - assert.equal(typeof reply.redir, 'number'); + testUtils.testWithClient('client.clientInfo', async client => { + const reply = await client.clientInfo(); + assert.equal(typeof reply.id, 'number'); + assert.equal(typeof reply.addr, 'string'); + assert.equal(typeof reply.laddr, 'string'); + assert.equal(typeof reply.fd, 'number'); + assert.equal(typeof reply.name, 'string'); + assert.equal(typeof reply.age, 'number'); + assert.equal(typeof reply.idle, 'number'); + assert.equal(typeof reply.flags, 'string'); + assert.equal(typeof reply.db, 'number'); + assert.equal(typeof reply.sub, 'number'); + assert.equal(typeof reply.psub, 'number'); + assert.equal(typeof reply.multi, 'number'); + assert.equal(typeof reply.qbuf, 'number'); + assert.equal(typeof reply.qbufFree, 'number'); + assert.equal(typeof reply.argvMem, 'number'); + assert.equal(typeof reply.obl, 'number'); + assert.equal(typeof reply.oll, 'number'); + assert.equal(typeof reply.omem, 'number'); + assert.equal(typeof reply.totMem, 'number'); + assert.equal(typeof reply.events, 'string'); + assert.equal(typeof reply.cmd, 'string'); + assert.equal(typeof reply.user, 'string'); + assert.equal(typeof reply.redir, 'number'); - if (testUtils.isVersionGreaterThan([7, 0])) { - assert.equal(typeof reply.multiMem, 'number'); - assert.equal(typeof reply.resp, 'number'); - } + if (testUtils.isVersionGreaterThan([7, 0])) { + assert.equal(typeof reply.multiMem, 'number'); + assert.equal(typeof reply.resp, 'number'); + } - if (testUtils.isVersionGreaterThan([7, 0, 3])) { - assert.equal(typeof reply.ssub, 'number'); - } - }, - GLOBAL.SERVERS.OPEN - ); + if (testUtils.isVersionGreaterThan([7, 0, 3])) { + assert.equal(typeof reply.ssub, 'number'); + } + }, GLOBAL.SERVERS.OPEN); }); diff --git a/packages/client/lib/commands/CLIENT_INFO.ts b/packages/client/lib/commands/CLIENT_INFO.ts index e7e3d2e38a8..146cbde1282 100644 --- a/packages/client/lib/commands/CLIENT_INFO.ts +++ b/packages/client/lib/commands/CLIENT_INFO.ts @@ -1,9 +1,89 @@ -import { ClientInfoReply, transformClientInfoReply } from './generic-transformers'; +export const IS_READ_ONLY = true; export function transformArguments(): Array { return ['CLIENT', 'INFO']; } +export interface ClientInfoReply { + id: number; + addr: string; + laddr?: string; // 6.2 + fd: number; + name: string; + age: number; + idle: number; + flags: string; + db: number; + sub: number; + psub: number; + ssub?: number; // 7.0.3 + multi: number; + qbuf: number; + qbufFree: number; + argvMem?: number; // 6.0 + multiMem?: number; // 7.0 + obl: number; + oll: number; + omem: number; + totMem?: number; // 6.0 + events: string; + cmd: string; + user?: string; // 6.0 + redir?: number; // 6.2 + resp?: number; // 7.0 +} + +const CLIENT_INFO_REGEX = /([^\s=]+)=([^\s]*)/g; + export function transformReply(reply: string): ClientInfoReply { - return transformClientInfoReply(reply); + const map: Record = {}; + for (const item of reply.matchAll(CLIENT_INFO_REGEX)) { + map[item[1]] = item[2]; + } + + const clientInfoReply: ClientInfoReply = { + id: Number(map.id), + addr: map.addr, + fd: Number(map.fd), + name: map.name, + age: Number(map.age), + idle: Number(map.idle), + flags: map.flags, + db: Number(map.db), + sub: Number(map.sub), + psub: Number(map.psub), + multi: Number(map.multi), + qbuf: Number(map.qbuf), + qbufFree: Number(map.qbuffree), + argvMem: Number(map.argvmem), + obl: Number(map.obl), + oll: Number(map.oll), + omem: Number(map.omem), + totMem: Number(map.totmem), + events: map.events, + cmd: map.cmd, + user: map.user + }; + + if (map.laddr !== undefined) { + clientInfoReply.laddr = map.laddr; + } + + if (map.redir !== undefined) { + clientInfoReply.redir = Number(map.redir); + } + + if (map.ssub !== undefined) { + clientInfoReply.ssub = Number(map.ssub); + } + + if (map.multiMem !== undefined) { + clientInfoReply.multiMem = Number(map.multimem); + } + + if (map.resp !== undefined) { + clientInfoReply.resp = Number(map.resp); + } + + return clientInfoReply; } diff --git a/packages/client/lib/commands/CLIENT_LIST.spec.ts b/packages/client/lib/commands/CLIENT_LIST.spec.ts index 3a19db7e8ce..c9c720e12ef 100644 --- a/packages/client/lib/commands/CLIENT_LIST.spec.ts +++ b/packages/client/lib/commands/CLIENT_LIST.spec.ts @@ -5,129 +5,74 @@ import testUtils, { GLOBAL } from '../test-utils'; describe('CLIENT LIST', () => { describe('transformArguments', () => { it('simple', () => { - assert.deepEqual(transformArguments(), ['CLIENT', 'LIST']); + assert.deepEqual( + transformArguments(), + ['CLIENT', 'LIST'] + ); }); - it('with type', () => { - assert.deepEqual(transformArguments({ type: 'normal' }), ['CLIENT', 'LIST', 'TYPE', 'normal']); + it('with TYPE', () => { + assert.deepEqual( + transformArguments({ + TYPE: 'NORMAL' + }), + ['CLIENT', 'LIST', 'TYPE', 'NORMAL'] + ); }); - it('with client id', () => { - assert.deepEqual(transformArguments({ id: ['1', '2'] }), ['CLIENT', 'LIST', 'ID', '1', '2']); + it('with ID', () => { + assert.deepEqual( + transformArguments({ + ID: ['1', '2'] + }), + ['CLIENT', 'LIST', 'ID', '1', '2'] + ); }); }); - it('transformReply', () => { - assert.deepEqual( - transformReply( - 'id=526512 addr=127.0.0.1:36244 laddr=127.0.0.1:6379 fd=8 name= age=11213 idle=0 flags=N db=0 sub=0 psub=0 ssub=0 multi=-1 qbuf=26 qbuf-free=40928 argv-mem=10 multi-mem=0 rbs=1024 rbp=0 obl=0 oll=0 omem=0 tot-mem=61466 events=r cmd=client user=default redir=-1 resp=2\nid=526513 addr=127.0.0.1:36244 laddr=127.0.0.1:6379 fd=8 name= age=11213 idle=0 flags=N db=0 sub=0 psub=0 ssub=0 multi=-1 qbuf=26 qbuf-free=40928 argv-mem=10 multi-mem=0 rbs=1024 rbp=0 obl=0 oll=0 omem=0 tot-mem=61466 events=r cmd=client user=default redir=-1 resp=2\n' - ), - [ - { - id: 526512, - addr: '127.0.0.1:36244', - laddr: '127.0.0.1:6379', - fd: 8, - name: '', - age: 11213, - idle: 0, - flags: 'N', - db: 0, - sub: 0, - psub: 0, - ssub: 0, - multi: -1, - multiMem: 0, - qbuf: 26, - qbufFree: 40928, - argvMem: 10, - obl: 0, - oll: 0, - omem: 0, - totMem: 61466, - events: 'r', - cmd: 'client', - user: 'default', - redir: -1, - resp: 2 - }, - { - id: 526513, - addr: '127.0.0.1:36244', - laddr: '127.0.0.1:6379', - fd: 8, - name: '', - age: 11213, - idle: 0, - flags: 'N', - db: 0, - sub: 0, - psub: 0, - ssub: 0, - multi: -1, - multiMem: 0, - qbuf: 26, - qbufFree: 40928, - argvMem: 10, - obl: 0, - oll: 0, - omem: 0, - totMem: 61466, - events: 'r', - cmd: 'client', - user: 'default', - redir: -1, - resp: 2 - } - ] - ); - }); - - testUtils.testWithClient( - 'client.clientList', - async (client) => { - const reply = await client.clientList(); - assert.ok(Array.isArray(reply)); + testUtils.testWithClient('client.clientList', async client => { + const reply = await client.clientList(); + assert.ok(Array.isArray(reply)); - assert.equal(typeof reply[0].id, 'number'); - assert.equal(typeof reply[0].addr, 'string'); - assert.equal(typeof reply[0].fd, 'number'); - assert.equal(typeof reply[0].name, 'string'); - assert.equal(typeof reply[0].age, 'number'); - assert.equal(typeof reply[0].idle, 'number'); - assert.equal(typeof reply[0].flags, 'string'); - assert.equal(typeof reply[0].db, 'number'); - assert.equal(typeof reply[0].sub, 'number'); - assert.equal(typeof reply[0].psub, 'number'); - assert.equal(typeof reply[0].multi, 'number'); - assert.equal(typeof reply[0].qbuf, 'number'); - assert.equal(typeof reply[0].qbufFree, 'number'); - assert.equal(typeof reply[0].obl, 'number'); - assert.equal(typeof reply[0].oll, 'number'); - assert.equal(typeof reply[0].omem, 'number'); - assert.equal(typeof reply[0].events, 'string'); - assert.equal(typeof reply[0].cmd, 'string'); + for (const item of reply) { + assert.equal(typeof item.id, 'number'); + assert.equal(typeof item.addr, 'string'); + assert.equal(typeof item.fd, 'number'); + assert.equal(typeof item.name, 'string'); + assert.equal(typeof item.age, 'number'); + assert.equal(typeof item.idle, 'number'); + assert.equal(typeof item.flags, 'string'); + assert.equal(typeof item.db, 'number'); + assert.equal(typeof item.sub, 'number'); + assert.equal(typeof item.psub, 'number'); + assert.equal(typeof item.multi, 'number'); + assert.equal(typeof item.qbuf, 'number'); + assert.equal(typeof item.qbufFree, 'number'); + assert.equal(typeof item.obl, 'number'); + assert.equal(typeof item.oll, 'number'); + assert.equal(typeof item.omem, 'number'); + assert.equal(typeof item.events, 'string'); + assert.equal(typeof item.cmd, 'string'); if (testUtils.isVersionGreaterThan([6, 0])) { - assert.equal(typeof reply[0].argvMem, 'number'); - assert.equal(typeof reply[0].totMem, 'number'); - assert.equal(typeof reply[0].user, 'string'); + assert.equal(typeof item.argvMem, 'number'); + assert.equal(typeof item.totMem, 'number'); + assert.equal(typeof item.user, 'string'); } if (testUtils.isVersionGreaterThan([6, 2])) { - assert.equal(typeof reply[0].redir, 'number'); - assert.equal(typeof reply[0].laddr, 'string'); + assert.equal(typeof item.redir, 'number'); + assert.equal(typeof item.laddr, 'string'); } if (testUtils.isVersionGreaterThan([7, 0])) { - assert.equal(typeof reply[0].multiMem, 'number'); - assert.equal(typeof reply[0].resp, 'number'); + assert.equal(typeof item.multiMem, 'number'); + assert.equal(typeof item.resp, 'number'); } if (testUtils.isVersionGreaterThan([7, 0, 3])) { - assert.equal(typeof reply[0].ssub, 'number'); + assert.equal(typeof item.ssub, 'number'); } - }, - GLOBAL.SERVERS.OPEN - ); + } + }, GLOBAL.SERVERS.OPEN); }); diff --git a/packages/client/lib/commands/CLIENT_LIST.ts b/packages/client/lib/commands/CLIENT_LIST.ts index 0cacd9ffa8d..6f71dc7d999 100644 --- a/packages/client/lib/commands/CLIENT_LIST.ts +++ b/packages/client/lib/commands/CLIENT_LIST.ts @@ -1,43 +1,43 @@ import { RedisCommandArguments, RedisCommandArgument } from '.'; -import { ClientInfoReply, transformClientInfoReply } from './generic-transformers'; +import { pushVerdictArguments } from './generic-transformers'; +import { transformReply as transformClientInfoReply, ClientInfoReply } from './CLIENT_INFO'; interface ListFilterType { - type: 'normal' | 'master' | 'replica' | 'pubsub'; - id?: never; + TYPE: 'NORMAL' | 'MASTER' | 'REPLICA' | 'PUBSUB'; + ID?: never; } + interface ListFilterId { - id: Array; - type?: never; + ID: Array; + TYPE?: never; } export type ListFilter = ListFilterType | ListFilterId; +export const IS_READ_ONLY = true; + export function transformArguments(filter?: ListFilter): RedisCommandArguments { - const args: RedisCommandArguments = ['CLIENT', 'LIST']; + let args: RedisCommandArguments = ['CLIENT', 'LIST']; if (filter) { - if (isFilterType(filter)) { - args.push('TYPE', filter.type); - } - - if (isFilterId(filter)) { - args.push('ID', ...filter.id); + if (filter.TYPE !== undefined) { + args.push('TYPE', filter.TYPE); + } else { + args.push('ID'); + args = pushVerdictArguments(args, filter.ID); } } return args; } -function isFilterType(filter?: ListFilter): filter is ListFilterType { - return (filter as ListFilterType)?.type !== undefined; -} - -function isFilterId(filter?: ListFilter): filter is ListFilterId { - return (filter as ListFilterId)?.id !== undefined; -} - -export function transformReply(reply: string): Array { - const REGEX = /([^\n]+)/g; - const items = [...reply.matchAll(REGEX)]; - return items.map((item) => transformClientInfoReply(item[1])); +export function transformReply(rawReply: string): Array { + const split = rawReply.split('\n'), + length = split.length - 1, + reply: Array = []; + for (let i = 0; i < length; i++) { + reply.push(transformClientInfoReply(split[i])); + } + + return reply; } diff --git a/packages/client/lib/commands/generic-transformers.ts b/packages/client/lib/commands/generic-transformers.ts index 3a921858b8a..d3a57a9346b 100644 --- a/packages/client/lib/commands/generic-transformers.ts +++ b/packages/client/lib/commands/generic-transformers.ts @@ -688,89 +688,3 @@ export function transformRangeReply([start, end]: RawRangeReply): RangeReply { end }; } - -export type ClientInfoReply = { - id: number; - addr: string; - laddr?: string; // 6.2 - fd: number; - name: string; - age: number; - idle: number; - flags: string; - db: number; - sub: number; - psub: number; - ssub?: number; // 7.0.3 - multi: number; - qbuf: number; - qbufFree: number; - argvMem?: number; // 6.0 - multiMem?: number; // 7.0 - obl: number; - oll: number; - omem: number; - totMem?: number; // 6.0 - events: string; - cmd: string; - user?: string; // 6.0 - redir?: number; // 6.2 - resp?: number; // 7.0 -}; - -export function transformClientInfoReply(reply: string): ClientInfoReply { - const REGEX = /([^\s=]+)=([^\s]*)/g; - const items = [...reply.matchAll(REGEX)]; - - const map: { [key: string]: string } = {}; - for (const item of items) { - const key = item[1].replace(/-([a-z])/g, (g) => g[1].toUpperCase()); - map[key] = item[2]; - } - - const clientInfoReply: ClientInfoReply = { - id: Number(map.id), - addr: map.addr, - fd: Number(map.fd), - name: map.name, - age: Number(map.age), - idle: Number(map.idle), - flags: map.flags, - db: Number(map.db), - sub: Number(map.sub), - psub: Number(map.psub), - multi: Number(map.multi), - qbuf: Number(map.qbuf), - qbufFree: Number(map.qbufFree), - argvMem: Number(map.argvMem), - obl: Number(map.obl), - oll: Number(map.oll), - omem: Number(map.omem), - totMem: Number(map.totMem), - events: map.events, - cmd: map.cmd, - user: map.user - }; - - if (map.laddr !== undefined) { - clientInfoReply.laddr = map.laddr; - } - - if (map.redir !== undefined) { - clientInfoReply.redir = Number(map.redir); - } - - if (map.ssub !== undefined) { - clientInfoReply.ssub = Number(map.ssub); - } - - if (map.multiMem !== undefined) { - clientInfoReply.multiMem = Number(map.multiMem); - } - - if (map.resp !== undefined) { - clientInfoReply.resp = Number(map.resp); - } - - return clientInfoReply; -} From 5fe73a7bfb0532cc6838446e253c8bca6a8a9508 Mon Sep 17 00:00:00 2001 From: Leibale Eidelman Date: Mon, 23 Jan 2023 18:02:51 -0500 Subject: [PATCH 6/7] fix multimem --- packages/client/lib/commands/CLIENT_INFO.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/lib/commands/CLIENT_INFO.ts b/packages/client/lib/commands/CLIENT_INFO.ts index 146cbde1282..b74b9751fac 100644 --- a/packages/client/lib/commands/CLIENT_INFO.ts +++ b/packages/client/lib/commands/CLIENT_INFO.ts @@ -77,7 +77,7 @@ export function transformReply(reply: string): ClientInfoReply { clientInfoReply.ssub = Number(map.ssub); } - if (map.multiMem !== undefined) { + if (map.multimem !== undefined) { clientInfoReply.multiMem = Number(map.multimem); } From eec2e2268afd50d830ef7675d86f77ea7d721715 Mon Sep 17 00:00:00 2001 From: Leibale Date: Mon, 23 Jan 2023 18:34:39 -0500 Subject: [PATCH 7/7] fix qbufFree argvMem totMem multiMem --- packages/client/lib/commands/CLIENT_INFO.ts | 26 ++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/client/lib/commands/CLIENT_INFO.ts b/packages/client/lib/commands/CLIENT_INFO.ts index b74b9751fac..7f6b6e1884e 100644 --- a/packages/client/lib/commands/CLIENT_INFO.ts +++ b/packages/client/lib/commands/CLIENT_INFO.ts @@ -35,13 +35,13 @@ export interface ClientInfoReply { const CLIENT_INFO_REGEX = /([^\s=]+)=([^\s]*)/g; -export function transformReply(reply: string): ClientInfoReply { +export function transformReply(rawReply: string): ClientInfoReply { const map: Record = {}; - for (const item of reply.matchAll(CLIENT_INFO_REGEX)) { + for (const item of rawReply.matchAll(CLIENT_INFO_REGEX)) { map[item[1]] = item[2]; } - const clientInfoReply: ClientInfoReply = { + const reply: ClientInfoReply = { id: Number(map.id), addr: map.addr, fd: Number(map.fd), @@ -54,36 +54,36 @@ export function transformReply(reply: string): ClientInfoReply { psub: Number(map.psub), multi: Number(map.multi), qbuf: Number(map.qbuf), - qbufFree: Number(map.qbuffree), - argvMem: Number(map.argvmem), + qbufFree: Number(map['qbuf-free']), + argvMem: Number(map['argv-mem']), obl: Number(map.obl), oll: Number(map.oll), omem: Number(map.omem), - totMem: Number(map.totmem), + totMem: Number(map['tot-mem']), events: map.events, cmd: map.cmd, user: map.user }; if (map.laddr !== undefined) { - clientInfoReply.laddr = map.laddr; + reply.laddr = map.laddr; } if (map.redir !== undefined) { - clientInfoReply.redir = Number(map.redir); + reply.redir = Number(map.redir); } if (map.ssub !== undefined) { - clientInfoReply.ssub = Number(map.ssub); + reply.ssub = Number(map.ssub); } - if (map.multimem !== undefined) { - clientInfoReply.multiMem = Number(map.multimem); + if (map['multi-mem'] !== undefined) { + reply.multiMem = Number(map['multi-mem']); } if (map.resp !== undefined) { - clientInfoReply.resp = Number(map.resp); + reply.resp = Number(map.resp); } - return clientInfoReply; + return reply; }