@@ -196,63 +196,12 @@ async def _handle_deltas(self, deltas: List[Dict[str, Any]]) -> None:
196
196
room_id , prev_event_id , event_id , typ
197
197
)
198
198
elif typ == EventTypes .Member :
199
- change = await self ._get_key_change (
199
+ await self ._handle_room_membership_event (
200
+ room_id ,
200
201
prev_event_id ,
201
202
event_id ,
202
- key_name = "membership" ,
203
- public_value = Membership .JOIN ,
203
+ state_key ,
204
204
)
205
-
206
- is_remote = not self .is_mine_id (state_key )
207
- if change is MatchChange .now_false :
208
- # Need to check if the server left the room entirely, if so
209
- # we might need to remove all the users in that room
210
- is_in_room = await self .store .is_host_joined (
211
- room_id , self .server_name
212
- )
213
- if not is_in_room :
214
- logger .debug ("Server left room: %r" , room_id )
215
- # Fetch all the users that we marked as being in user
216
- # directory due to being in the room and then check if
217
- # need to remove those users or not
218
- user_ids = await self .store .get_users_in_dir_due_to_room (
219
- room_id
220
- )
221
-
222
- for user_id in user_ids :
223
- await self ._handle_remove_user (room_id , user_id )
224
- continue
225
- else :
226
- logger .debug ("Server is still in room: %r" , room_id )
227
-
228
- include_in_dir = (
229
- is_remote
230
- or await self .store .should_include_local_user_in_dir (state_key )
231
- )
232
- if include_in_dir :
233
- if change is MatchChange .no_change :
234
- # Handle any profile changes for remote users.
235
- # (For local users we are not forced to scan membership
236
- # events; instead the rest of the application calls
237
- # `handle_local_profile_change`.)
238
- if is_remote :
239
- await self ._handle_profile_change (
240
- state_key , room_id , prev_event_id , event_id
241
- )
242
- continue
243
-
244
- if change is MatchChange .now_true : # The user joined
245
- # This may be the first time we've seen a remote user. If
246
- # so, ensure we have a directory entry for them. (We don't
247
- # need to do this for local users: their directory entry
248
- # is created at the point of registration.
249
- if is_remote :
250
- await self ._upsert_directory_entry_for_remote_user (
251
- state_key , event_id
252
- )
253
- await self ._track_user_joined_room (room_id , state_key )
254
- else : # The user left
255
- await self ._handle_remove_user (room_id , state_key )
256
205
else :
257
206
logger .debug ("Ignoring irrelevant type: %r" , typ )
258
207
@@ -326,6 +275,72 @@ async def _handle_room_publicity_change(
326
275
for user_id in users_in_room :
327
276
await self ._track_user_joined_room (room_id , user_id )
328
277
278
+ async def _handle_room_membership_event (
279
+ self ,
280
+ room_id : str ,
281
+ prev_event_id : str ,
282
+ event_id : str ,
283
+ state_key : str ,
284
+ ) -> None :
285
+ """Process a single room membershp event.
286
+
287
+ We have to do two things:
288
+
289
+ 1. Update the room-sharing tables.
290
+ This applies to remote users and non-excluded local users.
291
+ 2. Update the user_directory and user_directory_search tables.
292
+ This applies to remote users only, because we only become aware of
293
+ the (and any profile changes) by listening to these events.
294
+ The rest of the application knows exactly when local users are
295
+ created or their profile changed---it will directly call methods
296
+ on this class.
297
+ """
298
+ joined = await self ._get_key_change (
299
+ prev_event_id ,
300
+ event_id ,
301
+ key_name = "membership" ,
302
+ public_value = Membership .JOIN ,
303
+ )
304
+
305
+ # Both cases ignore excluded local users, so start by discarding them.
306
+ is_remote = not self .is_mine_id (state_key )
307
+ if not is_remote and not await self .store .should_include_local_user_in_dir (
308
+ state_key
309
+ ):
310
+ return
311
+
312
+ if joined is MatchChange .now_false :
313
+ # Need to check if the server left the room entirely, if so
314
+ # we might need to remove all the users in that room
315
+ is_in_room = await self .store .is_host_joined (room_id , self .server_name )
316
+ if not is_in_room :
317
+ logger .debug ("Server left room: %r" , room_id )
318
+ # Fetch all the users that we marked as being in user
319
+ # directory due to being in the room and then check if
320
+ # need to remove those users or not
321
+ user_ids = await self .store .get_users_in_dir_due_to_room (room_id )
322
+
323
+ for user_id in user_ids :
324
+ await self ._handle_remove_user (room_id , user_id )
325
+ else :
326
+ logger .debug ("Server is still in room: %r" , room_id )
327
+ await self ._handle_remove_user (room_id , state_key )
328
+ elif joined is MatchChange .no_change :
329
+ # Handle any profile changes for remote users.
330
+ # (For local users the rest of the application calls
331
+ # `handle_local_profile_change`.)
332
+ if is_remote :
333
+ await self ._handle_possible_remote_profile_change (
334
+ state_key , room_id , prev_event_id , event_id
335
+ )
336
+ elif joined is MatchChange .now_true : # The user joined
337
+ # This may be the first time we've seen a remote user. If
338
+ # so, ensure we have a directory entry for them. (For local users,
339
+ # the rest of the application calls `handle_local_profile_change`.)
340
+ if is_remote :
341
+ await self ._upsert_directory_entry_for_remote_user (state_key , event_id )
342
+ await self ._track_user_joined_room (room_id , state_key )
343
+
329
344
async def _upsert_directory_entry_for_remote_user (
330
345
self , user_id : str , event_id : str
331
346
) -> None :
@@ -386,7 +401,12 @@ async def _track_user_joined_room(self, room_id: str, user_id: str) -> None:
386
401
await self .store .add_users_who_share_private_room (room_id , to_insert )
387
402
388
403
async def _handle_remove_user (self , room_id : str , user_id : str ) -> None :
389
- """Called when we might need to remove user from directory
404
+ """Called when when someone leaves a room. The user may be local or remote.
405
+
406
+ (If the person who left was the last local user in this room, the server
407
+ is no longer in the room. We call this function to forget that the remaining
408
+ remote users are in the room, even though they haven't left. So the name is
409
+ a little misleading!)
390
410
391
411
Args:
392
412
room_id: The room ID that user left or stopped being public that
@@ -403,15 +423,16 @@ async def _handle_remove_user(self, room_id: str, user_id: str) -> None:
403
423
if len (rooms_user_is_in ) == 0 :
404
424
await self .store .remove_from_user_dir (user_id )
405
425
406
- async def _handle_profile_change (
426
+ async def _handle_possible_remote_profile_change (
407
427
self ,
408
428
user_id : str ,
409
429
room_id : str ,
410
430
prev_event_id : Optional [str ],
411
431
event_id : Optional [str ],
412
432
) -> None :
413
433
"""Check member event changes for any profile changes and update the
414
- database if there are.
434
+ database if there are. This is intended for remote users only. The caller
435
+ is responsible for checking that the given user is remote.
415
436
"""
416
437
if not prev_event_id or not event_id :
417
438
return
0 commit comments