@@ -7,6 +7,7 @@ import type { Unsubscribe } from './store';
77import { StateStore } from './store' ;
88import type {
99 EventHandlerPipelineHandler ,
10+ FindEventHandlerParams ,
1011 InsertEventHandlerPayload ,
1112 LabeledEventHandler ,
1213} from './EventHandlerPipeline' ;
@@ -17,11 +18,32 @@ export type ChannelPaginatorsOrchestratorEventHandlerContext = {
1718 orchestrator : ChannelPaginatorsOrchestrator ;
1819} ;
1920
21+ type EventHandlerContext = ChannelPaginatorsOrchestratorEventHandlerContext ;
22+
2023type SupportedEventType = EventTypes | ( string & { } ) ;
2124
22- const reEmit : EventHandlerPipelineHandler <
23- ChannelPaginatorsOrchestratorEventHandlerContext
24- > = ( { event, ctx : { orchestrator } } ) => {
25+ const getCachedChannelFromEvent = (
26+ event : Event ,
27+ cache : Record < string , Channel > ,
28+ ) : Channel | undefined => {
29+ let channel : Channel | undefined = undefined ;
30+ if ( event . cid ) {
31+ channel = cache [ event . cid ] ;
32+ } else if ( event . channel_id && event . channel_type ) {
33+ // todo: is there a central method to construct the cid from type and channel id?
34+ channel = cache [ `${ event . channel_type } :${ event . channel_id } ` ] ;
35+ } else if ( event . channel ) {
36+ channel = cache [ event . channel . cid ] ;
37+ } else {
38+ return ;
39+ }
40+ return channel ;
41+ } ;
42+
43+ const reEmit : EventHandlerPipelineHandler < EventHandlerContext > = ( {
44+ event,
45+ ctx : { orchestrator } ,
46+ } ) => {
2547 if ( ! event . cid ) return ;
2648 const channel = orchestrator . client . activeChannels [ event . cid ] ;
2749 if ( ! channel ) return ;
@@ -33,31 +55,37 @@ const reEmit: EventHandlerPipelineHandler<
3355 } ) ;
3456} ;
3557
36- const removeItem : EventHandlerPipelineHandler <
37- ChannelPaginatorsOrchestratorEventHandlerContext
38- > = ( { event, ctx : { orchestrator } } ) => {
58+ const removeItem : EventHandlerPipelineHandler < EventHandlerContext > = ( {
59+ event,
60+ ctx : { orchestrator } ,
61+ } ) => {
3962 if ( ! event . cid ) return ;
4063 const channel = orchestrator . client . activeChannels [ event . cid ] ;
4164 orchestrator . paginators . forEach ( ( paginator ) => {
4265 paginator . removeItem ( { id : event . cid , item : channel } ) ;
4366 } ) ;
4467} ;
4568
46- const updateLists : EventHandlerPipelineHandler <
47- ChannelPaginatorsOrchestratorEventHandlerContext
48- > = async ( { event, ctx : { orchestrator } } ) => {
49- let channel : Channel | undefined = undefined ;
50- if ( event . cid ) {
51- channel = orchestrator . client . activeChannels [ event . cid ] ;
52- } else if ( event . channel_id && event . channel_type ) {
53- // todo: is there a central method to construct the cid from type and channel id?
54- channel =
55- orchestrator . client . activeChannels [ `${ event . channel_type } :${ event . channel_id } ` ] ;
56- } else if ( event . channel ) {
57- channel = orchestrator . client . activeChannels [ event . channel . cid ] ;
58- } else {
59- return ;
60- }
69+ // todo: documentation: show how to implement allowNewMessagesFromUnfilteredChannels just by inserting event handler
70+ // at the start of the handler pipeline and filter out events for unknown channels
71+ export const ignoreEventsForUnknownChannels : EventHandlerPipelineHandler <
72+ EventHandlerContext
73+ > = ( { event, ctx : { orchestrator } } ) => {
74+ const channel : Channel | undefined = getCachedChannelFromEvent (
75+ event ,
76+ orchestrator . client . activeChannels ,
77+ ) ;
78+ if ( ! channel ) return { action : 'stop' } ;
79+ } ;
80+
81+ const updateLists : EventHandlerPipelineHandler < EventHandlerContext > = async ( {
82+ event,
83+ ctx : { orchestrator } ,
84+ } ) => {
85+ let channel : Channel | undefined = getCachedChannelFromEvent (
86+ event ,
87+ orchestrator . client . activeChannels ,
88+ ) ;
6189
6290 if ( ! channel ) {
6391 const [ type , id ] = event . cid
@@ -96,104 +124,91 @@ const updateLists: EventHandlerPipelineHandler<
96124} ;
97125
98126// we have to make sure that client.activeChannels is always up-to-date
99- const channelDeletedHandler : LabeledEventHandler < ChannelPaginatorsOrchestratorEventHandlerContext > =
100- {
101- handle : removeItem ,
102- id : 'ChannelPaginatorsOrchestrator:default-handler:channel.deleted' ,
103- } ;
127+ const channelDeletedHandler : LabeledEventHandler < EventHandlerContext > = {
128+ handle : removeItem ,
129+ id : 'ChannelPaginatorsOrchestrator:default-handler:channel.deleted' ,
130+ } ;
104131
105132// fixme: this handler should not be handled by the orchestrator but as Channel does not have reactive state,
106133// we need to re-emit the whole list to reflect the changes
107- const channelUpdatedHandler : LabeledEventHandler < ChannelPaginatorsOrchestratorEventHandlerContext > =
108- {
109- handle : reEmit ,
110- id : 'ChannelPaginatorsOrchestrator:default-handler:channel.updated' ,
111- } ;
134+ const channelUpdatedHandler : LabeledEventHandler < EventHandlerContext > = {
135+ handle : reEmit ,
136+ id : 'ChannelPaginatorsOrchestrator:default-handler:channel.updated' ,
137+ } ;
112138
113139// fixme: this handler should not be handled by the orchestrator but as Channel does not have reactive state,
114140// we need to re-emit the whole list to reflect the changes
115- const channelTruncatedHandler : LabeledEventHandler < ChannelPaginatorsOrchestratorEventHandlerContext > =
116- {
117- handle : reEmit ,
118- id : 'ChannelPaginatorsOrchestrator:default-handler:channel.truncated' ,
119- } ;
120-
121- const channelVisibleHandler : LabeledEventHandler < ChannelPaginatorsOrchestratorEventHandlerContext > =
122- {
123- handle : updateLists ,
124- id : 'ChannelPaginatorsOrchestrator:default-handler:channel.visible' ,
125- } ;
141+ const channelTruncatedHandler : LabeledEventHandler < EventHandlerContext > = {
142+ handle : reEmit ,
143+ id : 'ChannelPaginatorsOrchestrator:default-handler:channel.truncated' ,
144+ } ;
145+
146+ const channelVisibleHandler : LabeledEventHandler < EventHandlerContext > = {
147+ handle : updateLists ,
148+ id : 'ChannelPaginatorsOrchestrator:default-handler:channel.visible' ,
149+ } ;
126150
127151// members filter - should not be impacted as id is stable - cannot be updated
128152// member.user.name - can be impacted
129- const memberUpdatedHandler : LabeledEventHandler < ChannelPaginatorsOrchestratorEventHandlerContext > =
130- {
131- handle : updateLists ,
132- id : 'ChannelPaginatorsOrchestrator:default-handler:member.updated' ,
133- } ;
134-
135- const messageNewHandler : LabeledEventHandler < ChannelPaginatorsOrchestratorEventHandlerContext > =
136- {
137- handle : updateLists ,
138- id : 'ChannelPaginatorsOrchestrator:default-handler:message.new' ,
139- } ;
140-
141- const notificationAddedToChannelHandler : LabeledEventHandler < ChannelPaginatorsOrchestratorEventHandlerContext > =
142- {
143- handle : updateLists ,
144- id : 'ChannelPaginatorsOrchestrator:default-handler:notification.added_to_channel' ,
145- } ;
146-
147- const notificationMessageNewHandler : LabeledEventHandler < ChannelPaginatorsOrchestratorEventHandlerContext > =
148- {
149- handle : updateLists ,
150- id : 'ChannelPaginatorsOrchestrator:default-handler:notification.message_new' ,
151- } ;
152-
153- const notificationRemovedFromChannelHandler : LabeledEventHandler < ChannelPaginatorsOrchestratorEventHandlerContext > =
154- {
155- handle : removeItem ,
156- id : 'ChannelPaginatorsOrchestrator:default-handler:notification.removed_from_channel' ,
157- } ;
153+ const memberUpdatedHandler : LabeledEventHandler < EventHandlerContext > = {
154+ handle : updateLists ,
155+ id : 'ChannelPaginatorsOrchestrator:default-handler:member.updated' ,
156+ } ;
157+
158+ const messageNewHandler : LabeledEventHandler < EventHandlerContext > = {
159+ handle : updateLists ,
160+ id : 'ChannelPaginatorsOrchestrator:default-handler:message.new' ,
161+ } ;
162+
163+ const notificationAddedToChannelHandler : LabeledEventHandler < EventHandlerContext > = {
164+ handle : updateLists ,
165+ id : 'ChannelPaginatorsOrchestrator:default-handler:notification.added_to_channel' ,
166+ } ;
167+
168+ const notificationMessageNewHandler : LabeledEventHandler < EventHandlerContext > = {
169+ handle : updateLists ,
170+ id : 'ChannelPaginatorsOrchestrator:default-handler:notification.message_new' ,
171+ } ;
172+
173+ const notificationRemovedFromChannelHandler : LabeledEventHandler < EventHandlerContext > = {
174+ handle : removeItem ,
175+ id : 'ChannelPaginatorsOrchestrator:default-handler:notification.removed_from_channel' ,
176+ } ;
158177
159178// fixme: updates users for member object in all the channels which are loaded with that member - normalization would be beneficial
160- const userPresenceChangedHandler : LabeledEventHandler < ChannelPaginatorsOrchestratorEventHandlerContext > =
161- {
162- handle : ( { event, ctx : { orchestrator } } ) => {
163- const eventUser = event . user ;
164- if ( ! eventUser ?. id ) return ;
165- orchestrator . paginators . forEach ( ( paginator ) => {
166- const paginatorItems = paginator . items ;
167- if ( ! paginatorItems ) return ;
168- let updated = false ;
169- paginatorItems . forEach ( ( channel ) => {
170- if ( channel . state . members [ eventUser . id ] ) {
171- channel . state . members [ eventUser . id ] . user = event . user ;
172- updated = true ;
173- }
174- if ( channel . state . membership . user ?. id === eventUser . id ) {
175- channel . state . membership . user = eventUser ;
176- updated = true ;
177- }
178- } ) ;
179- if ( updated ) {
180- // fixme: user is not reactive and so the whole list has to be re-rendered
181- paginator . state . partialNext ( { items : [ ...paginatorItems ] } ) ;
179+ const userPresenceChangedHandler : LabeledEventHandler < EventHandlerContext > = {
180+ handle : ( { event, ctx : { orchestrator } } ) => {
181+ const eventUser = event . user ;
182+ if ( ! eventUser ?. id ) return ;
183+ orchestrator . paginators . forEach ( ( paginator ) => {
184+ const paginatorItems = paginator . items ;
185+ if ( ! paginatorItems ) return ;
186+ let updated = false ;
187+ paginatorItems . forEach ( ( channel ) => {
188+ if ( channel . state . members [ eventUser . id ] ) {
189+ channel . state . members [ eventUser . id ] . user = event . user ;
190+ updated = true ;
191+ }
192+ if ( channel . state . membership . user ?. id === eventUser . id ) {
193+ channel . state . membership . user = eventUser ;
194+ updated = true ;
182195 }
183196 } ) ;
184- } ,
185- id : 'ChannelPaginatorsOrchestrator:default-handler:user.presence.changed' ,
186- } ;
197+ if ( updated ) {
198+ // fixme: user is not reactive and so the whole list has to be re-rendered
199+ paginator . state . partialNext ( { items : [ ...paginatorItems ] } ) ;
200+ }
201+ } ) ;
202+ } ,
203+ id : 'ChannelPaginatorsOrchestrator:default-handler:user.presence.changed' ,
204+ } ;
187205
188206export type ChannelPaginatorsOrchestratorState = {
189207 paginators : ChannelPaginator [ ] ;
190208} ;
191209
192210export type ChannelPaginatorsOrchestratorEventHandlers = Partial <
193- Record <
194- SupportedEventType ,
195- LabeledEventHandler < ChannelPaginatorsOrchestratorEventHandlerContext > [ ]
196- >
211+ Record < SupportedEventType , LabeledEventHandler < EventHandlerContext > [ ] >
197212> ;
198213
199214export type ChannelPaginatorsOrchestratorOptions = {
@@ -205,14 +220,15 @@ export type ChannelPaginatorsOrchestratorOptions = {
205220export class ChannelPaginatorsOrchestrator extends WithSubscriptions {
206221 client : StreamChat ;
207222 state : StateStore < ChannelPaginatorsOrchestratorState > ;
208- protected pipelines = new Map <
223+ protected _pipelines = new Map <
209224 SupportedEventType ,
210- EventHandlerPipeline < ChannelPaginatorsOrchestratorEventHandlerContext >
225+ EventHandlerPipeline < EventHandlerContext >
211226 > ( ) ;
212227
213228 protected static readonly defaultEventHandlers : ChannelPaginatorsOrchestratorEventHandlers =
214229 {
215230 'channel.deleted' : [ channelDeletedHandler ] ,
231+ 'channel.hidden' : [ channelDeletedHandler ] ,
216232 'channel.updated' : [ channelUpdatedHandler ] ,
217233 'channel.truncated' : [ channelTruncatedHandler ] ,
218234 'channel.visible' : [ channelVisibleHandler ] ,
@@ -243,7 +259,11 @@ export class ChannelPaginatorsOrchestrator extends WithSubscriptions {
243259 return this . state . getLatestValue ( ) . paginators ;
244260 }
245261
246- private get ctx ( ) : ChannelPaginatorsOrchestratorEventHandlerContext {
262+ get pipelines ( ) : Map < SupportedEventType , EventHandlerPipeline < EventHandlerContext > > {
263+ return this . _pipelines ;
264+ }
265+
266+ private get ctx ( ) : EventHandlerContext {
247267 return { orchestrator : this } ;
248268 }
249269
@@ -291,17 +311,39 @@ export class ChannelPaginatorsOrchestrator extends WithSubscriptions {
291311 ...payload
292312 } : {
293313 eventType : SupportedEventType ;
294- } & InsertEventHandlerPayload < ChannelPaginatorsOrchestratorEventHandlerContext > ) : Unsubscribe {
314+ } & InsertEventHandlerPayload < EventHandlerContext > ) : Unsubscribe {
295315 return this . ensurePipeline ( eventType ) . insert ( payload ) ;
296316 }
297317
318+ setEventHandlers ( {
319+ eventType,
320+ handlers,
321+ } : {
322+ eventType : SupportedEventType ;
323+ handlers : LabeledEventHandler < EventHandlerContext > [ ] ;
324+ } ) {
325+ return this . ensurePipeline ( eventType ) . replaceAll ( handlers ) ;
326+ }
327+
328+ removeEventHandlers ( {
329+ eventType,
330+ handlers,
331+ } : {
332+ eventType : SupportedEventType ;
333+ handlers : FindEventHandlerParams < EventHandlerContext > [ ] ;
334+ } ) {
335+ const pipeline = this . _pipelines . get ( eventType ) ;
336+ if ( ! pipeline ) return ;
337+ handlers . forEach ( ( params ) => pipeline . remove ( params ) ) ;
338+ }
339+
298340 /** Subscribe to WS (and more buses via attachBus) */
299341 registerSubscriptions ( ) : Unsubscribe {
300342 if ( ! this . hasSubscriptions ) {
301343 this . addUnsubscribeFunction (
302344 // todo: maybe we should have a wrapper here to decide, whether the event is a LocalEventBus event or else supported by client
303345 this . client . on ( ( event : Event ) => {
304- const pipe = this . pipelines . get ( event . type ) ;
346+ const pipe = this . _pipelines . get ( event . type ) ;
305347 if ( pipe ) {
306348 pipe . run ( event , this . ctx ) ;
307349 }
@@ -315,13 +357,13 @@ export class ChannelPaginatorsOrchestrator extends WithSubscriptions {
315357
316358 ensurePipeline (
317359 eventType : SupportedEventType ,
318- ) : EventHandlerPipeline < ChannelPaginatorsOrchestratorEventHandlerContext > {
319- let pipe = this . pipelines . get ( eventType ) ;
360+ ) : EventHandlerPipeline < EventHandlerContext > {
361+ let pipe = this . _pipelines . get ( eventType ) ;
320362 if ( ! pipe ) {
321- pipe = new EventHandlerPipeline < ChannelPaginatorsOrchestratorEventHandlerContext > ( {
363+ pipe = new EventHandlerPipeline < EventHandlerContext > ( {
322364 id : `ChannelPaginatorsOrchestrator:${ eventType } ` ,
323365 } ) ;
324- this . pipelines . set ( eventType , pipe ) ;
366+ this . _pipelines . set ( eventType , pipe ) ;
325367 }
326368 return pipe ;
327369 }
0 commit comments