tuwunel_api/server/
query.rs1use axum::extract::State;
2use futures::StreamExt;
3use rand::seq::SliceRandom;
4use ruma::{
5 OwnedServerName,
6 api::federation::query::{get_profile_information, get_room_information},
7 profile::ProfileFieldValue,
8};
9use tuwunel_core::{Err, Result, err};
10
11use crate::Ruma;
12
13pub(crate) async fn get_room_information_route(
17 State(services): State<crate::State>,
18 body: Ruma<get_room_information::v1::Request>,
19) -> Result<get_room_information::v1::Response> {
20 let room_id = services
21 .alias
22 .resolve_local_alias(&body.room_alias)
23 .await
24 .map_err(|_| err!(Request(NotFound("Room alias not found."))))?;
25
26 let mut servers: Vec<OwnedServerName> = services
27 .state_cache
28 .room_servers(&room_id)
29 .map(ToOwned::to_owned)
30 .collect()
31 .await;
32
33 servers.sort_unstable();
34 servers.dedup();
35
36 servers.shuffle(&mut rand::rng());
37
38 if let Some(server_index) = servers
40 .iter()
41 .position(|server| server == services.globals.server_name())
42 {
43 servers.swap_remove(server_index);
44 servers.insert(0, services.globals.server_name().to_owned());
45 }
46
47 Ok(get_room_information::v1::Response { room_id, servers })
48}
49
50pub(crate) async fn get_profile_information_route(
55 State(services): State<crate::State>,
56 body: Ruma<get_profile_information::v1::Request>,
57) -> Result<get_profile_information::v1::Response> {
58 if !services
59 .server
60 .config
61 .allow_inbound_profile_lookup_federation_requests
62 {
63 return Err!(Request(Forbidden(
64 "Profile lookup over federation is not allowed on this homeserver.",
65 )));
66 }
67
68 if !services.globals.user_is_local(&body.user_id) {
69 return Err!(Request(InvalidParam("User does not belong to this server.",)));
70 }
71
72 if !services.users.exists(&body.user_id).await {
73 return Err!(Request(NotFound("Profile was not found.")));
74 }
75
76 match &body.field {
77 | Some(field) => {
78 let value = services
79 .profile
80 .profile_key(&body.user_id, field)
81 .await
82 .ok();
83
84 let response = value
85 .map(|value| ProfileFieldValue::new(field.as_str(), value))
86 .transpose()
87 .map_err(|_| {
88 err!(Database(
89 error!(user_id = %body.user_id, key = %field, "Invalid json in database profile value")
90 ))
91 })?
92 .into_iter()
93 .collect();
94
95 Ok(response)
96 },
97 | None => {
98 let response = services
99 .profile
100 .all_profile_keys(&body.user_id)
101 .collect::<_>()
102 .await;
103
104 Ok(response)
105 },
106 }
107}