-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Extract RealtimeChannel MessageFilter-related code to new class
In preparation for #1397 (making MessageFilter functionality tree-shakable).
- Loading branch information
1 parent
768eb0c
commit 948f255
Showing
2 changed files
with
117 additions
and
103 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import * as API from '../../../../ably'; | ||
import RealtimeChannel from './realtimechannel'; | ||
import Message from '../types/message'; | ||
|
||
export class FilteredSubscriptions { | ||
static subscribeFilter( | ||
channel: RealtimeChannel, | ||
filter: API.Types.MessageFilter, | ||
listener: API.Types.messageCallback<Message> | ||
) { | ||
const filteredListener = (m: Message) => { | ||
const mapping: { [key in keyof API.Types.MessageFilter]: any } = { | ||
name: m.name, | ||
refTimeserial: m.extras?.ref?.timeserial, | ||
refType: m.extras?.ref?.type, | ||
isRef: !!m.extras?.ref?.timeserial, | ||
clientId: m.clientId, | ||
}; | ||
// Check if any values are defined in the filter and if they match the value in the message object | ||
if ( | ||
Object.entries(filter).find(([key, value]) => | ||
value !== undefined ? mapping[key as keyof API.Types.MessageFilter] !== value : false | ||
) | ||
) { | ||
return; | ||
} | ||
listener(m); | ||
}; | ||
this.addFilteredSubscription(channel, filter, listener, filteredListener); | ||
channel.subscriptions.on(filteredListener); | ||
} | ||
|
||
// Adds a new filtered subscription | ||
static addFilteredSubscription( | ||
channel: RealtimeChannel, | ||
filter: API.Types.MessageFilter, | ||
realListener: API.Types.messageCallback<Message>, | ||
filteredListener: API.Types.messageCallback<Message> | ||
) { | ||
if (!channel.filteredSubscriptions) { | ||
channel.filteredSubscriptions = new Map< | ||
API.Types.messageCallback<Message>, | ||
Map<API.Types.MessageFilter, API.Types.messageCallback<Message>[]> | ||
>(); | ||
} | ||
if (channel.filteredSubscriptions.has(realListener)) { | ||
const realListenerMap = channel.filteredSubscriptions.get(realListener) as Map< | ||
API.Types.MessageFilter, | ||
API.Types.messageCallback<Message>[] | ||
>; | ||
// Add the filtered listener to the map, or append to the array if this filter has already been used | ||
realListenerMap.set(filter, realListenerMap?.get(filter)?.concat(filteredListener) || [filteredListener]); | ||
} else { | ||
channel.filteredSubscriptions.set( | ||
realListener, | ||
new Map<API.Types.MessageFilter, API.Types.messageCallback<Message>[]>([[filter, [filteredListener]]]) | ||
); | ||
} | ||
} | ||
|
||
static getAndDeleteFilteredSubscriptions( | ||
channel: RealtimeChannel, | ||
filter: API.Types.MessageFilter | undefined, | ||
realListener: API.Types.messageCallback<Message> | undefined | ||
): API.Types.messageCallback<Message>[] { | ||
// No filtered subscriptions map means there has been no filtered subscriptions yet, so return nothing | ||
if (!channel.filteredSubscriptions) { | ||
return []; | ||
} | ||
// Only a filter is passed in with no specific listener | ||
if (!realListener && filter) { | ||
// Return each listener which is attached to the specified filter object | ||
return Array.from(channel.filteredSubscriptions.entries()) | ||
.map(([key, filterMaps]) => { | ||
// Get (then delete) the maps matching this filter | ||
let listenerMaps = filterMaps.get(filter); | ||
filterMaps.delete(filter); | ||
// Clear the parent if nothing is left | ||
if (filterMaps.size === 0) { | ||
channel.filteredSubscriptions?.delete(key); | ||
} | ||
return listenerMaps; | ||
}) | ||
.reduce( | ||
(prev, cur) => (cur ? (prev as API.Types.messageCallback<Message>[]).concat(...cur) : prev), | ||
[] | ||
) as API.Types.messageCallback<Message>[]; | ||
} | ||
|
||
// No subscriptions for this listener | ||
if (!realListener || !channel.filteredSubscriptions.has(realListener)) { | ||
return []; | ||
} | ||
const realListenerMap = channel.filteredSubscriptions.get(realListener) as Map< | ||
API.Types.MessageFilter, | ||
API.Types.messageCallback<Message>[] | ||
>; | ||
// If no filter is specified return all listeners using that function | ||
if (!filter) { | ||
// array.flat is not available unless we support es2019 or higher | ||
const listeners = Array.from(realListenerMap.values()).reduce((prev, cur) => prev.concat(...cur), []); | ||
// remove the listener from the map | ||
channel.filteredSubscriptions.delete(realListener); | ||
return listeners; | ||
} | ||
|
||
let listeners = realListenerMap.get(filter); | ||
realListenerMap.delete(filter); | ||
|
||
return listeners || []; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters