Skip to main content

tuwunel_api/client/membership/
join.rs

1use axum::extract::State;
2use futures::FutureExt;
3use ruma::{
4	RoomId,
5	api::client::membership::{join_room_by_id, join_room_by_id_or_alias},
6};
7use tuwunel_core::{Result, warn};
8
9use super::banned_room_check;
10use crate::{ClientIp, Ruma};
11
12/// # `POST /_matrix/client/r0/rooms/{roomId}/join`
13///
14/// Tries to join the sender user into a room.
15///
16/// - If the server knowns about this room: creates the join event and does auth
17///   rules locally
18/// - If the server does not know about the room: asks other servers over
19///   federation
20#[tracing::instrument(skip_all, fields(%client), name = "join")]
21pub(crate) async fn join_room_by_id_route(
22	State(services): State<crate::State>,
23	ClientIp(client): ClientIp,
24	body: Ruma<join_room_by_id::v3::Request>,
25) -> Result<join_room_by_id::v3::Response> {
26	let sender_user = body.sender_user();
27
28	let room_id: &RoomId = &body.room_id;
29
30	banned_room_check(&services, sender_user, room_id, None, client).await?;
31
32	let mut errors = 0_usize;
33	while let Err(e) = services
34		.membership
35		.join(
36			sender_user,
37			room_id,
38			None,
39			body.reason.clone(),
40			&[],
41			body.appservice_info.is_some(),
42		)
43		.boxed()
44		.await
45	{
46		errors = errors.saturating_add(1);
47		if errors >= services.config.max_join_attempts_per_join_request {
48			warn!(
49				"Several servers failed. Giving up for this request. Try again for different \
50				 server selection."
51			);
52			return Err(e);
53		}
54	}
55
56	Ok(join_room_by_id::v3::Response { room_id: room_id.to_owned() })
57}
58
59/// # `POST /_matrix/client/r0/join/{roomIdOrAlias}`
60///
61/// Tries to join the sender user into a room.
62///
63/// - If the server knowns about this room: creates the join event and does auth
64///   rules locally
65/// - If the server does not know about the room: use the server name query
66///   param if specified. if not specified, asks other servers over federation
67///   via room alias server name and room ID server name
68#[tracing::instrument(skip_all, fields(%client), name = "join")]
69pub(crate) async fn join_room_by_id_or_alias_route(
70	State(services): State<crate::State>,
71	ClientIp(client): ClientIp,
72	body: Ruma<join_room_by_id_or_alias::v3::Request>,
73) -> Result<join_room_by_id_or_alias::v3::Response> {
74	let sender_user = body.sender_user();
75	let appservice_info = &body.appservice_info;
76
77	let (room_id, servers) = services
78		.alias
79		.maybe_resolve_with_servers(&body.room_id_or_alias, Some(&body.via))
80		.await?;
81
82	banned_room_check(&services, sender_user, &room_id, Some(&body.room_id_or_alias), client)
83		.await?;
84
85	let mut errors = 0_usize;
86	while let Err(e) = services
87		.membership
88		.join(
89			sender_user,
90			&room_id,
91			Some(&body.room_id_or_alias),
92			body.reason.clone(),
93			&servers,
94			appservice_info.is_some(),
95		)
96		.boxed()
97		.await
98	{
99		errors = errors.saturating_add(1);
100		if errors >= services.config.max_join_attempts_per_join_request {
101			warn!(
102				"Several servers failed. Giving up for this request. Try again for different \
103				 server selection."
104			);
105			return Err(e);
106		}
107	}
108
109	Ok(join_room_by_id_or_alias::v3::Response { room_id: room_id.clone() })
110}