@@ -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
/**
@@ -89,17 +93,18 @@ class ShardedRedisAdapter extends ClusterAdapter {
89
93
SSUBSCRIBE ( this . subClient , this . channel , handler ) ;
90
94
SSUBSCRIBE ( this . subClient , this . responseChannel , handler ) ;
91
95
92
- if ( this . opts . subscriptionMode === "dynamic" ) {
96
+ if (
97
+ this . opts . subscriptionMode === "dynamic" ||
98
+ this . opts . subscriptionMode === "dynamic-private"
99
+ ) {
93
100
this . on ( "create-room" , ( room ) => {
94
- const isPublicRoom = ! this . sids . has ( room ) ;
95
- if ( isPublicRoom ) {
101
+ if ( this . shouldUseASeparateNamespace ( room ) ) {
96
102
SSUBSCRIBE ( this . subClient , this . dynamicChannel ( room ) , handler ) ;
97
103
}
98
104
} ) ;
99
105
100
106
this . on ( "delete-room" , ( room ) => {
101
- const isPublicRoom = ! this . sids . has ( room ) ;
102
- if ( isPublicRoom ) {
107
+ if ( this . shouldUseASeparateNamespace ( room ) ) {
103
108
SUNSUBSCRIBE ( this . subClient , this . dynamicChannel ( room ) ) ;
104
109
}
105
110
} ) ;
@@ -109,10 +114,12 @@ class ShardedRedisAdapter extends ClusterAdapter {
109
114
override close ( ) : Promise < void > | void {
110
115
const channels = [ this . channel , this . responseChannel ] ;
111
116
112
- if ( this . opts . subscriptionMode === "dynamic" ) {
117
+ if (
118
+ this . opts . subscriptionMode === "dynamic" ||
119
+ this . opts . subscriptionMode === "dynamic-private"
120
+ ) {
113
121
this . rooms . forEach ( ( _sids , room ) => {
114
- const isPublicRoom = ! this . sids . has ( room ) ;
115
- if ( isPublicRoom ) {
122
+ if ( this . shouldUseASeparateNamespace ( room ) ) {
116
123
channels . push ( this . dynamicChannel ( room ) ) ;
117
124
}
118
125
} ) ;
@@ -136,11 +143,13 @@ class ShardedRedisAdapter extends ClusterAdapter {
136
143
// broadcast with ack can not use a dynamic channel, because the serverCount() method return the number of all
137
144
// servers, not only the ones where the given room exists
138
145
const useDynamicChannel =
139
- this . opts . subscriptionMode === "dynamic" &&
140
146
message . type === MessageType . BROADCAST &&
141
147
message . data . requestId === undefined &&
142
148
message . data . opts . rooms . length === 1 &&
143
- ! looksLikeASocketId ( message . data . opts . rooms [ 0 ] ) ;
149
+ ( ( this . opts . subscriptionMode === "dynamic" &&
150
+ ! looksLikeASocketId ( message . data . opts . rooms [ 0 ] ) ) ||
151
+ this . opts . subscriptionMode === "dynamic-private" ) ;
152
+
144
153
if ( useDynamicChannel ) {
145
154
return this . dynamicChannel ( message . data . opts . rooms [ 0 ] ) ;
146
155
} else {
@@ -204,4 +213,13 @@ class ShardedRedisAdapter extends ClusterAdapter {
204
213
override serverCount ( ) : Promise < number > {
205
214
return PUBSUB ( this . pubClient , "SHARDNUMSUB" , this . channel ) ;
206
215
}
216
+
217
+ private shouldUseASeparateNamespace ( room : string ) : boolean {
218
+ const isPublicRoom = ! this . sids . has ( room ) ;
219
+
220
+ return (
221
+ ( this . opts . subscriptionMode === "dynamic" && isPublicRoom ) ||
222
+ this . opts . subscriptionMode === "dynamic-private"
223
+ ) ;
224
+ }
207
225
}
0 commit comments