Skip to content

Commit 1cf3ff6

Browse files
Add rooms name and avatar to Sliding Sync /sync (#17418)
Based on [MSC3575](matrix-org/matrix-spec-proposals#3575): Sliding Sync
1 parent d48061b commit 1cf3ff6

File tree

3 files changed

+305
-55
lines changed

3 files changed

+305
-55
lines changed

changelog.d/17418.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Populate `name`/`avatar` fields in experimental [MSC3575](https://github.com/matrix-org/matrix-spec-proposals/pull/3575) Sliding Sync `/sync` endpoint.

synapse/handlers/sliding_sync.py

Lines changed: 96 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#
1919
#
2020
import logging
21+
from itertools import chain
2122
from typing import TYPE_CHECKING, Any, Dict, Final, List, Optional, Set, Tuple
2223

2324
import attr
@@ -464,6 +465,7 @@ async def current_sync_for_user(
464465
membership_state_keys = room_sync_config.required_state_map.get(
465466
EventTypes.Member
466467
)
468+
# Also see `StateFilter.must_await_full_state(...)` for comparison
467469
lazy_loading = (
468470
membership_state_keys is not None
469471
and len(membership_state_keys) == 1
@@ -1202,7 +1204,7 @@ async def get_room_sync_data(
12021204

12031205
# Figure out any stripped state events for invite/knocks. This allows the
12041206
# potential joiner to identify the room.
1205-
stripped_state: List[JsonDict] = []
1207+
stripped_state: Optional[List[JsonDict]] = None
12061208
if room_membership_for_user_at_to_token.membership in (
12071209
Membership.INVITE,
12081210
Membership.KNOCK,
@@ -1239,21 +1241,23 @@ async def get_room_sync_data(
12391241
# updates.
12401242
initial = True
12411243

1242-
# Fetch the required state for the room
1244+
# Fetch the `required_state` for the room
12431245
#
12441246
# No `required_state` for invite/knock rooms (just `stripped_state`)
12451247
#
12461248
# FIXME: It would be nice to make the `rooms` response more uniform regardless
12471249
# of membership. Currently, we have to make this optional because
12481250
# `invite`/`knock` rooms only have `stripped_state`. See
12491251
# https://github.com/matrix-org/matrix-spec-proposals/pull/3575#discussion_r1653045932
1252+
#
1253+
# Calculate the `StateFilter` based on the `required_state` for the room
12501254
room_state: Optional[StateMap[EventBase]] = None
1255+
required_room_state: Optional[StateMap[EventBase]] = None
12511256
if room_membership_for_user_at_to_token.membership not in (
12521257
Membership.INVITE,
12531258
Membership.KNOCK,
12541259
):
1255-
# Calculate the `StateFilter` based on the `required_state` for the room
1256-
state_filter: Optional[StateFilter] = StateFilter.none()
1260+
required_state_filter = StateFilter.none()
12571261
# If we have a double wildcard ("*", "*") in the `required_state`, we need
12581262
# to fetch all state for the room
12591263
#
@@ -1276,7 +1280,7 @@ async def get_room_sync_data(
12761280
if StateValues.WILDCARD in room_sync_config.required_state_map.get(
12771281
StateValues.WILDCARD, set()
12781282
):
1279-
state_filter = StateFilter.all()
1283+
required_state_filter = StateFilter.all()
12801284
# TODO: `StateFilter` currently doesn't support wildcard event types. We're
12811285
# currently working around this by returning all state to the client but it
12821286
# would be nice to fetch less from the database and return just what the
@@ -1285,7 +1289,7 @@ async def get_room_sync_data(
12851289
room_sync_config.required_state_map.get(StateValues.WILDCARD)
12861290
is not None
12871291
):
1288-
state_filter = StateFilter.all()
1292+
required_state_filter = StateFilter.all()
12891293
else:
12901294
required_state_types: List[Tuple[str, Optional[str]]] = []
12911295
for (
@@ -1317,51 +1321,88 @@ async def get_room_sync_data(
13171321
else:
13181322
required_state_types.append((state_type, state_key))
13191323

1320-
state_filter = StateFilter.from_types(required_state_types)
1321-
1322-
# We can skip fetching state if we don't need any
1323-
if state_filter != StateFilter.none():
1324-
# We can return all of the state that was requested if we're doing an
1325-
# initial sync
1326-
if initial:
1327-
# People shouldn't see past their leave/ban event
1328-
if room_membership_for_user_at_to_token.membership in (
1329-
Membership.LEAVE,
1330-
Membership.BAN,
1331-
):
1332-
room_state = await self.storage_controllers.state.get_state_at(
1333-
room_id,
1334-
stream_position=to_token.copy_and_replace(
1335-
StreamKeyType.ROOM,
1336-
room_membership_for_user_at_to_token.event_pos.to_room_stream_token(),
1337-
),
1338-
state_filter=state_filter,
1339-
# Partially-stated rooms should have all state events except for
1340-
# the membership events and since we've already excluded
1341-
# partially-stated rooms unless `required_state` only has
1342-
# `["m.room.member", "$LAZY"]` for membership, we should be able
1343-
# to retrieve everything requested. Plus we don't want to block
1344-
# the whole sync waiting for this one room.
1345-
await_full_state=False,
1346-
)
1347-
# Otherwise, we can get the latest current state in the room
1348-
else:
1349-
room_state = await self.storage_controllers.state.get_current_state(
1350-
room_id,
1351-
state_filter,
1352-
# Partially-stated rooms should have all state events except for
1353-
# the membership events and since we've already excluded
1354-
# partially-stated rooms unless `required_state` only has
1355-
# `["m.room.member", "$LAZY"]` for membership, we should be able
1356-
# to retrieve everything requested. Plus we don't want to block
1357-
# the whole sync waiting for this one room.
1358-
await_full_state=False,
1359-
)
1360-
# TODO: Query `current_state_delta_stream` and reverse/rewind back to the `to_token`
1324+
required_state_filter = StateFilter.from_types(required_state_types)
1325+
1326+
# We need this base set of info for the response so let's just fetch it along
1327+
# with the `required_state` for the room
1328+
META_ROOM_STATE = [(EventTypes.Name, ""), (EventTypes.RoomAvatar, "")]
1329+
state_filter = StateFilter(
1330+
types=StateFilter.from_types(
1331+
chain(META_ROOM_STATE, required_state_filter.to_types())
1332+
).types,
1333+
include_others=required_state_filter.include_others,
1334+
)
1335+
1336+
# We can return all of the state that was requested if this was the first
1337+
# time we've sent the room down this connection.
1338+
if initial:
1339+
# People shouldn't see past their leave/ban event
1340+
if room_membership_for_user_at_to_token.membership in (
1341+
Membership.LEAVE,
1342+
Membership.BAN,
1343+
):
1344+
room_state = await self.storage_controllers.state.get_state_at(
1345+
room_id,
1346+
stream_position=to_token.copy_and_replace(
1347+
StreamKeyType.ROOM,
1348+
room_membership_for_user_at_to_token.event_pos.to_room_stream_token(),
1349+
),
1350+
state_filter=state_filter,
1351+
# Partially-stated rooms should have all state events except for
1352+
# remote membership events. Since we've already excluded
1353+
# partially-stated rooms unless `required_state` only has
1354+
# `["m.room.member", "$LAZY"]` for membership, we should be able to
1355+
# retrieve everything requested. When we're lazy-loading, if there
1356+
# are some remote senders in the timeline, we should also have their
1357+
# membership event because we had to auth that timeline event. Plus
1358+
# we don't want to block the whole sync waiting for this one room.
1359+
await_full_state=False,
1360+
)
1361+
# Otherwise, we can get the latest current state in the room
13611362
else:
1362-
# TODO: Once we can figure out if we've sent a room down this connection before,
1363-
# we can return updates instead of the full required state.
1364-
raise NotImplementedError()
1363+
room_state = await self.storage_controllers.state.get_current_state(
1364+
room_id,
1365+
state_filter,
1366+
# Partially-stated rooms should have all state events except for
1367+
# remote membership events. Since we've already excluded
1368+
# partially-stated rooms unless `required_state` only has
1369+
# `["m.room.member", "$LAZY"]` for membership, we should be able to
1370+
# retrieve everything requested. When we're lazy-loading, if there
1371+
# are some remote senders in the timeline, we should also have their
1372+
# membership event because we had to auth that timeline event. Plus
1373+
# we don't want to block the whole sync waiting for this one room.
1374+
await_full_state=False,
1375+
)
1376+
# TODO: Query `current_state_delta_stream` and reverse/rewind back to the `to_token`
1377+
else:
1378+
# TODO: Once we can figure out if we've sent a room down this connection before,
1379+
# we can return updates instead of the full required state.
1380+
raise NotImplementedError()
1381+
1382+
if required_state_filter != StateFilter.none():
1383+
required_room_state = required_state_filter.filter_state(room_state)
1384+
1385+
# Find the room name and avatar from the state
1386+
room_name: Optional[str] = None
1387+
room_avatar: Optional[str] = None
1388+
if room_state is not None:
1389+
name_event = room_state.get((EventTypes.Name, ""))
1390+
if name_event is not None:
1391+
room_name = name_event.content.get("name")
1392+
1393+
avatar_event = room_state.get((EventTypes.RoomAvatar, ""))
1394+
if avatar_event is not None:
1395+
room_avatar = avatar_event.content.get("url")
1396+
elif stripped_state is not None:
1397+
for event in stripped_state:
1398+
if event["type"] == EventTypes.Name:
1399+
room_name = event.get("content", {}).get("name")
1400+
elif event["type"] == EventTypes.RoomAvatar:
1401+
room_avatar = event.get("content", {}).get("url")
1402+
1403+
# Found everything so we can stop looking
1404+
if room_name is not None and room_avatar is not None:
1405+
break
13651406

13661407
# Figure out the last bump event in the room
13671408
last_bump_event_result = (
@@ -1378,16 +1419,16 @@ async def get_room_sync_data(
13781419
bump_stamp = bump_event_pos.stream
13791420

13801421
return SlidingSyncResult.RoomResult(
1381-
# TODO: Dummy value
1382-
name=None,
1383-
# TODO: Dummy value
1384-
avatar=None,
1422+
name=room_name,
1423+
avatar=room_avatar,
13851424
# TODO: Dummy value
13861425
heroes=None,
13871426
# TODO: Dummy value
13881427
is_dm=False,
13891428
initial=initial,
1390-
required_state=list(room_state.values()) if room_state else None,
1429+
required_state=(
1430+
list(required_room_state.values()) if required_room_state else None
1431+
),
13911432
timeline_events=timeline_events,
13921433
bundled_aggregations=bundled_aggregations,
13931434
stripped_state=stripped_state,

0 commit comments

Comments
 (0)