mirror of
https://git.anonymousland.org/anonymousland/synapse.git
synced 2025-11-13 20:10:46 -05:00
Support federation in the new spaces summary API (MSC2946). (#10569)
This commit is contained in:
parent
a3a7514570
commit
7de445161f
6 changed files with 518 additions and 165 deletions
|
|
@ -1290,6 +1290,88 @@ class FederationClient(FederationBase):
|
|||
failover_on_unknown_endpoint=True,
|
||||
)
|
||||
|
||||
async def get_room_hierarchy(
|
||||
self,
|
||||
destinations: Iterable[str],
|
||||
room_id: str,
|
||||
suggested_only: bool,
|
||||
) -> Tuple[JsonDict, Sequence[JsonDict], Sequence[str]]:
|
||||
"""
|
||||
Call other servers to get a hierarchy of the given room.
|
||||
|
||||
Performs simple data validates and parsing of the response.
|
||||
|
||||
Args:
|
||||
destinations: The remote servers. We will try them in turn, omitting any
|
||||
that have been blacklisted.
|
||||
room_id: ID of the space to be queried
|
||||
suggested_only: If true, ask the remote server to only return children
|
||||
with the "suggested" flag set
|
||||
|
||||
Returns:
|
||||
A tuple of:
|
||||
The room as a JSON dictionary.
|
||||
A list of children rooms, as JSON dictionaries.
|
||||
A list of inaccessible children room IDs.
|
||||
|
||||
Raises:
|
||||
SynapseError if we were unable to get a valid summary from any of the
|
||||
remote servers
|
||||
"""
|
||||
|
||||
async def send_request(
|
||||
destination: str,
|
||||
) -> Tuple[JsonDict, Sequence[JsonDict], Sequence[str]]:
|
||||
res = await self.transport_layer.get_room_hierarchy(
|
||||
destination=destination,
|
||||
room_id=room_id,
|
||||
suggested_only=suggested_only,
|
||||
)
|
||||
|
||||
room = res.get("room")
|
||||
if not isinstance(room, dict):
|
||||
raise InvalidResponseError("'room' must be a dict")
|
||||
|
||||
# Validate children_state of the room.
|
||||
children_state = room.get("children_state", [])
|
||||
if not isinstance(children_state, Sequence):
|
||||
raise InvalidResponseError("'room.children_state' must be a list")
|
||||
if any(not isinstance(e, dict) for e in children_state):
|
||||
raise InvalidResponseError("Invalid event in 'children_state' list")
|
||||
try:
|
||||
[
|
||||
FederationSpaceSummaryEventResult.from_json_dict(e)
|
||||
for e in children_state
|
||||
]
|
||||
except ValueError as e:
|
||||
raise InvalidResponseError(str(e))
|
||||
|
||||
# Validate the children rooms.
|
||||
children = res.get("children", [])
|
||||
if not isinstance(children, Sequence):
|
||||
raise InvalidResponseError("'children' must be a list")
|
||||
if any(not isinstance(r, dict) for r in children):
|
||||
raise InvalidResponseError("Invalid room in 'children' list")
|
||||
|
||||
# Validate the inaccessible children.
|
||||
inaccessible_children = res.get("inaccessible_children", [])
|
||||
if not isinstance(inaccessible_children, Sequence):
|
||||
raise InvalidResponseError("'inaccessible_children' must be a list")
|
||||
if any(not isinstance(r, str) for r in inaccessible_children):
|
||||
raise InvalidResponseError(
|
||||
"Invalid room ID in 'inaccessible_children' list"
|
||||
)
|
||||
|
||||
return room, children, inaccessible_children
|
||||
|
||||
# TODO Fallback to the old federation API and translate the results.
|
||||
return await self._try_destination_list(
|
||||
"fetch room hierarchy",
|
||||
destinations,
|
||||
send_request,
|
||||
failover_on_unknown_endpoint=True,
|
||||
)
|
||||
|
||||
|
||||
@attr.s(frozen=True, slots=True, auto_attribs=True)
|
||||
class FederationSpaceSummaryEventResult:
|
||||
|
|
|
|||
|
|
@ -1177,6 +1177,28 @@ class TransportLayerClient:
|
|||
destination=destination, path=path, data=params
|
||||
)
|
||||
|
||||
async def get_room_hierarchy(
|
||||
self,
|
||||
destination: str,
|
||||
room_id: str,
|
||||
suggested_only: bool,
|
||||
) -> JsonDict:
|
||||
"""
|
||||
Args:
|
||||
destination: The remote server
|
||||
room_id: The room ID to ask about.
|
||||
suggested_only: if True, only suggested rooms will be returned
|
||||
"""
|
||||
path = _create_path(
|
||||
FEDERATION_UNSTABLE_PREFIX, "/org.matrix.msc2946/hierarchy/%s", room_id
|
||||
)
|
||||
|
||||
return await self.client.get_json(
|
||||
destination=destination,
|
||||
path=path,
|
||||
args={"suggested_only": "true" if suggested_only else "false"},
|
||||
)
|
||||
|
||||
|
||||
def _create_path(federation_prefix: str, path: str, *args: str) -> str:
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -1936,6 +1936,33 @@ class FederationSpaceSummaryServlet(BaseFederationServlet):
|
|||
)
|
||||
|
||||
|
||||
class FederationRoomHierarchyServlet(BaseFederationServlet):
|
||||
PREFIX = FEDERATION_UNSTABLE_PREFIX + "/org.matrix.msc2946"
|
||||
PATH = "/hierarchy/(?P<room_id>[^/]*)"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hs: HomeServer,
|
||||
authenticator: Authenticator,
|
||||
ratelimiter: FederationRateLimiter,
|
||||
server_name: str,
|
||||
):
|
||||
super().__init__(hs, authenticator, ratelimiter, server_name)
|
||||
self.handler = hs.get_space_summary_handler()
|
||||
|
||||
async def on_GET(
|
||||
self,
|
||||
origin: str,
|
||||
content: Literal[None],
|
||||
query: Mapping[bytes, Sequence[bytes]],
|
||||
room_id: str,
|
||||
) -> Tuple[int, JsonDict]:
|
||||
suggested_only = parse_boolean_from_args(query, "suggested_only", default=False)
|
||||
return 200, await self.handler.get_federation_hierarchy(
|
||||
origin, room_id, suggested_only
|
||||
)
|
||||
|
||||
|
||||
class RoomComplexityServlet(BaseFederationServlet):
|
||||
"""
|
||||
Indicates to other servers how complex (and therefore likely
|
||||
|
|
@ -1999,6 +2026,7 @@ FEDERATION_SERVLET_CLASSES: Tuple[Type[BaseFederationServlet], ...] = (
|
|||
FederationVersionServlet,
|
||||
RoomComplexityServlet,
|
||||
FederationSpaceSummaryServlet,
|
||||
FederationRoomHierarchyServlet,
|
||||
FederationV1SendKnockServlet,
|
||||
FederationMakeKnockServlet,
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue