From 887479d9c7bc2619731e3888808f4a695b95ce5c Mon Sep 17 00:00:00 2001 From: dasha_uwu Date: Sun, 25 Jan 2026 04:37:39 +0500 Subject: [PATCH] Add `admin rooms prune-empty` to delete empty rooms --- src/admin/room/commands.rs | 52 ++++++++++++++++++++++++++++++++++++-- src/admin/room/mod.rs | 6 +++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/admin/room/commands.rs b/src/admin/room/commands.rs index 82267787..96744891 100644 --- a/src/admin/room/commands.rs +++ b/src/admin/room/commands.rs @@ -1,6 +1,6 @@ -use futures::StreamExt; +use futures::{FutureExt, StreamExt}; use ruma::OwnedRoomId; -use tuwunel_core::{Err, Result}; +use tuwunel_core::{Err, Result, utils::FutureBoolExt}; use crate::{PAGE_SIZE, admin_command, get_room_info}; @@ -84,3 +84,51 @@ pub(super) async fn room_delete(&self, room_id: OwnedRoomId, force: bool) -> Res Ok(()) } + +#[admin_command] +pub(super) async fn room_prune_empty(&self, force: bool) -> Result { + let rooms = self + .services + .metadata + .iter_ids() + .filter(|room_id| { + let has_no_local_users = self + .services + .state_cache + .local_users_in_room(room_id) + .boxed() + .into_future() + .map(|(next, ..)| next.is_none()) + .boxed(); + + let has_no_local_invites = self + .services + .state_cache + .local_users_invited_to_room(room_id) + .boxed() + .into_future() + .map(|(next, ..)| next.is_none()) + .boxed(); + + has_no_local_users.and(has_no_local_invites) + }) + .map(ToOwned::to_owned) + .collect::>() + .await; + + for room_id in &rooms { + let state_lock = self.services.state.mutex.lock(room_id).await; + + self.services + .delete + .delete_room(room_id, force, state_lock) + .await?; + } + + let rooms_len = rooms.len(); + + self.write_str(&format!("Successfully deleted {rooms_len} rooms from our database.")) + .await?; + + Ok(()) +} diff --git a/src/admin/room/mod.rs b/src/admin/room/mod.rs index cc19d462..2411c2b1 100644 --- a/src/admin/room/mod.rs +++ b/src/admin/room/mod.rs @@ -63,4 +63,10 @@ pub(super) enum RoomCommand { #[arg(short, long)] force: bool, }, + + /// - Prune empty rooms + PruneEmpty { + #[arg(short, long)] + force: bool, + }, }