18
18
#
19
19
#
20
20
import logging
21
+ from itertools import chain
21
22
from typing import TYPE_CHECKING , Any , Dict , Final , List , Optional , Set , Tuple
22
23
23
24
import attr
@@ -464,6 +465,7 @@ async def current_sync_for_user(
464
465
membership_state_keys = room_sync_config .required_state_map .get (
465
466
EventTypes .Member
466
467
)
468
+ # Also see `StateFilter.must_await_full_state(...)` for comparison
467
469
lazy_loading = (
468
470
membership_state_keys is not None
469
471
and len (membership_state_keys ) == 1
@@ -1202,7 +1204,7 @@ async def get_room_sync_data(
1202
1204
1203
1205
# Figure out any stripped state events for invite/knocks. This allows the
1204
1206
# potential joiner to identify the room.
1205
- stripped_state : List [JsonDict ] = []
1207
+ stripped_state : Optional [ List [JsonDict ]] = None
1206
1208
if room_membership_for_user_at_to_token .membership in (
1207
1209
Membership .INVITE ,
1208
1210
Membership .KNOCK ,
@@ -1239,21 +1241,23 @@ async def get_room_sync_data(
1239
1241
# updates.
1240
1242
initial = True
1241
1243
1242
- # Fetch the required state for the room
1244
+ # Fetch the `required_state` for the room
1243
1245
#
1244
1246
# No `required_state` for invite/knock rooms (just `stripped_state`)
1245
1247
#
1246
1248
# FIXME: It would be nice to make the `rooms` response more uniform regardless
1247
1249
# of membership. Currently, we have to make this optional because
1248
1250
# `invite`/`knock` rooms only have `stripped_state`. See
1249
1251
# 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
1250
1254
room_state : Optional [StateMap [EventBase ]] = None
1255
+ required_room_state : Optional [StateMap [EventBase ]] = None
1251
1256
if room_membership_for_user_at_to_token .membership not in (
1252
1257
Membership .INVITE ,
1253
1258
Membership .KNOCK ,
1254
1259
):
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 ()
1257
1261
# If we have a double wildcard ("*", "*") in the `required_state`, we need
1258
1262
# to fetch all state for the room
1259
1263
#
@@ -1276,7 +1280,7 @@ async def get_room_sync_data(
1276
1280
if StateValues .WILDCARD in room_sync_config .required_state_map .get (
1277
1281
StateValues .WILDCARD , set ()
1278
1282
):
1279
- state_filter = StateFilter .all ()
1283
+ required_state_filter = StateFilter .all ()
1280
1284
# TODO: `StateFilter` currently doesn't support wildcard event types. We're
1281
1285
# currently working around this by returning all state to the client but it
1282
1286
# would be nice to fetch less from the database and return just what the
@@ -1285,7 +1289,7 @@ async def get_room_sync_data(
1285
1289
room_sync_config .required_state_map .get (StateValues .WILDCARD )
1286
1290
is not None
1287
1291
):
1288
- state_filter = StateFilter .all ()
1292
+ required_state_filter = StateFilter .all ()
1289
1293
else :
1290
1294
required_state_types : List [Tuple [str , Optional [str ]]] = []
1291
1295
for (
@@ -1317,51 +1321,88 @@ async def get_room_sync_data(
1317
1321
else :
1318
1322
required_state_types .append ((state_type , state_key ))
1319
1323
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
1361
1362
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
1365
1406
1366
1407
# Figure out the last bump event in the room
1367
1408
last_bump_event_result = (
@@ -1378,16 +1419,16 @@ async def get_room_sync_data(
1378
1419
bump_stamp = bump_event_pos .stream
1379
1420
1380
1421
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 ,
1385
1424
# TODO: Dummy value
1386
1425
heroes = None ,
1387
1426
# TODO: Dummy value
1388
1427
is_dm = False ,
1389
1428
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
+ ),
1391
1432
timeline_events = timeline_events ,
1392
1433
bundled_aggregations = bundled_aggregations ,
1393
1434
stripped_state = stripped_state ,
0 commit comments