Skip to content

Commit 42c8ab6

Browse files
fix(sharded): ensure compatibility with ioredis
Related: #499
1 parent 55ce829 commit 42c8ab6

File tree

5 files changed

+213
-88
lines changed

5 files changed

+213
-88
lines changed

lib/sharded-adapter.ts

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
import { ClusterAdapter, ClusterMessage, MessageType } from "./cluster-adapter";
22
import { decode, encode } from "notepack.io";
3-
import { hasBinary, parseNumSubResponse, sumValues } from "./util";
3+
import { hasBinary, PUBSUB, SPUBLISH, SSUBSCRIBE, SUNSUBSCRIBE } from "./util";
44
import debugModule from "debug";
55

66
const debug = debugModule("socket.io-redis");
77

8-
const RETURN_BUFFERS = true;
9-
108
export interface ShardedRedisAdapterOptions {
119
/**
1210
* The prefix for the Redis Pub/Sub channels.
@@ -78,25 +76,21 @@ class ShardedRedisAdapter extends ClusterAdapter {
7876

7977
const handler = (message, channel) => this.onRawMessage(message, channel);
8078

81-
this.subClient.sSubscribe(this.channel, handler, RETURN_BUFFERS);
82-
this.subClient.sSubscribe(this.responseChannel, handler, RETURN_BUFFERS);
79+
SSUBSCRIBE(this.subClient, this.channel, handler);
80+
SSUBSCRIBE(this.subClient, this.responseChannel, handler);
8381

8482
if (this.opts.subscriptionMode === "dynamic") {
8583
this.on("create-room", (room) => {
8684
const isPublicRoom = !this.sids.has(room);
8785
if (isPublicRoom) {
88-
this.subClient.sSubscribe(
89-
this.dynamicChannel(room),
90-
handler,
91-
RETURN_BUFFERS
92-
);
86+
SSUBSCRIBE(this.subClient, this.dynamicChannel(room), handler);
9387
}
9488
});
9589

9690
this.on("delete-room", (room) => {
9791
const isPublicRoom = !this.sids.has(room);
9892
if (isPublicRoom) {
99-
this.subClient.sUnsubscribe(this.dynamicChannel(room));
93+
SUNSUBSCRIBE(this.subClient, this.dynamicChannel(room));
10094
}
10195
});
10296
}
@@ -114,13 +108,13 @@ class ShardedRedisAdapter extends ClusterAdapter {
114108
});
115109
}
116110

117-
return this.subClient.sUnsubscribe(channels);
111+
return SUNSUBSCRIBE(this.subClient, channels);
118112
}
119113

120114
override publishMessage(message) {
121115
const channel = this.computeChannel(message);
122116
debug("publishing message of type %s to %s", message.type, channel);
123-
this.pubClient.sPublish(channel, this.encode(message));
117+
SPUBLISH(this.pubClient, channel, this.encode(message));
124118

125119
return Promise.resolve("");
126120
}
@@ -147,7 +141,8 @@ class ShardedRedisAdapter extends ClusterAdapter {
147141
override publishResponse(requesterUid, response) {
148142
debug("publishing response of type %s to %s", response.type, requesterUid);
149143

150-
this.pubClient.sPublish(
144+
SPUBLISH(
145+
this.pubClient,
151146
`${this.channel}${requesterUid}#`,
152147
this.encode(response)
153148
);
@@ -189,21 +184,6 @@ class ShardedRedisAdapter extends ClusterAdapter {
189184
}
190185

191186
override serverCount(): Promise<number> {
192-
if (
193-
this.pubClient.constructor.name === "Cluster" ||
194-
this.pubClient.isCluster
195-
) {
196-
return Promise.all(
197-
this.pubClient.nodes().map((node) => {
198-
return node
199-
.sendCommand(["PUBSUB", "SHARDNUMSUB", this.channel])
200-
.then(parseNumSubResponse);
201-
})
202-
).then(sumValues);
203-
} else {
204-
return this.pubClient
205-
.sendCommand(["PUBSUB", "SHARDNUMSUB", this.channel])
206-
.then(parseNumSubResponse);
207-
}
187+
return PUBSUB(this.pubClient, "SHARDNUMSUB", this.channel);
208188
}
209189
}

lib/util.ts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,89 @@ export function sumValues(values) {
4444
return acc + val;
4545
}, 0);
4646
}
47+
48+
const RETURN_BUFFERS = true;
49+
50+
/**
51+
* Whether the client comes from the `redis` package
52+
*
53+
* @param redisClient
54+
*
55+
* @see https://github.com/redis/node-redis
56+
*/
57+
function isRedisV4Client(redisClient: any) {
58+
return typeof redisClient.sSubscribe === "function";
59+
}
60+
61+
export function SSUBSCRIBE(
62+
redisClient: any,
63+
channel: string,
64+
handler: (rawMessage: Buffer, channel: Buffer) => void
65+
) {
66+
if (isRedisV4Client(redisClient)) {
67+
redisClient.sSubscribe(channel, handler, RETURN_BUFFERS);
68+
} else {
69+
redisClient.ssubscribe(channel);
70+
71+
redisClient.on("smessageBuffer", (rawChannel, message) => {
72+
if (rawChannel.toString() === channel) {
73+
handler(message, rawChannel);
74+
}
75+
});
76+
}
77+
}
78+
79+
export function SUNSUBSCRIBE(redisClient: any, channel: string | string[]) {
80+
if (isRedisV4Client(redisClient)) {
81+
redisClient.sUnsubscribe(channel);
82+
} else {
83+
redisClient.sunsubscribe(channel);
84+
}
85+
}
86+
87+
export function SPUBLISH(
88+
redisClient: any,
89+
channel: string,
90+
payload: string | Uint8Array
91+
) {
92+
if (isRedisV4Client(redisClient)) {
93+
redisClient.sPublish(channel, payload);
94+
} else {
95+
redisClient.spublish(channel, payload);
96+
}
97+
}
98+
99+
export function PUBSUB(redisClient: any, arg: string, channel: string) {
100+
if (redisClient.constructor.name === "Cluster" || redisClient.isCluster) {
101+
return Promise.all(
102+
redisClient.nodes().map((node) => {
103+
return node
104+
.sendCommand(["PUBSUB", arg, channel])
105+
.then(parseNumSubResponse);
106+
})
107+
).then(sumValues);
108+
} else if (isRedisV4Client(redisClient)) {
109+
const isCluster = Array.isArray(redisClient.masters);
110+
if (isCluster) {
111+
const nodes = redisClient.masters;
112+
return Promise.all(
113+
nodes.map((node) => {
114+
return node.client
115+
.sendCommand(["PUBSUB", arg, channel])
116+
.then(parseNumSubResponse);
117+
})
118+
).then(sumValues);
119+
} else {
120+
return redisClient
121+
.sendCommand(["PUBSUB", arg, channel])
122+
.then(parseNumSubResponse);
123+
}
124+
} else {
125+
return new Promise((resolve, reject) => {
126+
redisClient.send_command("PUBSUB", [arg, channel], (err, numSub) => {
127+
if (err) return reject(err);
128+
resolve(parseNumSubResponse(numSub));
129+
});
130+
});
131+
}
132+
}

0 commit comments

Comments
 (0)