tuwunel_admin/room/
alias.rs1use std::fmt::Write;
2
3use clap::Subcommand;
4use futures::StreamExt;
5use ruma::{OwnedRoomAliasId, OwnedRoomId};
6use tuwunel_core::{Err, Result, err};
7use tuwunel_macros::{admin_command, admin_command_dispatch};
8use tuwunel_service::Services;
9
10use crate::Context;
11
12#[admin_command_dispatch(handler_prefix = "alias")]
13#[derive(Debug, Subcommand)]
14pub(crate) enum RoomAliasCommand {
15 Set {
17 #[arg(short, long)]
18 force: bool,
20
21 room_id: OwnedRoomId,
23
24 room_alias_localpart: String,
26 },
27
28 Remove {
30 room_alias_localpart: String,
32 },
33
34 Which {
36 room_alias_localpart: String,
39 },
40
41 List {
43 room_id: Option<OwnedRoomId>,
45 },
46}
47
48fn parse_alias_from_localpart(
49 services: &Services,
50 room_alias_localpart: &String,
51) -> Result<OwnedRoomAliasId> {
52 let room_alias_str = format!("#{}:{}", room_alias_localpart, services.globals.server_name());
53
54 Ok(OwnedRoomAliasId::try_from(room_alias_str)?)
55}
56
57#[admin_command]
58pub(super) async fn alias_set(
59 &self,
60 force: bool,
61 room_id: OwnedRoomId,
62 room_alias_localpart: String,
63) -> Result {
64 let room_alias = parse_alias_from_localpart(self.services, &room_alias_localpart)?;
65
66 match self
67 .services
68 .alias
69 .resolve_local_alias(&room_alias)
70 .await
71 {
72 | Ok(id) => {
73 if !force {
74 return Err!(
75 "Refusing to overwrite in use alias for {id}, use -f or --force to overwrite"
76 );
77 }
78
79 self.services
80 .alias
81 .set_alias(&room_alias, &room_id)
82 .map_err(|err| err!("Failed to remove alias: {err}"))?;
83
84 self.write_str(&format!("Successfully overwrote alias (formerly {id})"))
85 .await
86 },
87 | _ => {
88 self.services
89 .alias
90 .set_alias(&room_alias, &room_id)
91 .map_err(|err| err!("Failed to remove alias: {err}"))?;
92
93 self.write_str("Successfully set alias").await
94 },
95 }
96}
97
98#[admin_command]
99pub(super) async fn alias_remove(&self, room_alias_localpart: String) -> Result {
100 let room_alias = parse_alias_from_localpart(self.services, &room_alias_localpart)?;
101
102 let id = self
103 .services
104 .alias
105 .resolve_local_alias(&room_alias)
106 .await
107 .map_err(|_| err!("Alias isn't in use."))?;
108
109 self.services
110 .alias
111 .remove_alias(&room_alias)
112 .await
113 .map_err(|err| err!("Failed to remove alias: {err}"))?;
114
115 self.write_str(&format!("Removed alias from {id}"))
116 .await
117}
118
119#[admin_command]
120pub(super) async fn alias_which(&self, room_alias_localpart: String) -> Result {
121 let room_alias = parse_alias_from_localpart(self.services, &room_alias_localpart)?;
122
123 let id = self
124 .services
125 .alias
126 .resolve_local_alias(&room_alias)
127 .await
128 .map_err(|_| err!("Alias isn't in use."))?;
129
130 self.write_str(&format!("Alias resolves to {id}"))
131 .await
132}
133
134#[admin_command]
135pub(super) async fn alias_list(&self, room_id: Option<OwnedRoomId>) -> Result {
136 match room_id {
137 | Some(room_id) => list_aliases_for_room(self, room_id).await,
138 | None => list_all_aliases(self).await,
139 }
140}
141
142async fn list_aliases_for_room(context: &Context<'_>, room_id: OwnedRoomId) -> Result {
143 let aliases: Vec<OwnedRoomAliasId> = context
144 .services
145 .alias
146 .local_aliases_for_room(&room_id)
147 .map(Into::into)
148 .collect()
149 .await;
150
151 let mut plain_list = String::new();
152
153 for alias in aliases {
154 writeln!(plain_list, "- {alias}")?;
155 }
156
157 let plain = format!("Aliases for {room_id}:\n{plain_list}");
158 context.write_str(&plain).await
159}
160
161async fn list_all_aliases(context: &Context<'_>) -> Result {
162 let aliases = context
163 .services
164 .alias
165 .all_local_aliases()
166 .map(|(room_id, localpart)| (room_id.to_owned(), localpart.to_owned()))
167 .collect::<Vec<_>>()
168 .await;
169
170 let server_name = context.services.globals.server_name();
171
172 let mut plain_list = String::new();
173 for (room_id, alias_id) in aliases {
174 writeln!(plain_list, "- `{room_id}` -> #{alias_id}:{server_name}")?;
175 }
176
177 let plain = format!("Aliases:\n{plain_list}");
178 context.write_str(&plain).await
179}