@@ -1364,13 +1364,59 @@ async def send_request(
13641364
13651365 return room , children , inaccessible_children
13661366
1367- # TODO Fallback to the old federation API and translate the results.
1368- return await self ._try_destination_list (
1369- "fetch room hierarchy" ,
1370- destinations ,
1371- send_request ,
1372- failover_on_unknown_endpoint = True ,
1373- )
1367+ try :
1368+ return await self ._try_destination_list (
1369+ "fetch room hierarchy" ,
1370+ destinations ,
1371+ send_request ,
1372+ failover_on_unknown_endpoint = True ,
1373+ )
1374+ except SynapseError as e :
1375+ # Fallback to the old federation API and translate the results if
1376+ # no servers implement the new API.
1377+ #
1378+ # The algorithm below is a bit inefficient as it only attempts to
1379+ # get information for the requested room, but the legacy API may
1380+ # return additional layers.
1381+ if e .code == 502 :
1382+ legacy_result = await self .get_space_summary (
1383+ destinations ,
1384+ room_id ,
1385+ suggested_only ,
1386+ max_rooms_per_space = None ,
1387+ exclude_rooms = [],
1388+ )
1389+
1390+ # Find the requested room in the response (and remove it).
1391+ for _i , room in enumerate (legacy_result .rooms ):
1392+ if room .get ("room_id" ) == room_id :
1393+ break
1394+ else :
1395+ # The requested room was not returned, nothing we can do.
1396+ raise
1397+ requested_room = legacy_result .rooms .pop (_i )
1398+
1399+ # Find any children events of the requested room.
1400+ children_events = []
1401+ children_room_ids = set ()
1402+ for event in legacy_result .events :
1403+ if event .room_id == room_id :
1404+ children_events .append (event .data )
1405+ children_room_ids .add (event .state_key )
1406+ # And add them under the requested room.
1407+ requested_room ["children_state" ] = children_events
1408+
1409+ # Find the children rooms.
1410+ children = []
1411+ for room in legacy_result .rooms :
1412+ if room .get ("room_id" ) in children_room_ids :
1413+ children .append (room )
1414+
1415+ # It isn't clear from the response whether some of the rooms are
1416+ # not accessible.
1417+ return requested_room , children , ()
1418+
1419+ raise
13741420
13751421
13761422@attr .s (frozen = True , slots = True , auto_attribs = True )
@@ -1430,7 +1476,7 @@ def from_json_dict(cls, d: JsonDict) -> "FederationSpaceSummaryEventResult":
14301476class FederationSpaceSummaryResult :
14311477 """Represents the data returned by a successful get_space_summary call."""
14321478
1433- rooms : Sequence [JsonDict ]
1479+ rooms : List [JsonDict ]
14341480 events : Sequence [FederationSpaceSummaryEventResult ]
14351481
14361482 @classmethod
@@ -1444,7 +1490,7 @@ def from_json_dict(cls, d: JsonDict) -> "FederationSpaceSummaryResult":
14441490 ValueError if d is not a valid /spaces/ response
14451491 """
14461492 rooms = d .get ("rooms" )
1447- if not isinstance (rooms , Sequence ):
1493+ if not isinstance (rooms , List ):
14481494 raise ValueError ("'rooms' must be a list" )
14491495 if any (not isinstance (r , dict ) for r in rooms ):
14501496 raise ValueError ("Invalid room in 'rooms' list" )
0 commit comments