mirror of
https://github.com/element-hq/synapse.git
synced 2026-08-28 00:44:35 +00:00
Add MSC4262 Profile Updates via Sliding Sync dummy response and config
This commit is contained in:
@@ -80,6 +80,7 @@ class SlidingSyncExtensionHandler:
|
||||
self._storage_controllers = hs.get_storage_controllers()
|
||||
self._enable_thread_subscriptions = hs.config.experimental.msc4306_enabled
|
||||
self._enable_sticky_events = hs.config.experimental.msc4354_enabled
|
||||
self._enable_profiles = hs.config.server.include_profile_updates_in_sync
|
||||
|
||||
@trace
|
||||
async def get_extensions_response(
|
||||
@@ -197,6 +198,16 @@ class SlidingSyncExtensionHandler:
|
||||
from_token=from_token,
|
||||
)
|
||||
|
||||
profiles_coro = None
|
||||
if sync_config.extensions.profiles is not Absent and self._enable_profiles:
|
||||
profiles_coro = self.get_profiles_extension_response(
|
||||
sync_config=sync_config,
|
||||
profiles_request=sync_config.extensions.profiles,
|
||||
all_interested_room_ids=all_interested_room_ids,
|
||||
to_token=to_token,
|
||||
from_token=from_token,
|
||||
)
|
||||
|
||||
(
|
||||
to_device_response,
|
||||
e2ee_response,
|
||||
@@ -205,6 +216,7 @@ class SlidingSyncExtensionHandler:
|
||||
typing_response,
|
||||
thread_subs_response,
|
||||
sticky_events_response,
|
||||
profiles_response,
|
||||
) = await gather_optional_coroutines(
|
||||
to_device_coro,
|
||||
e2ee_coro,
|
||||
@@ -213,6 +225,7 @@ class SlidingSyncExtensionHandler:
|
||||
typing_coro,
|
||||
thread_subs_coro,
|
||||
sticky_events_coro,
|
||||
profiles_coro,
|
||||
)
|
||||
|
||||
return SlidingSyncResult.Extensions(
|
||||
@@ -223,6 +236,7 @@ class SlidingSyncExtensionHandler:
|
||||
typing=typing_response,
|
||||
thread_subscriptions=thread_subs_response,
|
||||
sticky_events=sticky_events_response,
|
||||
profiles=profiles_response,
|
||||
)
|
||||
|
||||
def find_relevant_room_ids_for_extension(
|
||||
@@ -1055,3 +1069,18 @@ class SlidingSyncExtensionHandler:
|
||||
sticky_events_stream_id=sticky_events_to_id
|
||||
),
|
||||
)
|
||||
|
||||
async def get_profiles_extension_response(
|
||||
self,
|
||||
sync_config: SlidingSyncConfig,
|
||||
profiles_request: SlidingSyncConfig.Extensions.ProfilesExtension,
|
||||
all_interested_room_ids: set[str],
|
||||
to_token: StreamToken,
|
||||
from_token: SlidingSyncStreamToken | None,
|
||||
) -> SlidingSyncResult.Extensions.ProfilesExtension | None:
|
||||
if not profiles_request.enabled:
|
||||
return None
|
||||
|
||||
return SlidingSyncResult.Extensions.ProfilesExtension(
|
||||
users={},
|
||||
)
|
||||
|
||||
@@ -55,7 +55,13 @@ from synapse.http.servlet import (
|
||||
from synapse.http.site import SynapseRequest
|
||||
from synapse.logging.opentracing import log_kv, set_tag, trace_with_opname
|
||||
from synapse.rest.admin.experimental_features import ExperimentalFeature
|
||||
from synapse.types import JsonDict, Requester, SlidingSyncStreamToken, StreamToken
|
||||
from synapse.types import (
|
||||
JsonDict,
|
||||
JsonMapping,
|
||||
Requester,
|
||||
SlidingSyncStreamToken,
|
||||
StreamToken,
|
||||
)
|
||||
from synapse.types.rest.client import SlidingSyncBody
|
||||
from synapse.util.caches.lrucache import LruCache
|
||||
from synapse.util.cancellation import cancellable
|
||||
@@ -1142,8 +1148,23 @@ class SlidingSyncRestServlet(RestServlet):
|
||||
requester, extensions.sticky_events, ref_rooms_results
|
||||
)
|
||||
|
||||
if extensions.profiles:
|
||||
serialized_extensions[
|
||||
"org.matrix.msc4262.profiles"
|
||||
] = await self._serialise_profiles(
|
||||
requester, extensions.profiles, ref_rooms_results
|
||||
)
|
||||
|
||||
return serialized_extensions
|
||||
|
||||
async def _serialise_profiles(
|
||||
self,
|
||||
requester: Requester,
|
||||
profiles: SlidingSyncResult.Extensions.ProfilesExtension,
|
||||
ref_rooms_results: Mapping[str, SlidingSyncResult.RoomResult],
|
||||
) -> JsonMapping:
|
||||
return profiles.users
|
||||
|
||||
async def _serialise_sticky_events(
|
||||
self,
|
||||
requester: Requester,
|
||||
|
||||
@@ -442,6 +442,19 @@ class SlidingSyncResult:
|
||||
def __bool__(self) -> bool:
|
||||
return bool(self.room_id_to_sticky_events)
|
||||
|
||||
@attr.s(slots=True, frozen=True, auto_attribs=True)
|
||||
class ProfilesExtension:
|
||||
"""The Profile Updates extension (MSC4262)
|
||||
|
||||
Attributes:
|
||||
users: map (user_id -> [profile_updates])
|
||||
"""
|
||||
|
||||
users: Mapping[str, JsonMapping]
|
||||
|
||||
def __bool__(self) -> bool:
|
||||
return bool(self.users)
|
||||
|
||||
to_device: ToDeviceExtension | None = None
|
||||
e2ee: E2eeExtension | None = None
|
||||
account_data: AccountDataExtension | None = None
|
||||
@@ -449,6 +462,7 @@ class SlidingSyncResult:
|
||||
typing: TypingExtension | None = None
|
||||
thread_subscriptions: ThreadSubscriptionsExtension | None = None
|
||||
sticky_events: StickyEventsExtension | None = None
|
||||
profiles: ProfilesExtension | None = None
|
||||
|
||||
def __bool__(self) -> bool:
|
||||
"""Are there any updates that should be returned immediately to
|
||||
@@ -461,6 +475,7 @@ class SlidingSyncResult:
|
||||
or self.typing
|
||||
or self.thread_subscriptions
|
||||
or self.sticky_events
|
||||
or self.profiles
|
||||
)
|
||||
|
||||
next_pos: SlidingSyncStreamToken
|
||||
|
||||
@@ -478,6 +478,18 @@ class SlidingSyncBody(RequestBodyModel):
|
||||
limit: NonNegativeStrictInt = 100
|
||||
since: SlidingSyncStickyEventsToken | AbsentType = Absent
|
||||
|
||||
class ProfilesExtension(RequestBodyModel):
|
||||
"""The Profile Updates extension (MSC4262)
|
||||
|
||||
Attributes:
|
||||
enabled
|
||||
fields: List of fields to filter upon (optional)
|
||||
"""
|
||||
|
||||
enabled: StrictBool | None = False
|
||||
# Optionally filter on specific fields
|
||||
fields: list[StrictStr] | None = []
|
||||
|
||||
to_device: ToDeviceExtension | None = None
|
||||
e2ee: E2eeExtension | None = None
|
||||
account_data: AccountDataExtension | None = None
|
||||
@@ -489,6 +501,9 @@ class SlidingSyncBody(RequestBodyModel):
|
||||
sticky_events: StickyEventsExtension | AbsentType = Field(
|
||||
Absent, alias="org.matrix.msc4354.sticky_events"
|
||||
)
|
||||
profiles: ProfilesExtension | AbsentType = Field(
|
||||
Absent, alias="org.matrix.msc4262.profiles"
|
||||
)
|
||||
|
||||
conn_id: StrictStr | None = None
|
||||
lists: (
|
||||
|
||||
@@ -391,6 +391,7 @@ T4 = TypeVar("T4")
|
||||
T5 = TypeVar("T5")
|
||||
T6 = TypeVar("T6")
|
||||
T7 = TypeVar("T7")
|
||||
T8 = TypeVar("T8")
|
||||
|
||||
|
||||
@overload
|
||||
@@ -544,6 +545,32 @@ async def gather_optional_coroutines(
|
||||
]: ...
|
||||
|
||||
|
||||
@overload
|
||||
async def gather_optional_coroutines(
|
||||
*coroutines: Unpack[
|
||||
tuple[
|
||||
Coroutine[Any, Any, T1] | None,
|
||||
Coroutine[Any, Any, T2] | None,
|
||||
Coroutine[Any, Any, T3] | None,
|
||||
Coroutine[Any, Any, T4] | None,
|
||||
Coroutine[Any, Any, T5] | None,
|
||||
Coroutine[Any, Any, T6] | None,
|
||||
Coroutine[Any, Any, T7] | None,
|
||||
Coroutine[Any, Any, T8] | None,
|
||||
]
|
||||
],
|
||||
) -> tuple[
|
||||
T1 | None,
|
||||
T2 | None,
|
||||
T3 | None,
|
||||
T4 | None,
|
||||
T5 | None,
|
||||
T6 | None,
|
||||
T7 | None,
|
||||
T8 | None,
|
||||
]: ...
|
||||
|
||||
|
||||
async def gather_optional_coroutines(
|
||||
*coroutines: Unpack[tuple[Coroutine[Any, Any, T1] | None, ...]],
|
||||
) -> tuple[T1 | None, ...]:
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
#
|
||||
# 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:
|
||||
# <https://www.gnu.org/licenses/agpl-3.0.html>.
|
||||
#
|
||||
import logging
|
||||
|
||||
from parameterized import parameterized, parameterized_class
|
||||
|
||||
from twisted.internet.testing import MemoryReactor
|
||||
|
||||
import synapse.rest.admin
|
||||
from synapse.rest.client import login, profile, room, sync
|
||||
from synapse.server import HomeServer
|
||||
from synapse.util.clock import Clock
|
||||
|
||||
from tests.rest.client.sliding_sync.test_sliding_sync import SlidingSyncBase
|
||||
from tests.unittest import override_config
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# FIXME: This can be removed once we bump `SCHEMA_COMPAT_VERSION` and run the
|
||||
# foreground update for
|
||||
# `sliding_sync_joined_rooms`/`sliding_sync_membership_snapshots` (tracked by
|
||||
# https://github.com/element-hq/synapse/issues/17623)
|
||||
@parameterized_class(
|
||||
("use_new_tables",),
|
||||
[
|
||||
(True,),
|
||||
(False,),
|
||||
],
|
||||
class_name_func=lambda cls,
|
||||
num,
|
||||
params_dict: f"{cls.__name__}_{'new' if params_dict['use_new_tables'] else 'fallback'}",
|
||||
)
|
||||
class SlidingSyncProfilesTestCase(SlidingSyncBase):
|
||||
"""Tests for the profile updates sliding sync extension"""
|
||||
|
||||
servlets = [
|
||||
synapse.rest.admin.register_servlets,
|
||||
login.register_servlets,
|
||||
profile.register_servlets,
|
||||
room.register_servlets,
|
||||
sync.register_servlets,
|
||||
]
|
||||
|
||||
def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
|
||||
self.store = hs.get_datastores().main
|
||||
|
||||
super().prepare(reactor, clock, hs)
|
||||
|
||||
@parameterized.expand(
|
||||
[
|
||||
True,
|
||||
False,
|
||||
]
|
||||
)
|
||||
def test_no_data_when_not_enabled(self, is_initial: bool) -> None:
|
||||
"""
|
||||
Test that no profile extension response is returned
|
||||
if the feature is not enabled.
|
||||
"""
|
||||
user1_id = self.register_user("user1", "pass")
|
||||
user1_tok = self.login(user1_id, "pass")
|
||||
|
||||
# Make an initial Sliding Sync request with the profiles extension enabled
|
||||
sync_body = {
|
||||
"lists": {},
|
||||
"extensions": {
|
||||
"org.matrix.msc4262.profiles": {
|
||||
"enabled": True,
|
||||
},
|
||||
},
|
||||
}
|
||||
response_body, from_token = self.do_sync(sync_body, tok=user1_tok)
|
||||
self.assertIsNone(response_body["extensions"].get("org.matrix.msc4262.profiles"))
|
||||
|
||||
if not is_initial:
|
||||
# Make an incremental Sliding Sync request
|
||||
response_body, _ = self.do_sync(sync_body, since=from_token, tok=user1_tok)
|
||||
|
||||
self.assertIsNone(response_body["extensions"].get("org.matrix.msc4262.profiles"))
|
||||
|
||||
@override_config({"include_profile_updates_in_sync": True})
|
||||
def test_no_data_initial_sync(self) -> None:
|
||||
"""
|
||||
Test that enabling the profiles extension works during an initial sync,
|
||||
even if there is no-data.
|
||||
"""
|
||||
user1_id = self.register_user("user1", "pass")
|
||||
user1_tok = self.login(user1_id, "pass")
|
||||
|
||||
# Make an initial Sliding Sync request with the profiles extension enabled
|
||||
sync_body = {
|
||||
"lists": {},
|
||||
"extensions": {
|
||||
"org.matrix.msc4262.profiles": {
|
||||
"enabled": True,
|
||||
},
|
||||
},
|
||||
}
|
||||
response_body, _ = self.do_sync(sync_body, tok=user1_tok)
|
||||
self.assertIsNone(response_body["extensions"].get("org.matrix.msc4262.profiles"))
|
||||
|
||||
@override_config({"include_profile_updates_in_sync": True})
|
||||
def test_no_data_incremental_sync(self) -> None:
|
||||
"""
|
||||
Test that enabling profiles extension works during an incremental sync, even
|
||||
if there is no-data.
|
||||
"""
|
||||
user1_id = self.register_user("user1", "pass")
|
||||
user1_tok = self.login(user1_id, "pass")
|
||||
|
||||
sync_body = {
|
||||
"lists": {},
|
||||
"extensions": {
|
||||
"org.matrix.msc4262.profiles": {
|
||||
"enabled": True,
|
||||
}
|
||||
},
|
||||
}
|
||||
_, from_token = self.do_sync(sync_body, tok=user1_tok)
|
||||
|
||||
# Make an incremental Sliding Sync request with the profiles extension enabled
|
||||
response_body, _ = self.do_sync(sync_body, since=from_token, tok=user1_tok)
|
||||
|
||||
self.assertIsNone(response_body["extensions"].get("org.matrix.msc4262.profiles"))
|
||||
Reference in New Issue
Block a user