tuwunel_api/server/
hierarchy.rs1use Accessibility::{Accessible, Inaccessible};
2use Identifier::ServerName;
3use axum::extract::State;
4use futures::{FutureExt, StreamExt};
5use get_hierarchy::v1::{Request, Response};
6use ruma::api::federation::space::get_hierarchy;
7use tuwunel_core::{
8 Err, Result,
9 utils::stream::{BroadbandExt, IterStream},
10};
11use tuwunel_service::rooms::spaces::{Accessibility, Identifier, get_parent_children_via};
12
13use crate::Ruma;
14
15pub(crate) async fn get_hierarchy_route(
20 State(services): State<crate::State>,
21 body: Ruma<Request>,
22) -> Result<Response> {
23 if !services.metadata.exists(&body.room_id).await {
24 return Err!(Request(NotFound("Room does not exist.")));
25 }
26
27 match services
28 .spaces
29 .get_summary_and_children(&body.room_id, &ServerName(body.origin()), &[])
30 .await?
31 {
32 | Inaccessible => Err!(Request(NotFound("The requested room is inaccessible"))),
33 | Accessible(room) => {
34 let (children, inaccessible_children) =
35 get_parent_children_via(&room, body.suggested_only)
36 .stream()
37 .broad_filter_map(async |(child, _via)| {
38 match services
39 .spaces
40 .get_summary_and_children(&child, &ServerName(body.origin()), &[])
41 .await
42 .ok()?
43 {
44 | Inaccessible => Some((None, Some(child))),
45 | Accessible(summary) => Some((Some(summary), None)),
46 }
47 })
48 .unzip()
49 .map(|(children, inaccessible_children): (Vec<_>, Vec<_>)| {
50 let children = children
51 .into_iter()
52 .flatten()
53 .map(|parent| parent.summary)
54 .collect();
55
56 let inaccessible_children = inaccessible_children
57 .into_iter()
58 .flatten()
59 .collect();
60
61 (children, inaccessible_children)
62 })
63 .await;
64
65 Ok(Response { room, children, inaccessible_children })
66 },
67 }
68}