tuwunel_api/client/
alias.rs1use axum::extract::State;
2use futures::StreamExt;
3use rand::seq::SliceRandom;
4use ruma::{
5 OwnedServerName, RoomAliasId, RoomId,
6 api::client::alias::{create_alias, delete_alias, get_alias},
7};
8use tuwunel_core::{Err, Result, debug, err};
9use tuwunel_service::Services;
10
11use crate::Ruma;
12
13pub(crate) async fn create_alias_route(
17 State(services): State<crate::State>,
18 body: Ruma<create_alias::v3::Request>,
19) -> Result<create_alias::v3::Response> {
20 let sender_user = body.sender_user();
21 services
22 .alias
23 .appservice_checks(&body.room_alias, &body.appservice_info)
24 .await?;
25
26 if services
29 .config
30 .forbidden_alias_names
31 .is_match(body.room_alias.alias())
32 {
33 return Err!(Request(Forbidden("Room alias is forbidden.")));
34 }
35
36 if services
37 .alias
38 .resolve_local_alias(&body.room_alias)
39 .await
40 .is_ok()
41 {
42 return Err!(Conflict("Alias already exists."));
43 }
44
45 services
46 .alias
47 .set_alias_by(&body.room_alias, &body.room_id, sender_user)?;
48
49 Ok(create_alias::v3::Response::new())
50}
51
52pub(crate) async fn delete_alias_route(
58 State(services): State<crate::State>,
59 body: Ruma<delete_alias::v3::Request>,
60) -> Result<delete_alias::v3::Response> {
61 let sender_user = body.sender_user();
62 services
63 .alias
64 .appservice_checks(&body.room_alias, &body.appservice_info)
65 .await?;
66
67 services
68 .alias
69 .remove_alias_by(&body.room_alias, sender_user)
70 .await?;
71
72 Ok(delete_alias::v3::Response::new())
75}
76
77pub(crate) async fn get_alias_route(
81 State(services): State<crate::State>,
82 body: Ruma<get_alias::v3::Request>,
83) -> Result<get_alias::v3::Response> {
84 let room_alias = body.body.room_alias;
85
86 let (room_id, servers) = services
87 .alias
88 .resolve_alias(&room_alias)
89 .await
90 .map_err(|_| err!(Request(NotFound("Room with alias not found."))))?;
91
92 let servers = room_available_servers(&services, &room_id, &room_alias, servers).await;
93 debug!(?room_alias, ?room_id, "available servers: {servers:?}");
94
95 Ok(get_alias::v3::Response::new(room_id, servers))
96}
97
98async fn room_available_servers(
99 services: &Services,
100 room_id: &RoomId,
101 room_alias: &RoomAliasId,
102 pre_servers: Vec<OwnedServerName>,
103) -> Vec<OwnedServerName> {
104 let mut servers: Vec<OwnedServerName> = services
106 .state_cache
107 .room_servers(room_id)
108 .map(ToOwned::to_owned)
109 .collect()
110 .await;
111
112 servers.extend(pre_servers);
115
116 servers.sort_unstable();
117 servers.dedup();
118
119 servers.shuffle(&mut rand::rng());
121
122 if let Some(server_index) = servers
125 .iter()
126 .position(|server_name| services.globals.server_is_ours(server_name))
127 {
128 servers.swap(0, server_index);
129 } else if let Some(alias_server_index) = servers
130 .iter()
131 .position(|server| server == room_alias.server_name())
132 {
133 servers.swap(0, alias_server_index);
134 }
135
136 servers
137}