99
1010import Emittery from 'emittery'
1111import type { Redis , Cluster } from 'ioredis'
12- import * as errors from '../errors.js'
1312import type {
1413 PubSubOptions ,
1514 ConnectionEvents ,
@@ -38,8 +37,8 @@ export abstract class AbstractConnection<
3837 /**
3938 * A list of active subscriptions and pattern subscription
4039 */
41- protected subscriptions : Map < string , PubSubChannelHandler > = new Map ( )
42- protected psubscriptions : Map < string , PubSubPatternHandler > = new Map ( )
40+ protected subscriptions : Map < string , Set < PubSubChannelHandler > > = new Map ( )
41+ protected psubscriptions : Map < string , Set < PubSubPatternHandler > > = new Map ( )
4342
4443 /**
4544 * The last error emitted by the `error` event. We set it to `null` after
@@ -230,19 +229,23 @@ export abstract class AbstractConnection<
230229 * Listen for messages
231230 */
232231 this . ioSubscriberConnection ! . on ( 'message' , ( channel , message ) => {
233- const handler = this . subscriptions . get ( channel )
234- if ( handler ) {
235- handler ( message )
232+ const handlers = this . subscriptions . get ( channel )
233+ if ( handlers ) {
234+ for ( const handler of handlers ) {
235+ handler ( message )
236+ }
236237 }
237238 } )
238239
239240 /**
240241 * Listen for pattern messages
241242 */
242243 this . ioSubscriberConnection ! . on ( 'pmessage' , ( pattern , channel , message ) => {
243- const handler = this . psubscriptions . get ( pattern )
244- if ( handler ) {
245- handler ( channel , message )
244+ const handlers = this . psubscriptions . get ( pattern )
245+ if ( handlers ) {
246+ for ( const handler of handlers ) {
247+ handler ( channel , message )
248+ }
246249 }
247250 } )
248251 }
@@ -278,13 +281,6 @@ export abstract class AbstractConnection<
278281 */
279282 this . setupSubscriberConnection ( )
280283
281- /**
282- * Disallow multiple subscriptions to a single channel
283- */
284- if ( this . subscriptions . has ( channel ) ) {
285- throw new errors . E_MULTIPLE_REDIS_SUBSCRIPTIONS ( [ channel ] )
286- }
287-
288284 /**
289285 * If the subscriptions map is empty, it means we have no active subscriptions
290286 * on the given channel, hence we should make one subscription and also set
@@ -296,7 +292,12 @@ export abstract class AbstractConnection<
296292 options ?. onSubscription ( count as number )
297293 }
298294 this . emit ( 'subscription:ready' , { count : count as number , connection : this } )
299- this . subscriptions . set ( channel , handler )
295+ const subscriptions = this . subscriptions . get ( channel )
296+ if ( subscriptions ) {
297+ subscriptions . add ( handler )
298+ } else {
299+ this . subscriptions . set ( channel , new Set ( [ handler ] ) )
300+ }
300301 } )
301302 . catch ( ( error ) => {
302303 if ( options ?. onError ) {
@@ -309,8 +310,19 @@ export abstract class AbstractConnection<
309310 /**
310311 * Unsubscribe from a channel
311312 */
312- unsubscribe ( channel : string ) {
313- this . subscriptions . delete ( channel )
313+ unsubscribe ( channel : string , handler ?: PubSubChannelHandler ) {
314+ if ( handler ) {
315+ const subscriptions = this . subscriptions . get ( channel )
316+ if ( subscriptions ) {
317+ subscriptions . delete ( handler )
318+ }
319+
320+ if ( subscriptions && subscriptions . size !== 0 ) {
321+ return Promise . resolve ( )
322+ }
323+ } else {
324+ this . subscriptions . delete ( channel )
325+ }
314326 return this . ioSubscriberConnection ! . unsubscribe ( channel )
315327 }
316328
@@ -324,13 +336,6 @@ export abstract class AbstractConnection<
324336 */
325337 this . setupSubscriberConnection ( )
326338
327- /**
328- * Disallow multiple subscriptions to a single channel
329- */
330- if ( this . psubscriptions . has ( pattern ) ) {
331- throw new errors . E_MULTIPLE_REDIS_PSUBSCRIPTIONS ( [ pattern ] )
332- }
333-
334339 /**
335340 * If the subscriptions map is empty, it means we have no active subscriptions
336341 * on the given channel, hence we should make one subscription and also set
@@ -342,7 +347,12 @@ export abstract class AbstractConnection<
342347 options ?. onSubscription ( count as number )
343348 }
344349 this . emit ( 'psubscription:ready' , { count : count as number , connection : this } )
345- this . psubscriptions . set ( pattern , handler )
350+ const psubscriptions = this . psubscriptions . get ( pattern )
351+ if ( psubscriptions ) {
352+ psubscriptions . add ( handler )
353+ } else {
354+ this . psubscriptions . set ( pattern , new Set ( [ handler ] ) )
355+ }
346356 } )
347357 . catch ( ( error ) => {
348358 if ( options ?. onError ) {
@@ -355,8 +365,20 @@ export abstract class AbstractConnection<
355365 /**
356366 * Unsubscribe from a given pattern
357367 */
358- punsubscribe ( pattern : string ) {
359- this . psubscriptions . delete ( pattern )
368+ punsubscribe ( pattern : string , handler ?: PubSubPatternHandler ) {
369+ if ( handler ) {
370+ const psubscriptions = this . psubscriptions . get ( pattern )
371+ if ( psubscriptions ) {
372+ psubscriptions . delete ( handler )
373+ }
374+
375+ if ( psubscriptions && psubscriptions . size !== 0 ) {
376+ return Promise . resolve ( )
377+ }
378+ } else {
379+ this . psubscriptions . delete ( pattern )
380+ }
381+
360382 return this . ioSubscriberConnection ! . punsubscribe ( pattern )
361383 }
362384
0 commit comments