1mod block;
4mod context;
5mod delete_room;
6mod delete_status;
7mod forward_extremities;
8mod hierarchy;
9mod join;
10mod list_rooms;
11mod make_room_admin;
12mod messages;
13mod purge_history;
14mod room_details;
15mod room_members;
16mod state;
17mod timestamp_to_event;
18
19use futures::{
20 FutureExt, StreamExt, TryFutureExt,
21 future::{join, join3, join5},
22};
23use ruma::{
24 RoomId, UInt,
25 events::{
26 StateEventType,
27 room::{
28 guest_access::RoomGuestAccessEventContent,
29 history_visibility::RoomHistoryVisibilityEventContent,
30 },
31 },
32 uint,
33};
34use synapse_admin_api::rooms::list_rooms::v1::RoomDetails;
35use tuwunel_core::{Result, utils::TryFutureExtExt};
36use tuwunel_matrix::Event;
37use tuwunel_service::Services;
38
39pub(crate) use self::{
40 block::{admin_get_room_block_route, admin_set_room_block_route},
41 context::admin_room_context_route,
42 delete_room::{admin_delete_room_v1_route, admin_delete_room_v2_route},
43 delete_status::{admin_delete_status_by_id_route, admin_delete_status_by_room_route},
44 forward_extremities::{
45 admin_delete_forward_extremities_route, admin_get_forward_extremities_route,
46 },
47 hierarchy::admin_room_hierarchy_route,
48 join::admin_join_room_route,
49 list_rooms::admin_list_rooms_route,
50 make_room_admin::admin_make_room_admin_route,
51 messages::admin_room_messages_route,
52 purge_history::{
53 admin_purge_history_by_event_route, admin_purge_history_route,
54 admin_purge_history_status_route,
55 },
56 room_details::admin_room_details_route,
57 room_members::admin_room_members_route,
58 state::admin_room_state_route,
59 timestamp_to_event::admin_room_timestamp_to_event_route,
60};
61
62const DELETE_ROOM_ACTION: &str = "shutdown_and_purge_room";
65
66const PURGE_HISTORY_ACTION: &str = "purge_history";
69
70async fn room_row(services: &Services, room_id: &RoomId) -> RoomDetails {
73 let name = services.state_accessor.get_name(room_id).ok();
74
75 let canonical_alias = services
76 .state_accessor
77 .get_canonical_alias(room_id)
78 .ok();
79
80 let room_type = services
81 .state_accessor
82 .get_room_type(room_id)
83 .ok();
84
85 let encryption = services
86 .state_accessor
87 .get_room_encryption(room_id)
88 .map_ok(|algorithm| algorithm.to_string())
89 .ok();
90
91 let join_rules = services
92 .state_accessor
93 .get_join_rules(room_id)
94 .map(|join_rule| Some(join_rule.kind()));
95
96 let guest_access = services
97 .state_accessor
98 .room_state_get_content(room_id, &StateEventType::RoomGuestAccess, "")
99 .map_ok(|content: RoomGuestAccessEventContent| content.guest_access)
100 .ok();
101
102 let history_visibility = services
103 .state_accessor
104 .room_state_get_content(room_id, &StateEventType::RoomHistoryVisibility, "")
105 .map_ok(|content: RoomHistoryVisibilityEventContent| content.history_visibility)
106 .ok();
107
108 let create = services
109 .state_accessor
110 .get_create(room_id)
111 .map(Result::ok);
112
113 let version = services
114 .state
115 .get_room_version(room_id)
116 .map_ok(|version| version.to_string())
117 .ok();
118
119 let public = services.directory.is_public_room(room_id);
120
121 let joined_members = services
122 .state_cache
123 .room_joined_count(room_id)
124 .map(|count| count_to_uint(count.ok()));
125
126 let joined_local_members = services
127 .state_cache
128 .local_users_in_room(room_id)
129 .count()
130 .map(usize_to_uint);
131
132 let state_events = state_event_count(services, room_id);
133
134 let (
135 (name, canonical_alias, room_type, encryption, join_rules),
136 (guest_access, history_visibility, create, version, public),
137 (joined_members, joined_local_members, state_events),
138 ) = join(
139 join5(name, canonical_alias, room_type, encryption, join_rules),
140 join(
141 join5(guest_access, history_visibility, create, version, public),
142 join3(joined_members, joined_local_members, state_events),
143 ),
144 )
145 .map(|(head, (mid, tail))| (head, mid, tail))
146 .boxed() .await;
148
149 let (creator, federatable) = create
150 .map(|create| (Some(create.sender().to_owned()), create.federate().unwrap_or(true)))
151 .unwrap_or((None, true));
152
153 RoomDetails {
154 room_id: room_id.to_owned(),
155 name,
156 canonical_alias,
157 joined_members,
158 joined_local_members,
159 version,
160 creator,
161 encryption,
162 federatable,
163 public,
164 join_rules,
165 guest_access,
166 history_visibility,
167 state_events,
168 room_type,
169 }
170}
171
172async fn state_event_count(services: &Services, room_id: &RoomId) -> UInt {
173 let Ok(shortstatehash) = services
174 .state
175 .get_room_shortstatehash(room_id)
176 .await
177 else {
178 return uint!(0);
179 };
180
181 let count = services
182 .state_accessor
183 .state_full_ids(shortstatehash)
184 .count()
185 .await;
186
187 usize_to_uint(count)
188}
189
190fn count_to_uint(count: Option<u64>) -> UInt {
191 count
192 .and_then(|count| count.try_into().ok())
193 .unwrap_or_else(|| uint!(0))
194}
195
196fn usize_to_uint(count: usize) -> UInt { count.try_into().unwrap_or_else(|_| uint!(0)) }