Skip to content

Commit 78075ec

Browse files
fix: ensure CSR works with the ioredis package
1 parent d2d635d commit 78075ec

File tree

2 files changed

+85
-27
lines changed

2 files changed

+85
-27
lines changed

lib/adapter.ts

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import type {
99
} from "socket.io-adapter";
1010
import { decode, encode } from "@msgpack/msgpack";
1111
import debugModule from "debug";
12-
import { hasBinary, XADD, XREAD } from "./util";
12+
import { hasBinary, GETDEL, SET, XADD, XRANGE, XREAD } from "./util";
1313

1414
const debug = debugModule("socket.io-redis-streams-adapter");
1515

@@ -235,9 +235,12 @@ class RedisStreamsAdapter extends ClusterAdapterWithHeartbeat {
235235
const sessionKey = this.#opts.sessionKeyPrefix + session.pid;
236236
const encodedSession = Buffer.from(encode(session)).toString("base64");
237237

238-
this.#redisClient.set(sessionKey, encodedSession, {
239-
PX: this.nsp.server.opts.connectionStateRecovery.maxDisconnectionDuration,
240-
});
238+
SET(
239+
this.#redisClient,
240+
sessionKey,
241+
encodedSession,
242+
this.nsp.server.opts.connectionStateRecovery.maxDisconnectionDuration
243+
);
241244
}
242245

243246
override async restoreSession(
@@ -253,12 +256,8 @@ class RedisStreamsAdapter extends ClusterAdapterWithHeartbeat {
253256
const sessionKey = this.#opts.sessionKeyPrefix + pid;
254257

255258
const results = await Promise.all([
256-
this.#redisClient
257-
.multi()
258-
.get(sessionKey)
259-
.del(sessionKey) // GETDEL was added in Redis version 6.2
260-
.exec(),
261-
this.#redisClient.xRange(this.#opts.streamName, offset, offset),
259+
GETDEL(this.#redisClient, sessionKey),
260+
XRANGE(this.#redisClient, this.#opts.streamName, offset, offset),
262261
]);
263262

264263
const rawSession = results[0][0];
@@ -277,13 +276,11 @@ class RedisStreamsAdapter extends ClusterAdapterWithHeartbeat {
277276
// FIXME we need to add an arbitrary limit here, because if entries are added faster than what we can consume, then
278277
// we will loop endlessly. But if we stop before reaching the end of the stream, we might lose messages.
279278
for (let i = 0; i < RESTORE_SESSION_MAX_XRANGE_CALLS; i++) {
280-
const entries = await this.#redisClient.xRange(
279+
const entries = await XRANGE(
280+
this.#redisClient,
281281
this.#opts.streamName,
282282
RedisStreamsAdapter.nextOffset(offset),
283-
"+",
284-
{
285-
COUNT: this.#opts.readCount,
286-
}
283+
"+"
287284
);
288285

289286
if (entries.length === 0) {

lib/util.ts

Lines changed: 73 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,23 @@ function isRedisV4Client(redisClient: any) {
4747
return typeof redisClient.sSubscribe === "function";
4848
}
4949

50+
/**
51+
* Map the output of the XREAD/XRANGE command with the ioredis package to the format of the redis package
52+
* @param result
53+
*/
54+
function mapResult(result) {
55+
const id = result[0];
56+
const inlineValues = result[1];
57+
const message = {};
58+
for (let i = 0; i < inlineValues.length; i += 2) {
59+
message[inlineValues[i]] = inlineValues[i + 1];
60+
}
61+
return {
62+
id,
63+
message,
64+
};
65+
}
66+
5067
/**
5168
* @see https://redis.io/commands/xread/
5269
*/
@@ -81,18 +98,7 @@ export function XREAD(
8198
}
8299
return [
83100
{
84-
messages: results[0][1].map((result) => {
85-
const id = result[0];
86-
const inlineValues = result[1];
87-
const message = {};
88-
for (let i = 0; i < inlineValues.length; i += 2) {
89-
message[inlineValues[i]] = inlineValues[i + 1];
90-
}
91-
return {
92-
id,
93-
message,
94-
};
95-
}),
101+
messages: results[0][1].map(mapResult),
96102
},
97103
];
98104
});
@@ -125,3 +131,58 @@ export function XADD(
125131
return redisClient.xadd.call(redisClient, args);
126132
}
127133
}
134+
135+
/**
136+
* @see https://redis.io/commands/xrange/
137+
*/
138+
export function XRANGE(
139+
redisClient: any,
140+
streamName: string,
141+
start: string,
142+
end: string
143+
) {
144+
if (isRedisV4Client(redisClient)) {
145+
return redisClient.xRange(streamName, start, end);
146+
} else {
147+
return redisClient.xrange(streamName, start, end).then((res) => {
148+
return res.map(mapResult);
149+
});
150+
}
151+
}
152+
153+
/**
154+
* @see https://redis.io/commands/set/
155+
*/
156+
export function SET(
157+
redisClient: any,
158+
key: string,
159+
value: string,
160+
expiryInSeconds: number
161+
) {
162+
if (isRedisV4Client(redisClient)) {
163+
return redisClient.set(key, value, {
164+
PX: expiryInSeconds,
165+
});
166+
} else {
167+
return redisClient.set(key, value, "PX", expiryInSeconds);
168+
}
169+
}
170+
171+
/**
172+
* @see https://redis.io/commands/getdel/
173+
*/
174+
export function GETDEL(redisClient: any, key: string) {
175+
if (isRedisV4Client(redisClient)) {
176+
// note: GETDEL was added in Redis version 6.2
177+
return redisClient.multi().get(key).del(key).exec();
178+
} else {
179+
return redisClient
180+
.multi()
181+
.get(key)
182+
.del(key)
183+
.exec()
184+
.then((res) => {
185+
return [res[0][1]];
186+
});
187+
}
188+
}

0 commit comments

Comments
 (0)