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 match &body.field {
73 | Some(field) => {
74 let value = services
75 .profile
76 .profile_key(&body.user_id, field)
77 .await
78 .ok();
79
80 let response = value
81 .map(|value| ProfileFieldValue::new(field.as_str(), value))
82 .transpose()
83 .map_err(|_| {
84 err!(Database(
85 error!(user_id = %body.user_id, key = %field, "Invalid json in database profile value")
86 ))
87 })?
88 .into_iter()
89 .collect();
90
91 Ok(response)
92 },
93 | None => {
94 let response = services
95 .profile
96 .all_profile_keys(&body.user_id)
97 .collect::<_>()
98 .await;
99
100 Ok(response)
101 },
102 }
103}