Refactors in _generate_sync_entry_for_rooms (#11515)

* Move sync_token up to the top
* Pull out _get_ignored_users
* Try to signpost the body of `_generate_sync_entry_for_rooms`
* Pull out _calculate_user_changes

Co-authored-by: Patrick Cloke <clokep@users.noreply.github.com>
This commit is contained in:
David Robertson 2021-12-07 12:42:05 +00:00 committed by GitHub
parent 2a3ec6facf
commit 14d593f72d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 79 additions and 46 deletions

View File

@ -1 +1 @@
Add comments to various parts of the `/sync` handler. Refactor various parts of the `/sync` handler.

1
changelog.d/11515.misc Normal file
View File

@ -0,0 +1 @@
Refactor various parts of the `/sync` handler.

View File

@ -1506,16 +1506,22 @@ class SyncHandler:
account_data_by_room: Dictionary of per room account data account_data_by_room: Dictionary of per room account data
Returns: Returns:
Returns a 4-tuple whose entries are: Returns a 4-tuple describing rooms the user has joined or left, and users who've
joined or left rooms any rooms the user is in. This gets used later in
`_generate_sync_entry_for_device_list`.
Its entries are:
- newly_joined_rooms - newly_joined_rooms
- newly_joined_or_invited_or_knocked_users - newly_joined_or_invited_or_knocked_users
- newly_left_rooms - newly_left_rooms
- newly_left_users - newly_left_users
""" """
# Start by fetching all ephemeral events in rooms we've joined (if required). since_token = sync_result_builder.since_token
# 1. Start by fetching all ephemeral events in rooms we've joined (if required).
user_id = sync_result_builder.sync_config.user.to_string() user_id = sync_result_builder.sync_config.user.to_string()
block_all_room_ephemeral = ( block_all_room_ephemeral = (
sync_result_builder.since_token is None since_token is None
and sync_result_builder.sync_config.filter_collection.blocks_all_room_ephemeral() and sync_result_builder.sync_config.filter_collection.blocks_all_room_ephemeral()
) )
@ -1529,9 +1535,8 @@ class SyncHandler:
) )
sync_result_builder.now_token = now_token sync_result_builder.now_token = now_token
# We check up front if anything has changed, if it hasn't then there is # 2. We check up front if anything has changed, if it hasn't then there is
# no point in going further. # no point in going further.
since_token = sync_result_builder.since_token
if not sync_result_builder.full_state: if not sync_result_builder.full_state:
if since_token and not ephemeral_by_room and not account_data_by_room: if since_token and not ephemeral_by_room and not account_data_by_room:
have_changed = await self._have_rooms_changed(sync_result_builder) have_changed = await self._have_rooms_changed(sync_result_builder)
@ -1544,20 +1549,8 @@ class SyncHandler:
logger.debug("no-oping sync") logger.debug("no-oping sync")
return set(), set(), set(), set() return set(), set(), set(), set()
ignored_account_data = ( # 3. Work out which rooms need reporting in the sync response.
await self.store.get_global_account_data_by_type_for_user( ignored_users = await self._get_ignored_users(user_id)
AccountDataTypes.IGNORED_USER_LIST, user_id=user_id
)
)
# If there is ignored users account data and it matches the proper type,
# then use it.
ignored_users: FrozenSet[str] = frozenset()
if ignored_account_data:
ignored_users_data = ignored_account_data.get("ignored_users", {})
if isinstance(ignored_users_data, dict):
ignored_users = frozenset(ignored_users_data.keys())
if since_token: if since_token:
room_changes = await self._get_rooms_changed( room_changes = await self._get_rooms_changed(
sync_result_builder, ignored_users sync_result_builder, ignored_users
@ -1567,7 +1560,6 @@ class SyncHandler:
) )
else: else:
room_changes = await self._get_all_rooms(sync_result_builder, ignored_users) room_changes = await self._get_all_rooms(sync_result_builder, ignored_users)
tags_by_room = await self.store.get_tags_for_user(user_id) tags_by_room = await self.store.get_tags_for_user(user_id)
log_kv({"rooms_changed": len(room_changes.room_entries)}) log_kv({"rooms_changed": len(room_changes.room_entries)})
@ -1578,6 +1570,8 @@ class SyncHandler:
newly_joined_rooms = room_changes.newly_joined_rooms newly_joined_rooms = room_changes.newly_joined_rooms
newly_left_rooms = room_changes.newly_left_rooms newly_left_rooms = room_changes.newly_left_rooms
# 4. We need to apply further processing to `room_entries` (rooms considered
# joined or archived).
async def handle_room_entries(room_entry: "RoomSyncResultBuilder") -> None: async def handle_room_entries(room_entry: "RoomSyncResultBuilder") -> None:
logger.debug("Generating room entry for %s", room_entry.room_id) logger.debug("Generating room entry for %s", room_entry.room_id)
await self._generate_room_entry( await self._generate_room_entry(
@ -1596,31 +1590,13 @@ class SyncHandler:
sync_result_builder.invited.extend(invited) sync_result_builder.invited.extend(invited)
sync_result_builder.knocked.extend(knocked) sync_result_builder.knocked.extend(knocked)
# Now we want to get any newly joined, invited or knocking users # 5. Work out which users have joined or left rooms we're in. We use this
newly_joined_or_invited_or_knocked_users = set() # to build the device_list part of the sync response in
newly_left_users = set() # `_generate_sync_entry_for_device_list`.
if since_token: (
for joined_sync in sync_result_builder.joined: newly_joined_or_invited_or_knocked_users,
it = itertools.chain( newly_left_users,
joined_sync.timeline.events, joined_sync.state.values() ) = sync_result_builder.calculate_user_changes()
)
for event in it:
if event.type == EventTypes.Member:
if (
event.membership == Membership.JOIN
or event.membership == Membership.INVITE
or event.membership == Membership.KNOCK
):
newly_joined_or_invited_or_knocked_users.add(
event.state_key
)
else:
prev_content = event.unsigned.get("prev_content", {})
prev_membership = prev_content.get("membership", None)
if prev_membership == Membership.JOIN:
newly_left_users.add(event.state_key)
newly_left_users -= newly_joined_or_invited_or_knocked_users
return ( return (
set(newly_joined_rooms), set(newly_joined_rooms),
@ -1629,6 +1605,29 @@ class SyncHandler:
newly_left_users, newly_left_users,
) )
async def _get_ignored_users(self, user_id: str) -> FrozenSet[str]:
"""Retrieve the users ignored by the given user from their global account_data.
Returns an empty set if
- there is no global account_data entry for ignored_users
- there is such an entry, but it's not a JSON object.
"""
# TODO: Can we `SELECT ignored_user_id FROM ignored_users WHERE ignorer_user_id=?;` instead?
ignored_account_data = (
await self.store.get_global_account_data_by_type_for_user(
AccountDataTypes.IGNORED_USER_LIST, user_id=user_id
)
)
# If there is ignored users account data and it matches the proper type,
# then use it.
ignored_users: FrozenSet[str] = frozenset()
if ignored_account_data:
ignored_users_data = ignored_account_data.get("ignored_users", {})
if isinstance(ignored_users_data, dict):
ignored_users = frozenset(ignored_users_data.keys())
return ignored_users
async def _have_rooms_changed( async def _have_rooms_changed(
self, sync_result_builder: "SyncResultBuilder" self, sync_result_builder: "SyncResultBuilder"
) -> bool: ) -> bool:
@ -2341,6 +2340,39 @@ class SyncResultBuilder:
groups: Optional[GroupsSyncResult] = None groups: Optional[GroupsSyncResult] = None
to_device: List[JsonDict] = attr.Factory(list) to_device: List[JsonDict] = attr.Factory(list)
def calculate_user_changes(self) -> Tuple[Set[str], Set[str]]:
"""Work out which other users have joined or left rooms we are joined to.
This data only is only useful for an incremental sync.
The SyncResultBuilder is not modified by this function.
"""
newly_joined_or_invited_or_knocked_users = set()
newly_left_users = set()
if self.since_token:
for joined_sync in self.joined:
it = itertools.chain(
joined_sync.timeline.events, joined_sync.state.values()
)
for event in it:
if event.type == EventTypes.Member:
if (
event.membership == Membership.JOIN
or event.membership == Membership.INVITE
or event.membership == Membership.KNOCK
):
newly_joined_or_invited_or_knocked_users.add(
event.state_key
)
else:
prev_content = event.unsigned.get("prev_content", {})
prev_membership = prev_content.get("membership", None)
if prev_membership == Membership.JOIN:
newly_left_users.add(event.state_key)
newly_left_users -= newly_joined_or_invited_or_knocked_users
return newly_joined_or_invited_or_knocked_users, newly_left_users
@attr.s(slots=True, auto_attribs=True) @attr.s(slots=True, auto_attribs=True)
class RoomSyncResultBuilder: class RoomSyncResultBuilder: