tuwunel_service/rooms/delete/
mod.rs1use std::sync::Arc;
2
3use futures::{FutureExt, StreamExt};
4use ruma::{OwnedRoomAliasId, OwnedRoomId, OwnedUserId, RoomId};
5use serde::{Deserialize, Serialize};
6use tuwunel_core::{Result, debug, result::LogErr, trace, utils::future::BoolExt, warn};
7
8use crate::rooms::timeline::RoomMutexGuard;
9
10pub struct Service {
11 services: Arc<crate::services::OnceServices>,
12}
13
14#[derive(Clone, Debug, Default, Serialize, Deserialize)]
18pub struct ShutdownRoom {
19 pub kicked_users: Vec<OwnedUserId>,
20 pub failed_to_kick_users: Vec<OwnedUserId>,
21 pub local_aliases: Vec<OwnedRoomAliasId>,
22 pub new_room_id: Option<OwnedRoomId>,
23}
24
25impl crate::Service for Service {
26 fn build(args: &crate::Args<'_>) -> Result<Arc<Self>> {
27 Ok(Arc::new(Self { services: args.services.clone() }))
28 }
29
30 fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
31}
32
33impl Service {
34 pub async fn delete_if_empty_local(&self, room_id: &RoomId, state_lock: RoomMutexGuard) {
35 debug_assert!(
36 self.services.config.delete_rooms_after_leave,
37 "Caller must checking if delete_rooms_after_leave configured."
38 );
39
40 let has_local_users = self
41 .services
42 .state_cache
43 .local_users_in_room(room_id)
44 .boxed()
45 .into_future()
46 .map(|(next, ..)| next.as_ref().is_some());
47
48 let has_local_invites = self
49 .services
50 .state_cache
51 .local_users_invited_to_room(room_id)
52 .boxed()
53 .into_future()
54 .map(|(next, ..)| next.as_ref().is_some());
55
56 if has_local_users.or(has_local_invites).await {
57 trace!(?room_id, "Not deleting with local joined or invited");
58 return;
59 }
60
61 debug!(?room_id, "Preparing to delete room...");
62
63 self.services
64 .delete
65 .delete_room(room_id, false, state_lock)
66 .boxed()
67 .await
68 .expect("unhandled error during room deletion");
69 }
70
71 pub async fn delete_room(
72 &self,
73 room_id: &RoomId,
74 force: bool,
75 state_lock: RoomMutexGuard,
76 ) -> Result<ShutdownRoom> {
77 let summary = self.shutdown_room(room_id, &state_lock).await;
78
79 self.purge_room(room_id, force, &state_lock).await;
80
81 debug!(?room_id, "Successfully deleted room from our database");
82
83 Ok(summary)
84 }
85
86 pub async fn shutdown_room(
90 &self,
91 room_id: &RoomId,
92 state_lock: &RoomMutexGuard,
93 ) -> ShutdownRoom {
94 debug!(?room_id, "Making all local users leave the room and forgetting it");
95 let (kicked_users, failed_to_kick_users) = self
96 .services
97 .state_cache
98 .local_users_in_room(room_id)
99 .map(ToOwned::to_owned)
100 .fold((Vec::new(), Vec::new()), async |(mut kicked, mut failed), user_id| {
101 match self
102 .services
103 .membership
104 .leave(&user_id, room_id, Some("Room Deleted".into()), true, state_lock)
105 .await
106 {
107 | Ok(()) => kicked.push(user_id),
108 | Err(e) => {
109 warn!(%e, "Failed to leave room");
110 failed.push(user_id);
111 },
112 }
113
114 (kicked, failed)
115 })
116 .await;
117
118 debug!("Deleting all our room aliases for the room");
119 let local_aliases = self
120 .services
121 .alias
122 .local_aliases_for_room(room_id)
123 .map(ToOwned::to_owned)
124 .collect::<Vec<_>>()
125 .await;
126
127 for alias in &local_aliases {
128 self.services
129 .alias
130 .remove_alias(alias)
131 .await
132 .log_err()
133 .ok();
134 }
135
136 debug!("Removing/unpublishing room from our room directory");
137 self.services.directory.set_not_public(room_id);
138
139 ShutdownRoom {
140 kicked_users,
141 failed_to_kick_users,
142 local_aliases,
143 new_room_id: None,
144 }
145 }
146
147 async fn purge_room(&self, room_id: &RoomId, force: bool, state_lock: &RoomMutexGuard) {
150 debug!("Deleting room's threads from database");
151 self.services
152 .threads
153 .delete_all_rooms_threads(room_id)
154 .await
155 .log_err()
156 .ok();
157
158 debug!("Deleting all the room's search token IDs from our database");
159 self.services
160 .search
161 .delete_all_search_tokenids_for_room(room_id)
162 .await
163 .log_err()
164 .ok();
165
166 debug!("Deleting all room's forward extremities from our database");
167 self.services
168 .state
169 .delete_all_rooms_forward_extremities(room_id)
170 .await
171 .log_err()
172 .ok();
173
174 debug!("Deleting all the room's event (PDU) references");
175 self.services
176 .pdu_metadata
177 .delete_all_referenced_for_room(room_id)
178 .await
179 .log_err()
180 .ok();
181
182 debug!("Deleting all the room's typed relation index entries");
183 self.services
184 .pdu_metadata
185 .delete_all_relatesto_typed_for_room(room_id)
186 .await
187 .log_err()
188 .ok();
189
190 debug!("Deleting all the room's member counts");
191 self.services
192 .state_cache
193 .delete_room_join_counts(room_id, force)
194 .await
195 .log_err()
196 .ok();
197
198 debug!("Deleting all the room's private read receipts");
199 self.services
200 .read_receipt
201 .delete_all_read_receipts(room_id)
202 .await
203 .log_err()
204 .ok();
205
206 debug!("Deleting the room's last notifications read.");
207 self.services
208 .pusher
209 .delete_room_notification_read(room_id)
210 .await
211 .log_err()
212 .ok();
213
214 debug!("Deleting room state hash from our database");
215 self.services
216 .state
217 .delete_room_shortstatehash(room_id, state_lock)
218 .log_err()
219 .ok();
220
221 debug!("Deleting PDUs");
222 self.services
223 .timeline
224 .delete_pdus(room_id)
225 .await
226 .log_err()
227 .ok();
228
229 debug!("Deleting internal room ID from our database");
230 self.services
231 .short
232 .delete_shortroomid(room_id)
233 .await
234 .log_err()
235 .ok();
236 }
237}