@@ -34,13 +34,17 @@ export interface ShardedRedisAdapterOptions {
34
34
* The default value, useful when some rooms have a low number of clients (so only a few Socket.IO servers are notified).
35
35
*
36
36
* Only public rooms (i.e. not related to a particular Socket ID) are taken in account, because:
37
- *
38
37
* - a lot of connected clients would mean a lot of subscription/unsubscription
39
38
* - the Socket ID attribute is ephemeral
40
39
*
40
+ * - "dynamic-private"
41
+ *
42
+ * Like "dynamic" but creates separate channels for private rooms as well. Useful when there is lots of 1:1 communication
43
+ * via socket.emit() calls.
44
+ *
41
45
* @default "dynamic"
42
46
*/
43
- subscriptionMode ?: "static" | "dynamic" ;
47
+ subscriptionMode ?: "static" | "dynamic" | "dynamic-private" ;
44
48
}
45
49
46
50
/**
@@ -91,15 +95,13 @@ class ShardedRedisAdapter extends ClusterAdapter {
91
95
92
96
if ( this . opts . subscriptionMode === "dynamic" ) {
93
97
this . on ( "create-room" , ( room ) => {
94
- const isPublicRoom = ! this . sids . has ( room ) ;
95
- if ( isPublicRoom ) {
98
+ if ( this . shouldUseASeparateNamespace ( room ) ) {
96
99
SSUBSCRIBE ( this . subClient , this . dynamicChannel ( room ) , handler ) ;
97
100
}
98
101
} ) ;
99
102
100
103
this . on ( "delete-room" , ( room ) => {
101
- const isPublicRoom = ! this . sids . has ( room ) ;
102
- if ( isPublicRoom ) {
104
+ if ( this . shouldUseASeparateNamespace ( room ) ) {
103
105
SUNSUBSCRIBE ( this . subClient , this . dynamicChannel ( room ) ) ;
104
106
}
105
107
} ) ;
@@ -111,8 +113,7 @@ class ShardedRedisAdapter extends ClusterAdapter {
111
113
112
114
if ( this . opts . subscriptionMode === "dynamic" ) {
113
115
this . rooms . forEach ( ( _sids , room ) => {
114
- const isPublicRoom = ! this . sids . has ( room ) ;
115
- if ( isPublicRoom ) {
116
+ if ( this . shouldUseASeparateNamespace ( room ) ) {
116
117
channels . push ( this . dynamicChannel ( room ) ) ;
117
118
}
118
119
} ) ;
@@ -133,15 +134,19 @@ class ShardedRedisAdapter extends ClusterAdapter {
133
134
}
134
135
135
136
private computeChannel ( message ) {
137
+ const isDynamicChannel =
138
+ ( this . opts . subscriptionMode === "dynamic" &&
139
+ ! looksLikeASocketId ( message . data . opts . rooms [ 0 ] ) ) ||
140
+ this . opts . subscriptionMode === "dynamic-private" ;
141
+
136
142
// broadcast with ack can not use a dynamic channel, because the serverCount() method return the number of all
137
143
// servers, not only the ones where the given room exists
138
- const useDynamicChannel =
139
- this . opts . subscriptionMode === "dynamic" &&
144
+ const isSupportedMessageType =
140
145
message . type === MessageType . BROADCAST &&
141
146
message . data . requestId === undefined &&
142
- message . data . opts . rooms . length === 1 &&
143
- ! looksLikeASocketId ( message . data . opts . rooms [ 0 ] ) ;
144
- if ( useDynamicChannel ) {
147
+ message . data . opts . rooms . length === 1 ;
148
+
149
+ if ( isDynamicChannel && isSupportedMessageType ) {
145
150
return this . dynamicChannel ( message . data . opts . rooms [ 0 ] ) ;
146
151
} else {
147
152
return this . channel ;
@@ -204,4 +209,13 @@ class ShardedRedisAdapter extends ClusterAdapter {
204
209
override serverCount ( ) : Promise < number > {
205
210
return PUBSUB ( this . pubClient , "SHARDNUMSUB" , this . channel ) ;
206
211
}
212
+
213
+ shouldUseASeparateNamespace ( room : string ) : boolean {
214
+ const isPublicRoom = ! this . sids . has ( room ) ;
215
+
216
+ return (
217
+ ( this . opts . subscriptionMode === "dynamic" && isPublicRoom ) ||
218
+ this . opts . subscriptionMode === "dynamic-private"
219
+ ) ;
220
+ }
207
221
}
0 commit comments