@@ -279,8 +279,19 @@ def _get_users_in_room_with_profiles(
279
279
280
280
@cached (max_entries = 100000 ) # type: ignore[synapse-@cached-mutable]
281
281
async def get_room_summary (self , room_id : str ) -> Mapping [str , MemberSummary ]:
282
- """Get the details of a room roughly suitable for use by the room
282
+ """
283
+ Get the details of a room roughly suitable for use by the room
283
284
summary extension to /sync. Useful when lazy loading room members.
285
+
286
+ Returns the total count of members in the room by membership type, and a
287
+ truncated list of members (the heroes). This will be the first 6 members of the
288
+ room:
289
+ - We want 5 heroes plus 1, in case one of them is the
290
+ calling user.
291
+ - They are ordered by `stream_ordering`, which are joined or
292
+ invited. When no joined or invited members are available, this also includes
293
+ banned and left users.
294
+
284
295
Args:
285
296
room_id: The room ID to query
286
297
Returns:
@@ -308,23 +319,36 @@ def _get_room_summary_txn(
308
319
for count , membership in txn :
309
320
res .setdefault (membership , MemberSummary ([], count ))
310
321
311
- # we order by membership and then fairly arbitrarily by event_id so
312
- # heroes are consistent
313
- # Note, rejected events will have a null membership field, so
314
- # we we manually filter them out.
322
+ # Order by membership (joins -> invites -> leave (former insiders) ->
323
+ # everything else (outsiders like bans/knocks), then by `stream_ordering` so
324
+ # the first members in the room show up first and to make the sort stable
325
+ # (consistent heroes).
326
+ #
327
+ # Note: rejected events will have a null membership field, so we we manually
328
+ # filter them out.
315
329
sql = """
316
330
SELECT state_key, membership, event_id
317
331
FROM current_state_events
318
332
WHERE type = 'm.room.member' AND room_id = ?
319
333
AND membership IS NOT NULL
320
334
ORDER BY
321
- CASE membership WHEN ? THEN 1 WHEN ? THEN 2 ELSE 3 END ASC,
322
- event_id ASC
335
+ CASE membership WHEN ? THEN 1 WHEN ? THEN 2 WHEN ? THEN 3 ELSE 4 END ASC,
336
+ event_stream_ordering ASC
323
337
LIMIT ?
324
338
"""
325
339
326
- # 6 is 5 (number of heroes) plus 1, in case one of them is the calling user.
327
- txn .execute (sql , (room_id , Membership .JOIN , Membership .INVITE , 6 ))
340
+ txn .execute (
341
+ sql ,
342
+ (
343
+ room_id ,
344
+ # Sort order
345
+ Membership .JOIN ,
346
+ Membership .INVITE ,
347
+ Membership .LEAVE ,
348
+ # 6 is 5 (number of heroes) plus 1, in case one of them is the calling user.
349
+ 6 ,
350
+ ),
351
+ )
328
352
for user_id , membership , event_id in txn :
329
353
summary = res [membership ]
330
354
# we will always have a summary for this membership type at this
@@ -1509,10 +1533,19 @@ def extract_heroes_from_room_summary(
1509
1533
) -> List [str ]:
1510
1534
"""Determine the users that represent a room, from the perspective of the `me` user.
1511
1535
1536
+ This function expects `MemberSummary.members` to already be sorted by
1537
+ `stream_ordering` like the results from `get_room_summary(...)`.
1538
+
1512
1539
The rules which say which users we select are specified in the "Room Summary"
1513
1540
section of
1514
1541
https://spec.matrix.org/v1.4/client-server-api/#get_matrixclientv3sync
1515
1542
1543
+
1544
+ Args:
1545
+ details: Mapping from membership type to member summary. We expect
1546
+ `MemberSummary.members` to already be sorted by `stream_ordering`.
1547
+ me: The user for whom we are determining the heroes for.
1548
+
1516
1549
Returns a list (possibly empty) of heroes' mxids.
1517
1550
"""
1518
1551
empty_ms = MemberSummary ([], 0 )
@@ -1527,11 +1560,11 @@ def extract_heroes_from_room_summary(
1527
1560
r [0 ] for r in details .get (Membership .LEAVE , empty_ms ).members if r [0 ] != me
1528
1561
] + [r [0 ] for r in details .get (Membership .BAN , empty_ms ).members if r [0 ] != me ]
1529
1562
1530
- # FIXME: order by stream ordering rather than as returned by SQL
1563
+ # We expect `MemberSummary.members` to already be sorted by `stream_ordering`
1531
1564
if joined_user_ids or invited_user_ids :
1532
- return sorted (joined_user_ids + invited_user_ids )[0 :5 ]
1565
+ return (joined_user_ids + invited_user_ids )[0 :5 ]
1533
1566
else :
1534
- return sorted ( gone_user_ids ) [0 :5 ]
1567
+ return gone_user_ids [0 :5 ]
1535
1568
1536
1569
1537
1570
@attr .s (slots = True , auto_attribs = True )
0 commit comments