Files
tuwunel/src/api/client/membership/join.rs
2025-12-03 09:23:33 +00:00

122 lines
3.3 KiB
Rust

use axum::extract::State;
use axum_client_ip::InsecureClientIp;
use futures::FutureExt;
use ruma::{
RoomId, RoomOrAliasId,
api::client::membership::{join_room_by_id, join_room_by_id_or_alias},
};
use tuwunel_core::{Result, warn};
use super::banned_room_check;
use crate::{Ruma, client::membership::get_join_params};
/// # `POST /_matrix/client/r0/rooms/{roomId}/join`
///
/// Tries to join the sender user into a room.
///
/// - If the server knowns about this room: creates the join event and does auth
/// rules locally
/// - If the server does not know about the room: asks other servers over
/// federation
#[tracing::instrument(skip_all, fields(%client), name = "join")]
pub(crate) async fn join_room_by_id_route(
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<join_room_by_id::v3::Request>,
) -> Result<join_room_by_id::v3::Response> {
let sender_user = body.sender_user();
let room_id: &RoomId = &body.room_id;
banned_room_check(&services, sender_user, Some(room_id), room_id.server_name(), client)
.await?;
let (room_id, servers) =
get_join_params(&services, sender_user, <&RoomOrAliasId>::from(room_id), &[]).await?;
let state_lock = services.state.mutex.lock(&room_id).await;
let mut errors = 0_usize;
while let Err(e) = services
.membership
.join(
sender_user,
&room_id,
body.reason.clone(),
&servers,
&body.appservice_info,
&state_lock,
)
.boxed()
.await
{
errors = errors.saturating_add(1);
if errors >= services.config.max_join_attempts_per_join_request {
warn!(
"Several servers failed. Giving up for this request. Try again for different \
server selection."
);
return Err(e);
}
}
drop(state_lock);
Ok(join_room_by_id::v3::Response { room_id })
}
/// # `POST /_matrix/client/r0/join/{roomIdOrAlias}`
///
/// Tries to join the sender user into a room.
///
/// - If the server knowns about this room: creates the join event and does auth
/// rules locally
/// - If the server does not know about the room: use the server name query
/// param if specified. if not specified, asks other servers over federation
/// via room alias server name and room ID server name
#[tracing::instrument(skip_all, fields(%client), name = "join")]
pub(crate) async fn join_room_by_id_or_alias_route(
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<join_room_by_id_or_alias::v3::Request>,
) -> Result<join_room_by_id_or_alias::v3::Response> {
let sender_user = body.sender_user();
let appservice_info = &body.appservice_info;
let (room_id, servers) =
get_join_params(&services, sender_user, &body.room_id_or_alias, &body.via).await?;
banned_room_check(&services, sender_user, Some(&room_id), room_id.server_name(), client)
.await?;
let state_lock = services.state.mutex.lock(&room_id).await;
let mut errors = 0_usize;
while let Err(e) = services
.membership
.join(
sender_user,
&room_id,
body.reason.clone(),
&servers,
appservice_info,
&state_lock,
)
.boxed()
.await
{
errors = errors.saturating_add(1);
if errors >= services.config.max_join_attempts_per_join_request {
warn!(
"Several servers failed. Giving up for this request. Try again for different \
server selection."
);
return Err(e);
}
}
drop(state_lock);
Ok(join_room_by_id_or_alias::v3::Response { room_id })
}