refactor: Make SpaceRoom::new_from_known async so we can properly compute is_dm

This commit is contained in:
Jorge Martín
2026-05-11 11:22:13 +02:00
committed by Jorge Martin Espinosa
parent 58141e422d
commit 29343233b7
4 changed files with 71 additions and 47 deletions

View File

@@ -102,7 +102,7 @@ impl LeaveSpaceHandle {
let is_last_owner = joined_owner_ids == [room.own_user_id()];
rooms.push(LeaveSpaceRoom {
space_room: SpaceRoom::new_from_known(&room, 0),
space_room: SpaceRoom::new_from_known(&room, 0).await,
is_last_owner,
are_creators_privileged,
});

View File

@@ -318,7 +318,7 @@ impl SpaceService {
{
let room_id = room.room_id();
editable_spaces
.push(SpaceRoom::new_from_known(room, graph.children_of(room_id).len() as u64));
.push(SpaceRoom::new_from_known(room, graph.children_of(room_id).len() as u64).await);
}
}
@@ -334,14 +334,22 @@ impl SpaceService {
pub async fn joined_parents_of_child(&self, child_id: &RoomId) -> Vec<SpaceRoom> {
let graph = &self.space_state.lock().await.graph;
graph
let rooms = graph
.parents_of(child_id)
.into_iter()
.filter_map(|parent_id| self.client.get_room(parent_id))
.map(|room| {
SpaceRoom::new_from_known(&room, graph.children_of(room.room_id()).len() as u64)
})
.collect()
.filter_map(|parent_id| self.client.get_room(parent_id));
Self::space_rooms_from_known_rooms(rooms, graph).await
}
async fn space_rooms_from_known_rooms(iter: impl Iterator<Item = Room>, graph: &SpaceGraph) -> Vec<SpaceRoom> {
let mut result = Vec::new();
for room in iter {
result.push(SpaceRoom::new_from_known(&room, graph.children_of(room.room_id()).len() as u64).await);
}
result
}
/// Returns the corresponding `SpaceRoom` for the given room ID, or `None`
@@ -352,7 +360,7 @@ impl SpaceService {
if graph.has_node(room_id)
&& let Some(room) = self.client.get_room(room_id)
{
Some(SpaceRoom::new_from_known(&room, graph.children_of(room.room_id()).len() as u64))
Some(SpaceRoom::new_from_known(&room, graph.children_of(room.room_id()).len() as u64).await)
} else {
None
}
@@ -583,15 +591,14 @@ impl SpaceService {
})
.collect::<Vec<_>>();
let top_level_spaces = top_level_space_rooms
.iter()
.map(|room| {
SpaceRoom::new_from_known(room, graph.children_of(room.room_id()).len() as u64)
})
.collect();
let mut top_level_spaces = Vec::new();
for room in &top_level_space_rooms {
top_level_spaces.push(SpaceRoom::new_from_known(room, graph.children_of(room.room_id()).len() as u64).await);
}
let space_filters =
Self::build_space_filters(client, &graph, top_level_space_rooms, space_child_states);
Self::build_space_filters(client, &graph, top_level_space_rooms, space_child_states).await;
(top_level_spaces, space_filters, graph)
}
@@ -604,7 +611,7 @@ impl SpaceService {
/// and second level ones so while the former are already sorted at this
/// point the latter need to be manually taken care of here though the use
/// of the collected `m.space.child` state event details.
fn build_space_filters(
async fn build_space_filters(
client: &Client,
graph: &SpaceGraph,
top_level_space_rooms: Vec<&Room>,
@@ -619,22 +626,14 @@ impl SpaceService {
.collect::<Vec<_>>();
filters.push(SpaceFilter {
space_room: SpaceRoom::new_from_known(top_level_space, children.len() as u64),
space_room: SpaceRoom::new_from_known(top_level_space, children.len() as u64).await,
level: 0,
descendants: children.clone(),
});
filters.append(
&mut children
.iter()
.filter_map(|id| client.get_room(id))
.filter(|room| room.is_space())
.map(|room| {
SpaceRoom::new_from_known(
&room,
graph.children_of(room.room_id()).len() as u64,
)
})
&mut children_rooms(&client, &children, graph).await
.into_iter()
.sorted_by(|a, b| {
let a_state = space_child_states.get(&a.room_id).cloned();
let b_state = space_child_states.get(&b.room_id).cloned();
@@ -657,6 +656,23 @@ impl SpaceService {
}
}
async fn children_rooms(client: &Client, children: &[OwnedRoomId], graph: &SpaceGraph) -> Vec<SpaceRoom> {
let mut result = Vec::new();
for child_room_id in children {
let Some(room) = client.get_room(child_room_id) else {
continue;
};
if !room.is_space() {
continue;
}
let space_room = SpaceRoom::new_from_known(&room, graph.children_of(room.room_id()).len() as u64).await;
result.push(space_room);
}
result
}
// MSC3230: lexicographically by `order` and then by room ID
fn compare_top_level_space_rooms(
a: (&RoomId, Option<&SpaceChildOrder>),

View File

@@ -116,14 +116,14 @@ impl SpaceRoom {
}
/// Build a `SpaceRoom` from a room already known to this client.
pub(crate) fn new_from_known(known_room: &Room, children_count: u64) -> Self {
pub(crate) async fn new_from_known(known_room: &Room, children_count: u64) -> Self {
let room_info = known_room.clone_info();
let name = room_info.name().map(ToOwned::to_owned);
let display_name = matrix_sdk_base::Room::compute_display_name_with_fields(
name.clone(),
room_info.canonical_alias(),
room_info.heroes().to_vec(),
known_room.heroes(),
known_room.joined_members_count(),
)
.to_string();
@@ -145,10 +145,10 @@ impl SpaceRoom {
is_direct: Some(known_room.direct_targets_length() != 0),
children_count,
state: Some(known_room.state()),
heroes: Some(room_info.heroes().to_vec()),
heroes: Some(known_room.heroes()),
via: vec![],
suggested: false,
is_dm: Some(known_room.is_dm()),
is_dm: known_room.compute_is_dm().await.ok(),
}
}

View File

@@ -144,24 +144,32 @@ impl SpaceRoomList {
continue;
}
let mut mutable_rooms = rooms.lock();
updates.iter_all_room_ids().for_each(|updated_room_id| {
let mut to_set = Vec::new();
for updated_room_id in updates.iter_all_room_ids() {
let mutable_rooms = rooms.lock();
if let Some((position, room)) = mutable_rooms
.clone()
.iter()
.find_position(|room| &room.room_id == updated_room_id)
&& let Some(updated_room) = client.get_room(updated_room_id)
{
mutable_rooms.set(
position,
SpaceRoom::new_from_known(
&updated_room,
room.children_count,
),
);
to_set.push((position, room.clone()));
}
})
drop(mutable_rooms);
}
for (pos, room) in to_set {
let Some(updated_room) = client.get_room(&room.room_id) else {
continue
};
let space_room = SpaceRoom::new_from_known(
&updated_room,
room.children_count,
).await;
let mut mutable_rooms = rooms.lock();
mutable_rooms.set(
pos,
space_room,
);
}
}
Err(err) => {
error!("error when listening to room updates: {err}");
@@ -191,14 +199,14 @@ impl SpaceRoomList {
while subscriber.next().await.is_some() {
if let Some(room) = client.get_room(&space_id) {
space_observable
.set(Some(SpaceRoom::new_from_known(&room, children_count)));
.set(Some(SpaceRoom::new_from_known(&room, children_count).await));
}
}
}
})
.abort_on_drop();
(Some(SpaceRoom::new_from_known(&parent, children_count)), Some(space_update_handle))
(Some(SpaceRoom::new_from_known(&parent, children_count).await), Some(space_update_handle))
} else {
(None, None)
};