diff options
author | Andrew Morgan <andrew@amorgan.xyz> | 2021-03-17 18:11:47 +0000 |
---|---|---|
committer | Andrew Morgan <andrew@amorgan.xyz> | 2021-03-18 16:35:21 +0000 |
commit | 847cc492d8ef27f5bd3698fcd9e6f26ff8ee9242 (patch) | |
tree | cbfb0669ed1be625dd9acaf8b325127a91e71517 | |
parent | Add an exclude_keyvalues option to simple_select_list_paginate_txn (diff) | |
download | synapse-847cc492d8ef27f5bd3698fcd9e6f26ff8ee9242.tar.xz |
Add a storage method to get the current presence state for all users
This will be useful for when PresenceRouter.get_interested_user returns "ALL". It allows for querying all current local user presencee. Note that the `presence_stream` table is culled frequently, and doesn't just grow forever like other stream tables.
-rw-r--r-- | synapse/storage/databases/main/presence.py | 61 |
1 files changed, 60 insertions, 1 deletions
diff --git a/synapse/storage/databases/main/presence.py b/synapse/storage/databases/main/presence.py index 29edab34d4..eae7065fdc 100644 --- a/synapse/storage/databases/main/presence.py +++ b/synapse/storage/databases/main/presence.py @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import List, Tuple +from typing import Dict, List, Tuple from synapse.api.presence import UserPresenceState from synapse.storage._base import SQLBaseStore, make_in_list_sql_clause @@ -157,5 +157,64 @@ class PresenceStore(SQLBaseStore): return {row["user_id"]: UserPresenceState(**row) for row in rows} + async def get_presence_for_all_users( + self, + include_offline: bool = True, + ) -> Dict[str, UserPresenceState]: + """Retrieve the current presence state for all users. + + Note that the presence_stream table is culled frequently, so it should only + contain the latest presence state for each user. + + Args: + include_offline: Whether to include offline presence states + + Returns: + A dict of user IDs to their current UserPresenceState. + """ + users_to_state = {} + + exclude_keyvalues = {} + if not include_offline: + # Exclude offline presence state + exclude_keyvalues = {"state": "offline"} + + # This may be a very heavy database query. + # We paginate in order to not block a database connection. + limit = 100 + offset = 0 + while True: + rows = await self.db_pool.runInteraction( + "get_presence_for_all_users", + self.db_pool.simple_select_list_paginate_txn, + "presence_stream", + orderby="stream_id", + start=offset, + limit=limit, + keyvalues={}, + exclude_keyvalues=exclude_keyvalues, + retcols=( + "user_id", + "state", + "last_active_ts", + "last_federation_update_ts", + "last_user_sync_ts", + "status_msg", + "currently_active", + ), + order_direction="ASC", + ) + + for row in rows: + users_to_state[row["user_id"]] = UserPresenceState(**row) + + # We've ran out of updates to query + if len(rows) < limit: + break + + offset += limit + + return users_to_state + def get_current_presence_token(self): return self._presence_id_gen.get_current_token() |