@@ -1506,16 +1506,22 @@ async def _generate_sync_entry_for_rooms(
15061506 account_data_by_room: Dictionary of per room account data
15071507
15081508 Returns:
1509- Returns a 4-tuple whose entries are:
1509+ Returns a 4-tuple describing rooms the user has joined or left, and users who've
1510+ joined or left rooms any rooms the user is in. This gets used later in
1511+ `_generate_sync_entry_for_device_list`.
1512+
1513+ Its entries are:
15101514 - newly_joined_rooms
15111515 - newly_joined_or_invited_or_knocked_users
15121516 - newly_left_rooms
15131517 - newly_left_users
15141518 """
1515- # Start by fetching all ephemeral events in rooms we've joined (if required).
1519+ since_token = sync_result_builder .since_token
1520+
1521+ # 1. Start by fetching all ephemeral events in rooms we've joined (if required).
15161522 user_id = sync_result_builder .sync_config .user .to_string ()
15171523 block_all_room_ephemeral = (
1518- sync_result_builder . since_token is None
1524+ since_token is None
15191525 and sync_result_builder .sync_config .filter_collection .blocks_all_room_ephemeral ()
15201526 )
15211527
@@ -1529,9 +1535,8 @@ async def _generate_sync_entry_for_rooms(
15291535 )
15301536 sync_result_builder .now_token = now_token
15311537
1532- # We check up front if anything has changed, if it hasn't then there is
1538+ # 2. We check up front if anything has changed, if it hasn't then there is
15331539 # no point in going further.
1534- since_token = sync_result_builder .since_token
15351540 if not sync_result_builder .full_state :
15361541 if since_token and not ephemeral_by_room and not account_data_by_room :
15371542 have_changed = await self ._have_rooms_changed (sync_result_builder )
@@ -1544,20 +1549,8 @@ async def _generate_sync_entry_for_rooms(
15441549 logger .debug ("no-oping sync" )
15451550 return set (), set (), set (), set ()
15461551
1547- ignored_account_data = (
1548- await self .store .get_global_account_data_by_type_for_user (
1549- AccountDataTypes .IGNORED_USER_LIST , user_id = user_id
1550- )
1551- )
1552-
1553- # If there is ignored users account data and it matches the proper type,
1554- # then use it.
1555- ignored_users : FrozenSet [str ] = frozenset ()
1556- if ignored_account_data :
1557- ignored_users_data = ignored_account_data .get ("ignored_users" , {})
1558- if isinstance (ignored_users_data , dict ):
1559- ignored_users = frozenset (ignored_users_data .keys ())
1560-
1552+ # 3. Work out which rooms need reporting in the sync response.
1553+ ignored_users = await self ._get_ignored_users (user_id )
15611554 if since_token :
15621555 room_changes = await self ._get_rooms_changed (
15631556 sync_result_builder , ignored_users
@@ -1567,7 +1560,6 @@ async def _generate_sync_entry_for_rooms(
15671560 )
15681561 else :
15691562 room_changes = await self ._get_all_rooms (sync_result_builder , ignored_users )
1570-
15711563 tags_by_room = await self .store .get_tags_for_user (user_id )
15721564
15731565 log_kv ({"rooms_changed" : len (room_changes .room_entries )})
@@ -1578,6 +1570,8 @@ async def _generate_sync_entry_for_rooms(
15781570 newly_joined_rooms = room_changes .newly_joined_rooms
15791571 newly_left_rooms = room_changes .newly_left_rooms
15801572
1573+ # 4. We need to apply further processing to `room_entries` (rooms considered
1574+ # joined or archived).
15811575 async def handle_room_entries (room_entry : "RoomSyncResultBuilder" ) -> None :
15821576 logger .debug ("Generating room entry for %s" , room_entry .room_id )
15831577 await self ._generate_room_entry (
@@ -1596,31 +1590,13 @@ async def handle_room_entries(room_entry: "RoomSyncResultBuilder") -> None:
15961590 sync_result_builder .invited .extend (invited )
15971591 sync_result_builder .knocked .extend (knocked )
15981592
1599- # Now we want to get any newly joined, invited or knocking users
1600- newly_joined_or_invited_or_knocked_users = set ()
1601- newly_left_users = set ()
1602- if since_token :
1603- for joined_sync in sync_result_builder .joined :
1604- it = itertools .chain (
1605- joined_sync .timeline .events , joined_sync .state .values ()
1606- )
1607- for event in it :
1608- if event .type == EventTypes .Member :
1609- if (
1610- event .membership == Membership .JOIN
1611- or event .membership == Membership .INVITE
1612- or event .membership == Membership .KNOCK
1613- ):
1614- newly_joined_or_invited_or_knocked_users .add (
1615- event .state_key
1616- )
1617- else :
1618- prev_content = event .unsigned .get ("prev_content" , {})
1619- prev_membership = prev_content .get ("membership" , None )
1620- if prev_membership == Membership .JOIN :
1621- newly_left_users .add (event .state_key )
1622-
1623- newly_left_users -= newly_joined_or_invited_or_knocked_users
1593+ # 5. Work out which users have joined or left rooms we're in. We use this
1594+ # to build the device_list part of the sync response in
1595+ # `_generate_sync_entry_for_device_list`.
1596+ (
1597+ newly_joined_or_invited_or_knocked_users ,
1598+ newly_left_users ,
1599+ ) = sync_result_builder .calculate_user_changes ()
16241600
16251601 return (
16261602 set (newly_joined_rooms ),
@@ -1629,6 +1605,29 @@ async def handle_room_entries(room_entry: "RoomSyncResultBuilder") -> None:
16291605 newly_left_users ,
16301606 )
16311607
1608+ async def _get_ignored_users (self , user_id : str ) -> FrozenSet [str ]:
1609+ """Retrieve the users ignored by the given user from their global account_data.
1610+
1611+ Returns an empty set if
1612+ - there is no global account_data entry for ignored_users
1613+ - there is such an entry, but it's not a JSON object.
1614+ """
1615+ # TODO: Can we `SELECT ignored_user_id FROM ignored_users WHERE ignorer_user_id=?;` instead?
1616+ ignored_account_data = (
1617+ await self .store .get_global_account_data_by_type_for_user (
1618+ AccountDataTypes .IGNORED_USER_LIST , user_id = user_id
1619+ )
1620+ )
1621+
1622+ # If there is ignored users account data and it matches the proper type,
1623+ # then use it.
1624+ ignored_users : FrozenSet [str ] = frozenset ()
1625+ if ignored_account_data :
1626+ ignored_users_data = ignored_account_data .get ("ignored_users" , {})
1627+ if isinstance (ignored_users_data , dict ):
1628+ ignored_users = frozenset (ignored_users_data .keys ())
1629+ return ignored_users
1630+
16321631 async def _have_rooms_changed (
16331632 self , sync_result_builder : "SyncResultBuilder"
16341633 ) -> bool :
@@ -2341,6 +2340,39 @@ class SyncResultBuilder:
23412340 groups : Optional [GroupsSyncResult ] = None
23422341 to_device : List [JsonDict ] = attr .Factory (list )
23432342
2343+ def calculate_user_changes (self ) -> Tuple [Set [str ], Set [str ]]:
2344+ """Work out which other users have joined or left rooms we are joined to.
2345+
2346+ This data only is only useful for an incremental sync.
2347+
2348+ The SyncResultBuilder is not modified by this function.
2349+ """
2350+ newly_joined_or_invited_or_knocked_users = set ()
2351+ newly_left_users = set ()
2352+ if self .since_token :
2353+ for joined_sync in self .joined :
2354+ it = itertools .chain (
2355+ joined_sync .timeline .events , joined_sync .state .values ()
2356+ )
2357+ for event in it :
2358+ if event .type == EventTypes .Member :
2359+ if (
2360+ event .membership == Membership .JOIN
2361+ or event .membership == Membership .INVITE
2362+ or event .membership == Membership .KNOCK
2363+ ):
2364+ newly_joined_or_invited_or_knocked_users .add (
2365+ event .state_key
2366+ )
2367+ else :
2368+ prev_content = event .unsigned .get ("prev_content" , {})
2369+ prev_membership = prev_content .get ("membership" , None )
2370+ if prev_membership == Membership .JOIN :
2371+ newly_left_users .add (event .state_key )
2372+
2373+ newly_left_users -= newly_joined_or_invited_or_knocked_users
2374+ return newly_joined_or_invited_or_knocked_users , newly_left_users
2375+
23442376
23452377@attr .s (slots = True , auto_attribs = True )
23462378class RoomSyncResultBuilder :
0 commit comments