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, InsecureClientIp(client): InsecureClientIp, body: Ruma, ) -> Result { 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, InsecureClientIp(client): InsecureClientIp, body: Ruma, ) -> Result { 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 }) }