From 16a21470dd91c3f6490e1d74709e3947c5029511 Mon Sep 17 00:00:00 2001 From: Michael Hollister Date: Sun, 10 Mar 2024 22:54:48 -0500 Subject: [PATCH 01/10] Added presence update on change of profile information and config flags for selective presence tracking Signed-off-by: Michael Hollister --- changelog.d/16992.feature | 1 + synapse/api/presence.py | 4 ++ synapse/config/server.py | 10 +++++ synapse/federation/federation_server.py | 11 +++++ synapse/handlers/presence.py | 43 +++++++++++++++++-- synapse/handlers/profile.py | 26 +++++++++++ synapse/replication/tcp/streams/_base.py | 2 + synapse/storage/databases/main/presence.py | 26 +++++++++-- synapse/storage/schema/__init__.py | 9 ++-- .../delta/85/01presence_stream_updates.sql | 20 +++++++++ tests/api/test_filtering.py | 4 ++ tests/handlers/test_presence.py | 4 ++ 12 files changed, 150 insertions(+), 10 deletions(-) create mode 100644 changelog.d/16992.feature create mode 100644 synapse/storage/schema/main/delta/85/01presence_stream_updates.sql diff --git a/changelog.d/16992.feature b/changelog.d/16992.feature new file mode 100644 index 0000000000..903916be7e --- /dev/null +++ b/changelog.d/16992.feature @@ -0,0 +1 @@ +Added presence update on change of profile information and config flags for selective presence tracking. Contributed by @Michael-Hollister. diff --git a/synapse/api/presence.py b/synapse/api/presence.py index 28c10403ce..891746dcd1 100644 --- a/synapse/api/presence.py +++ b/synapse/api/presence.py @@ -83,6 +83,8 @@ class UserPresenceState: last_user_sync_ts: int status_msg: Optional[str] currently_active: bool + displayname: Optional[str] + avatar_url: Optional[str] def as_dict(self) -> JsonDict: return attr.asdict(self) @@ -101,4 +103,6 @@ class UserPresenceState: last_user_sync_ts=0, status_msg=None, currently_active=False, + displayname=None, + avatar_url=None, ) diff --git a/synapse/config/server.py b/synapse/config/server.py index a2b2305776..e510205b98 100644 --- a/synapse/config/server.py +++ b/synapse/config/server.py @@ -384,6 +384,16 @@ class ServerConfig(Config): # Whether to internally track presence, requires that presence is enabled, self.track_presence = self.presence_enabled and presence_enabled != "untracked" + # Disabling server-side presence tracking + self.sync_presence_tracking = presence_config.get( + "sync_presence_tracking", True + ) + + # Disabling federation presence tracking + self.federation_presence_tracking = presence_config.get( + "federation_presence_tracking", True + ) + # Custom presence router module # This is the legacy way of configuring it (the config should now be put in the modules section) self.presence_router_module_class = None diff --git a/synapse/federation/federation_server.py b/synapse/federation/federation_server.py index 7ffc650aa1..d8dc1484b0 100644 --- a/synapse/federation/federation_server.py +++ b/synapse/federation/federation_server.py @@ -1428,6 +1428,17 @@ class FederationHandlerRegistry: if not self.config.server.track_presence and edu_type == EduTypes.PRESENCE: return + if ( + not self.config.server.federation_presence_tracking + and edu_type == EduTypes.PRESENCE + ): + filtered_edus = [] + for e in content["push"]: + # Process only profile presence updates to reduce resource impact + if "status_msg" in e or "displayname" in e or "avatar_url" in e: + filtered_edus.append(e) + content["push"] = filtered_edus + # Check if we have a handler on this instance handler = self.edu_handlers.get(edu_type) if handler: diff --git a/synapse/handlers/presence.py b/synapse/handlers/presence.py index 37ee625f71..6ea4cf7867 100644 --- a/synapse/handlers/presence.py +++ b/synapse/handlers/presence.py @@ -201,6 +201,7 @@ class BasePresenceHandler(abc.ABC): self._presence_enabled = hs.config.server.presence_enabled self._track_presence = hs.config.server.track_presence + self._sync_presence_tracking = hs.config.server.sync_presence_tracking self._federation = None if hs.should_send_federation(): @@ -451,6 +452,8 @@ class BasePresenceHandler(abc.ABC): state = { "presence": current_presence_state.state, "status_message": current_presence_state.status_msg, + "displayname": current_presence_state.displayname, + "avatar_url": current_presence_state.avatar_url, } # Copy the presence state to the tip of the presence stream. @@ -579,7 +582,11 @@ class WorkerPresenceHandler(BasePresenceHandler): Called by the sync and events servlets to record that a user has connected to this worker and is waiting for some events. """ - if not affect_presence or not self._track_presence: + if ( + not affect_presence + or not self._track_presence + or not self._sync_presence_tracking + ): return _NullContextManager() # Note that this causes last_active_ts to be incremented which is not @@ -648,6 +655,8 @@ class WorkerPresenceHandler(BasePresenceHandler): row.last_user_sync_ts, row.status_msg, row.currently_active, + row.displayname, + row.avatar_url, ) for row in rows ] @@ -1140,7 +1149,11 @@ class PresenceHandler(BasePresenceHandler): client that is being used by a user. presence_state: The presence state indicated in the sync request """ - if not affect_presence or not self._track_presence: + if ( + not affect_presence + or not self._track_presence + or not self._sync_presence_tracking + ): return _NullContextManager() curr_sync = self._user_device_to_num_current_syncs.get((user_id, device_id), 0) @@ -1340,6 +1353,8 @@ class PresenceHandler(BasePresenceHandler): new_fields["status_msg"] = push.get("status_msg", None) new_fields["currently_active"] = push.get("currently_active", False) + new_fields["displayname"] = push.get("displayname", None) + new_fields["avatar_url"] = push.get("avatar_url", None) prev_state = await self.current_state_for_user(user_id) updates.append(prev_state.copy_and_replace(**new_fields)) @@ -1369,6 +1384,8 @@ class PresenceHandler(BasePresenceHandler): the `state` dict. """ status_msg = state.get("status_msg", None) + displayname = state.get("displayname", None) + avatar_url = state.get("avatar_url", None) presence = state["presence"] if presence not in self.VALID_PRESENCE: @@ -1414,6 +1431,8 @@ class PresenceHandler(BasePresenceHandler): else: # Syncs do not override the status message. new_fields["status_msg"] = status_msg + new_fields["displayname"] = displayname + new_fields["avatar_url"] = avatar_url await self._update_states( [prev_state.copy_and_replace(**new_fields)], force_notify=force_notify @@ -1634,6 +1653,8 @@ class PresenceHandler(BasePresenceHandler): if state.state != PresenceState.OFFLINE or now - state.last_active_ts < 7 * 24 * 60 * 60 * 1000 or state.status_msg is not None + or state.displayname is not None + or state.avatar_url is not None ] await self._federation_queue.send_presence_to_destinations( @@ -1668,6 +1689,14 @@ def should_notify( notify_reason_counter.labels(user_location, "status_msg_change").inc() return True + if old_state.displayname != new_state.displayname: + notify_reason_counter.labels(user_location, "displayname_change").inc() + return True + + if old_state.avatar_url != new_state.avatar_url: + notify_reason_counter.labels(user_location, "avatar_url_change").inc() + return True + if old_state.state != new_state.state: notify_reason_counter.labels(user_location, "state_change").inc() state_transition_counter.labels( @@ -1725,6 +1754,8 @@ def format_user_presence_state( * status_msg: Optional. Included if `status_msg` is set on `state`. The user's status. * currently_active: Optional. Included only if `state.state` is "online". + * displayname: Optional. The current display name for this user, if any. + * avatar_url: Optional. The current avatar URL for this user, if any. Example: @@ -1733,7 +1764,9 @@ def format_user_presence_state( "user_id": "@alice:example.com", "last_active_ago": 16783813918, "status_msg": "Hello world!", - "currently_active": True + "currently_active": True, + "displayname": "Alice", + "avatar_url": "mxc://localhost/wefuiwegh8742w" } """ content: JsonDict = {"presence": state.state} @@ -1745,6 +1778,10 @@ def format_user_presence_state( content["status_msg"] = state.status_msg if state.state == PresenceState.ONLINE: content["currently_active"] = state.currently_active + if state.displayname: + content["displayname"] = state.displayname + if state.avatar_url: + content["avatar_url"] = state.avatar_url return content diff --git a/synapse/handlers/profile.py b/synapse/handlers/profile.py index e51e282a9f..968b3f5fb4 100644 --- a/synapse/handlers/profile.py +++ b/synapse/handlers/profile.py @@ -200,6 +200,19 @@ class ProfileHandler: if propagate: await self._update_join_states(requester, target_user) + if self.hs.config.server.track_presence: + presence_handler = self.hs.get_presence_handler() + current_presence_state = await presence_handler.get_state(target_user) + + state = { + "presence": current_presence_state.state, + "status_message": current_presence_state.status_msg, + "displayname": new_displayname, + "avatar_url": current_presence_state.avatar_url, + } + + await presence_handler.set_state(target_user, requester.device_id, state) + async def get_avatar_url(self, target_user: UserID) -> Optional[str]: if self.hs.is_mine(target_user): try: @@ -293,6 +306,19 @@ class ProfileHandler: if propagate: await self._update_join_states(requester, target_user) + if self.hs.config.server.track_presence: + presence_handler = self.hs.get_presence_handler() + current_presence_state = await presence_handler.get_state(target_user) + + state = { + "presence": current_presence_state.state, + "status_message": current_presence_state.status_msg, + "displayname": current_presence_state.displayname, + "avatar_url": new_avatar_url, + } + + await presence_handler.set_state(target_user, requester.device_id, state) + @cached() async def check_avatar_size_and_mime_type(self, mxc: str) -> bool: """Check that the size and content type of the avatar at the given MXC URI are diff --git a/synapse/replication/tcp/streams/_base.py b/synapse/replication/tcp/streams/_base.py index 661206c841..8e17257e8e 100644 --- a/synapse/replication/tcp/streams/_base.py +++ b/synapse/replication/tcp/streams/_base.py @@ -330,6 +330,8 @@ class PresenceStream(_StreamFromIdGen): last_user_sync_ts: int status_msg: str currently_active: bool + displayname: str + avatar_url: str NAME = "presence" ROW_TYPE = PresenceStreamRow diff --git a/synapse/storage/databases/main/presence.py b/synapse/storage/databases/main/presence.py index 567c2d30bd..f47f787e7c 100644 --- a/synapse/storage/databases/main/presence.py +++ b/synapse/storage/databases/main/presence.py @@ -181,6 +181,8 @@ class PresenceStore(PresenceBackgroundUpdateStore, CacheInvalidationWorkerStore) "last_user_sync_ts", "status_msg", "currently_active", + "displayname", + "avatar_url", "instance_name", ), values=[ @@ -193,6 +195,8 @@ class PresenceStore(PresenceBackgroundUpdateStore, CacheInvalidationWorkerStore) state.last_user_sync_ts, state.status_msg, state.currently_active, + state.displayname, + state.avatar_url, self._instance_name, ) for stream_id, state in zip(stream_orderings, presence_states) @@ -232,7 +236,8 @@ class PresenceStore(PresenceBackgroundUpdateStore, CacheInvalidationWorkerStore) sql = """ SELECT stream_id, user_id, state, last_active_ts, last_federation_update_ts, last_user_sync_ts, - status_msg, currently_active + status_msg, currently_active, displayname, + avatar_url FROM presence_stream WHERE ? < stream_id AND stream_id <= ? ORDER BY stream_id ASC @@ -285,6 +290,8 @@ class PresenceStore(PresenceBackgroundUpdateStore, CacheInvalidationWorkerStore) "last_user_sync_ts", "status_msg", "currently_active", + "displayname", + "avatar_url", ), desc="get_presence_for_users", ), @@ -299,8 +306,10 @@ class PresenceStore(PresenceBackgroundUpdateStore, CacheInvalidationWorkerStore) last_user_sync_ts=last_user_sync_ts, status_msg=status_msg, currently_active=bool(currently_active), + displayname=displayname, + avatar_url=avatar_url, ) - for user_id, state, last_active_ts, last_federation_update_ts, last_user_sync_ts, status_msg, currently_active in rows + for user_id, state, last_active_ts, last_federation_update_ts, last_user_sync_ts, status_msg, currently_active, displayname, avatar_url, in rows } async def should_user_receive_full_presence_with_token( @@ -427,6 +436,8 @@ class PresenceStore(PresenceBackgroundUpdateStore, CacheInvalidationWorkerStore) "last_user_sync_ts", "status_msg", "currently_active", + "displayname", + "avatar_url", ), order_direction="ASC", ), @@ -440,6 +451,8 @@ class PresenceStore(PresenceBackgroundUpdateStore, CacheInvalidationWorkerStore) last_user_sync_ts, status_msg, currently_active, + displayname, + avatar_url, ) in rows: users_to_state[user_id] = UserPresenceState( user_id=user_id, @@ -449,6 +462,8 @@ class PresenceStore(PresenceBackgroundUpdateStore, CacheInvalidationWorkerStore) last_user_sync_ts=last_user_sync_ts, status_msg=status_msg, currently_active=bool(currently_active), + displayname=displayname, + avatar_url=avatar_url, ) # We've run out of updates to query @@ -471,7 +486,8 @@ class PresenceStore(PresenceBackgroundUpdateStore, CacheInvalidationWorkerStore) # query. sql = ( "SELECT user_id, state, last_active_ts, last_federation_update_ts," - " last_user_sync_ts, status_msg, currently_active FROM presence_stream" + " last_user_sync_ts, status_msg, currently_active, displayname, avatar_url " + " FROM presence_stream" " WHERE state != ?" ) @@ -489,8 +505,10 @@ class PresenceStore(PresenceBackgroundUpdateStore, CacheInvalidationWorkerStore) last_user_sync_ts=last_user_sync_ts, status_msg=status_msg, currently_active=bool(currently_active), + displayname=displayname, + avatar_url=avatar_url, ) - for user_id, state, last_active_ts, last_federation_update_ts, last_user_sync_ts, status_msg, currently_active in rows + for user_id, state, last_active_ts, last_federation_update_ts, last_user_sync_ts, status_msg, currently_active, displayname, avatar_url, in rows ] def take_presence_startup_info(self) -> List[UserPresenceState]: diff --git a/synapse/storage/schema/__init__.py b/synapse/storage/schema/__init__.py index 0dc5d24249..203a601f3b 100644 --- a/synapse/storage/schema/__init__.py +++ b/synapse/storage/schema/__init__.py @@ -19,7 +19,7 @@ # # -SCHEMA_VERSION = 85 # remember to update the list below when updating +SCHEMA_VERSION = 86 # remember to update the list below when updating """Represents the expectations made by the codebase about the database schema This should be incremented whenever the codebase changes its requirements on the @@ -139,12 +139,15 @@ Changes in SCHEMA_VERSION = 84 Changes in SCHEMA_VERSION = 85 - Add a column `suspended` to the `users` table + +Changes in SCHEMA_VERSION = 86 + - Added displayname and avatar_url columns to presence_stream """ SCHEMA_COMPAT_VERSION = ( - # Transitive links are no longer written to `event_auth_chain_links` - 84 + # Added displayname and avatar_url columns to presence_stream + 86 ) """Limit on how far the synapse codebase can be rolled back without breaking db compat diff --git a/synapse/storage/schema/main/delta/85/01presence_stream_updates.sql b/synapse/storage/schema/main/delta/85/01presence_stream_updates.sql new file mode 100644 index 0000000000..54a32ba3a8 --- /dev/null +++ b/synapse/storage/schema/main/delta/85/01presence_stream_updates.sql @@ -0,0 +1,20 @@ +-- +-- This file is licensed under the Affero General Public License (AGPL) version 3. +-- +-- Copyright (C) 2023 New Vector, Ltd +-- +-- +-- This file is licensed under the Affero General Public License (AGPL) version 3. +-- +-- Copyright (C) 2024 New Vector, Ltd +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU Affero General Public License as +-- published by the Free Software Foundation, either version 3 of the +-- License, or (at your option) any later version. +-- +-- See the GNU Affero General Public License for more details: +-- . + +ALTER TABLE presence_stream ADD COLUMN displayname TEXT; +ALTER TABLE presence_stream ADD COLUMN avatar_url TEXT; diff --git a/tests/api/test_filtering.py b/tests/api/test_filtering.py index 743c52d969..0051653026 100644 --- a/tests/api/test_filtering.py +++ b/tests/api/test_filtering.py @@ -450,6 +450,8 @@ class FilteringTestCase(unittest.HomeserverTestCase): last_user_sync_ts=0, status_msg=None, currently_active=False, + displayname=None, + avatar_url=None, ), ] @@ -478,6 +480,8 @@ class FilteringTestCase(unittest.HomeserverTestCase): last_user_sync_ts=0, status_msg=None, currently_active=False, + displayname=None, + avatar_url=None, ), ] diff --git a/tests/handlers/test_presence.py b/tests/handlers/test_presence.py index cc630d606c..ae99bda15e 100644 --- a/tests/handlers/test_presence.py +++ b/tests/handlers/test_presence.py @@ -366,6 +366,8 @@ class PresenceUpdateTestCase(unittest.HomeserverTestCase): last_user_sync_ts=1, status_msg="I'm online!", currently_active=True, + displayname=None, + avatar_url=None, ) presence_states.append(presence_state) @@ -718,6 +720,8 @@ class PresenceHandlerInitTestCase(unittest.HomeserverTestCase): last_user_sync_ts=now, status_msg=None, currently_active=True, + displayname=None, + avatar_url=None, ) ] ) From c893e5a577cb290507150d77cd390048e3b6e150 Mon Sep 17 00:00:00 2001 From: Michael Hollister Date: Wed, 1 May 2024 13:37:47 -0500 Subject: [PATCH 02/10] Added missing type hints to DB queries --- synapse/storage/databases/main/presence.py | 28 ++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/synapse/storage/databases/main/presence.py b/synapse/storage/databases/main/presence.py index f47f787e7c..70c81e0c5e 100644 --- a/synapse/storage/databases/main/presence.py +++ b/synapse/storage/databases/main/presence.py @@ -276,7 +276,19 @@ class PresenceStore(PresenceBackgroundUpdateStore, CacheInvalidationWorkerStore) # TODO All these columns are nullable, but we don't expect that: # https://github.com/matrix-org/synapse/issues/16467 rows = cast( - List[Tuple[str, str, int, int, int, Optional[str], Union[int, bool]]], + List[ + Tuple[ + str, + str, + int, + int, + int, + Optional[str], + Union[int, bool], + Optional[str], + Optional[str], + ] + ], await self.db_pool.simple_select_many_batch( table="presence_stream", column="user_id", @@ -419,7 +431,19 @@ class PresenceStore(PresenceBackgroundUpdateStore, CacheInvalidationWorkerStore) # TODO All these columns are nullable, but we don't expect that: # https://github.com/matrix-org/synapse/issues/16467 rows = cast( - List[Tuple[str, str, int, int, int, Optional[str], Union[int, bool]]], + List[ + Tuple[ + str, + str, + int, + int, + int, + Optional[str], + Union[int, bool], + Optional[str], + Optional[str], + ] + ], await self.db_pool.runInteraction( "get_presence_for_all_users", self.db_pool.simple_select_list_paginate_txn, From a38f805ff34b7997ec06ec86e4344f8e7afc83d4 Mon Sep 17 00:00:00 2001 From: Michael Hollister Date: Wed, 1 May 2024 13:44:12 -0500 Subject: [PATCH 03/10] Updating DB schema to 86 due to rebase with develop --- .../01_presence_stream_updates.sql} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename synapse/storage/schema/main/delta/{85/01presence_stream_updates.sql => 86/01_presence_stream_updates.sql} (100%) diff --git a/synapse/storage/schema/main/delta/85/01presence_stream_updates.sql b/synapse/storage/schema/main/delta/86/01_presence_stream_updates.sql similarity index 100% rename from synapse/storage/schema/main/delta/85/01presence_stream_updates.sql rename to synapse/storage/schema/main/delta/86/01_presence_stream_updates.sql From fbbd8ed6beb1c258e4030ad269b1099f3a02302c Mon Sep 17 00:00:00 2001 From: Michael Hollister Date: Wed, 1 May 2024 14:20:17 -0500 Subject: [PATCH 04/10] Added documentation for configuring new presence tracking options --- docs/usage/configuration/config_documentation.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/usage/configuration/config_documentation.md b/docs/usage/configuration/config_documentation.md index 0c582d0387..2c1f46bca1 100644 --- a/docs/usage/configuration/config_documentation.md +++ b/docs/usage/configuration/config_documentation.md @@ -246,6 +246,8 @@ Example configuration: ```yaml presence: enabled: false + sync_presence_tracking: true + federation_presence_tracking: true ``` `enabled` can also be set to a special value of "untracked" which ignores updates @@ -254,6 +256,18 @@ received via clients and federation, while still accepting updates from the *The "untracked" option was added in Synapse 1.96.0.* +Enabling presence tracking can be resource intensive for the presence handler when server-side +tracking of user activity is enabled. Below are some additional configuration options if you +require additional performance: +* `sync_presence_tracking` (Default enabled): Determines if the server tracks a user's presence +activity when syncing. If disabled, the server will not automatically update the user's presence +activity when the sync endpoint is called. Note that client applications can still update their +presence by calling the respective presence endpoints. +* `federation_presence_tracking` (Default enabled): Determines if the server will accept +presence EDUs that only contain presence activity updates. If disabled, the server will drop +processing EDUs that do not contain updates to the `status_msg`, `displayname`, and +`avatar_url` fields. + --- ### `require_auth_for_profile_requests` From cccb26f206f67a9e2fc5f1669b2007261e825af9 Mon Sep 17 00:00:00 2001 From: Michael Hollister Date: Wed, 1 May 2024 14:22:28 -0500 Subject: [PATCH 05/10] Removed duplicate license comment block --- .../schema/main/delta/86/01_presence_stream_updates.sql | 5 ----- 1 file changed, 5 deletions(-) diff --git a/synapse/storage/schema/main/delta/86/01_presence_stream_updates.sql b/synapse/storage/schema/main/delta/86/01_presence_stream_updates.sql index 54a32ba3a8..046fef3193 100644 --- a/synapse/storage/schema/main/delta/86/01_presence_stream_updates.sql +++ b/synapse/storage/schema/main/delta/86/01_presence_stream_updates.sql @@ -1,11 +1,6 @@ -- -- This file is licensed under the Affero General Public License (AGPL) version 3. -- --- Copyright (C) 2023 New Vector, Ltd --- --- --- This file is licensed under the Affero General Public License (AGPL) version 3. --- -- Copyright (C) 2024 New Vector, Ltd -- -- This program is free software: you can redistribute it and/or modify From 89d8b32af729d4d6cdfed2c7b46198f0ba7c1d86 Mon Sep 17 00:00:00 2001 From: Michael Hollister Date: Thu, 30 May 2024 15:24:30 -0500 Subject: [PATCH 06/10] Improved wording of presence tracking documentation Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> --- docs/usage/configuration/config_documentation.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/usage/configuration/config_documentation.md b/docs/usage/configuration/config_documentation.md index 2c1f46bca1..74a5c2ebae 100644 --- a/docs/usage/configuration/config_documentation.md +++ b/docs/usage/configuration/config_documentation.md @@ -257,15 +257,15 @@ received via clients and federation, while still accepting updates from the *The "untracked" option was added in Synapse 1.96.0.* Enabling presence tracking can be resource intensive for the presence handler when server-side -tracking of user activity is enabled. Below are some additional configuration options if you -require additional performance: +tracking of user activity is enabled. Below are some additional configuration options which may +help improve the performance of the presence feature without outright disabling it: * `sync_presence_tracking` (Default enabled): Determines if the server tracks a user's presence activity when syncing. If disabled, the server will not automatically update the user's presence activity when the sync endpoint is called. Note that client applications can still update their presence by calling the respective presence endpoints. * `federation_presence_tracking` (Default enabled): Determines if the server will accept presence EDUs that only contain presence activity updates. If disabled, the server will drop -processing EDUs that do not contain updates to the `status_msg`, `displayname`, and +processing EDUs that do not contain updates to the `status_msg`, `displayname`, or `avatar_url` fields. --- From 6b12d3ec6c48b82762cbbf60cb266520248b20c8 Mon Sep 17 00:00:00 2001 From: Michael Hollister Date: Thu, 30 May 2024 22:45:38 -0500 Subject: [PATCH 07/10] Improved wording of documentation and config option naming --- .../configuration/config_documentation.md | 23 +++++++++++-------- synapse/config/server.py | 8 +++---- synapse/federation/federation_server.py | 12 +++++++++- synapse/handlers/presence.py | 8 ++++--- 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/docs/usage/configuration/config_documentation.md b/docs/usage/configuration/config_documentation.md index 74a5c2ebae..dad99bb74f 100644 --- a/docs/usage/configuration/config_documentation.md +++ b/docs/usage/configuration/config_documentation.md @@ -246,8 +246,8 @@ Example configuration: ```yaml presence: enabled: false - sync_presence_tracking: true - federation_presence_tracking: true + local_activity_tracking: true + remote_activity_tracking: true ``` `enabled` can also be set to a special value of "untracked" which ignores updates @@ -259,14 +259,17 @@ received via clients and federation, while still accepting updates from the Enabling presence tracking can be resource intensive for the presence handler when server-side tracking of user activity is enabled. Below are some additional configuration options which may help improve the performance of the presence feature without outright disabling it: -* `sync_presence_tracking` (Default enabled): Determines if the server tracks a user's presence -activity when syncing. If disabled, the server will not automatically update the user's presence -activity when the sync endpoint is called. Note that client applications can still update their -presence by calling the respective presence endpoints. -* `federation_presence_tracking` (Default enabled): Determines if the server will accept -presence EDUs that only contain presence activity updates. If disabled, the server will drop -processing EDUs that do not contain updates to the `status_msg`, `displayname`, or -`avatar_url` fields. +* `local_activity_tracking` (Default enabled): Determines if the server tracks a user's activity +when syncing or fetching events. If disabled, the server will not automatically update the +user's presence activity when the /sync or /events endpoints are called. Note that client +applications can still update their presence by calling the presence /status endpoint. +* `remote_activity_tracking` (Default enabled): Determines if the server will accept presence +EDUs from remote servers that are exclusively user activity updates. If disabled, the server +will reject processing these EDUs. However if a presence EDU contains profile updates to any of +the `status_msg`, `displayname`, or `avatar_url` fields, then the server will accept the EDU. + +If the presence `enabled` field is set "untracked", then these options will both act as if set +to false. --- ### `require_auth_for_profile_requests` diff --git a/synapse/config/server.py b/synapse/config/server.py index e510205b98..2cb960b41c 100644 --- a/synapse/config/server.py +++ b/synapse/config/server.py @@ -385,13 +385,13 @@ class ServerConfig(Config): self.track_presence = self.presence_enabled and presence_enabled != "untracked" # Disabling server-side presence tracking - self.sync_presence_tracking = presence_config.get( - "sync_presence_tracking", True + self.presence_local_activity_tracking = presence_config.get( + "local_activity_tracking", True ) # Disabling federation presence tracking - self.federation_presence_tracking = presence_config.get( - "federation_presence_tracking", True + self.presence_remote_activity_tracking = presence_config.get( + "remote_activity_tracking", True ) # Custom presence router module diff --git a/synapse/federation/federation_server.py b/synapse/federation/federation_server.py index d8dc1484b0..19f9edd25a 100644 --- a/synapse/federation/federation_server.py +++ b/synapse/federation/federation_server.py @@ -1425,11 +1425,21 @@ class FederationHandlerRegistry: self._edu_type_to_instance[edu_type] = instance_names async def on_edu(self, edu_type: str, origin: str, content: dict) -> None: + """Passes an EDU to a registered handler if one exists + + This potentially modifies the `content` dict for `m.presence` EDUs when + presence `remote_activity_tracking` is disabled. + + Args: + edu_type: The type of the incoming EDU to process + origin: The server we received the event from + content: The content of the EDU + """ if not self.config.server.track_presence and edu_type == EduTypes.PRESENCE: return if ( - not self.config.server.federation_presence_tracking + not self.config.server.presence_remote_activity_tracking and edu_type == EduTypes.PRESENCE ): filtered_edus = [] diff --git a/synapse/handlers/presence.py b/synapse/handlers/presence.py index 6ea4cf7867..00ce79ed60 100644 --- a/synapse/handlers/presence.py +++ b/synapse/handlers/presence.py @@ -201,7 +201,9 @@ class BasePresenceHandler(abc.ABC): self._presence_enabled = hs.config.server.presence_enabled self._track_presence = hs.config.server.track_presence - self._sync_presence_tracking = hs.config.server.sync_presence_tracking + self._presence_local_activity_tracking = ( + hs.config.server.presence_local_activity_tracking + ) self._federation = None if hs.should_send_federation(): @@ -585,7 +587,7 @@ class WorkerPresenceHandler(BasePresenceHandler): if ( not affect_presence or not self._track_presence - or not self._sync_presence_tracking + or not self._presence_local_activity_tracking ): return _NullContextManager() @@ -1152,7 +1154,7 @@ class PresenceHandler(BasePresenceHandler): if ( not affect_presence or not self._track_presence - or not self._sync_presence_tracking + or not self._presence_local_activity_tracking ): return _NullContextManager() From 46ddc1d893676904fa6ed910565dafe180b7a62a Mon Sep 17 00:00:00 2001 From: Michael Hollister Date: Thu, 30 May 2024 22:46:18 -0500 Subject: [PATCH 08/10] Reverted schema compat version --- synapse/storage/schema/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/synapse/storage/schema/__init__.py b/synapse/storage/schema/__init__.py index 203a601f3b..a24d04c781 100644 --- a/synapse/storage/schema/__init__.py +++ b/synapse/storage/schema/__init__.py @@ -146,8 +146,8 @@ Changes in SCHEMA_VERSION = 86 SCHEMA_COMPAT_VERSION = ( - # Added displayname and avatar_url columns to presence_stream - 86 + # Transitive links are no longer written to `event_auth_chain_links` + 84 ) """Limit on how far the synapse codebase can be rolled back without breaking db compat From 66d3244860821ce782498f7a63d81ad57ea8dee8 Mon Sep 17 00:00:00 2001 From: Michael Hollister Date: Thu, 30 May 2024 22:50:59 -0500 Subject: [PATCH 09/10] Updated changelog description --- changelog.d/16992.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.d/16992.feature b/changelog.d/16992.feature index 903916be7e..6b2cc83484 100644 --- a/changelog.d/16992.feature +++ b/changelog.d/16992.feature @@ -1 +1 @@ -Added presence update on change of profile information and config flags for selective presence tracking. Contributed by @Michael-Hollister. +Added presence tracking of user profile updates and config flags for disabling user activity tracking. Contributed by @Michael-Hollister. From 9716d536278b2e9725edfefeadd872cf1bdd8eb9 Mon Sep 17 00:00:00 2001 From: Michael Hollister Date: Thu, 30 May 2024 22:59:32 -0500 Subject: [PATCH 10/10] Docs grammar fix --- docs/usage/configuration/config_documentation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/usage/configuration/config_documentation.md b/docs/usage/configuration/config_documentation.md index dad99bb74f..4653e1e581 100644 --- a/docs/usage/configuration/config_documentation.md +++ b/docs/usage/configuration/config_documentation.md @@ -268,8 +268,8 @@ EDUs from remote servers that are exclusively user activity updates. If disabled will reject processing these EDUs. However if a presence EDU contains profile updates to any of the `status_msg`, `displayname`, or `avatar_url` fields, then the server will accept the EDU. -If the presence `enabled` field is set "untracked", then these options will both act as if set -to false. +If the presence `enabled` field is set to "untracked", then these options will both act as if +set to false. --- ### `require_auth_for_profile_requests`