feat: Combine local & remote force join

This commit is contained in:
timedout
2026-05-25 18:01:08 +01:00
parent 1d172be503
commit c1a6e649da
4 changed files with 32 additions and 62 deletions
+19 -12
View File
@@ -6,24 +6,24 @@ use std::{
}; };
use conduwuit::{ use conduwuit::{
debug_error, err, info, matrix::{ Err, Result, debug_error, err, info,
pdu::{PduEvent, PduId, RawPduId}, matrix::{
Event, Event,
}, trace, pdu::{PduEvent, PduId, RawPduId},
utils, },
trace, utils,
utils::{ utils::{
stream::{IterStream, ReadyExt}, stream::{IterStream, ReadyExt},
string::EMPTY, string::EMPTY,
}, warn, },
Err, warn,
Result,
}; };
use futures::{FutureExt, StreamExt, TryStreamExt}; use futures::{FutureExt, StreamExt, TryStreamExt};
use lettre::message::Mailbox; use lettre::message::Mailbox;
use ruma::{ use ruma::{
api::federation::event::get_room_state, events::AnyStateEvent, serde::Raw, CanonicalJsonObject, CanonicalJsonValue, CanonicalJsonObject, CanonicalJsonValue, EventId, OwnedEventId, OwnedRoomId,
EventId, OwnedEventId, OwnedRoomId, OwnedRoomOrAliasId, OwnedServerName, OwnedRoomOrAliasId, OwnedServerName, RoomId, RoomVersionId, UInt,
RoomId, RoomVersionId, UInt, api::federation::event::get_room_state, events::AnyStateEvent, serde::Raw,
}; };
use service::rooms::{ use service::rooms::{
short::{ShortEventId, ShortRoomId}, short::{ShortEventId, ShortRoomId},
@@ -98,7 +98,8 @@ fn render_node(
| NodeStatus::Normal(false) => format!("{evt_str}: {name}"), | NodeStatus::Normal(false) => format!("{evt_str}: {name}"),
| NodeStatus::Normal(true) => format!("{evt_str}: {name} (missing locally)"), | NodeStatus::Normal(true) => format!("{evt_str}: {name} (missing locally)"),
| NodeStatus::SoftFailed(false) => format!("{evt_str}: {name} (soft-failed)"), | NodeStatus::SoftFailed(false) => format!("{evt_str}: {name} (soft-failed)"),
| NodeStatus::SoftFailed(true) => format!("{evt_str}: {name} (soft-failed & missing locally)"), | NodeStatus::SoftFailed(true) =>
format!("{evt_str}: {name} (soft-failed & missing locally)"),
| NodeStatus::Rejected(false) => format!("{evt_str}: {name} (rejected)"), | NodeStatus::Rejected(false) => format!("{evt_str}: {name} (rejected)"),
| NodeStatus::Rejected(true) => format!("{evt_str}: {name} (rejected & missing locally)"), | NodeStatus::Rejected(true) => format!("{evt_str}: {name} (rejected & missing locally)"),
}; };
@@ -186,7 +187,13 @@ pub(super) async fn show_auth_chain(&self, event_id: OwnedEventId) -> Result {
let current_node_id = node_id_for(&current_event_id, &mut node_ids, &mut next_node_id); let current_node_id = node_id_for(&current_event_id, &mut node_ids, &mut next_node_id);
let current_status = node_status(&current_event_id, false).await; let current_status = node_status(&current_event_id, false).await;
render_node(&mut graph, &current_node_id, &current_event_id, &node_name(&event), current_status)?; render_node(
&mut graph,
&current_node_id,
&current_event_id,
&node_name(&event),
current_status,
)?;
let mut children = Vec::with_capacity(event.auth_events.len()); let mut children = Vec::with_capacity(event.auth_events.len());
for auth_event_id in event.auth_events().rev() { for auth_event_id in event.auth_events().rev() {
+6 -36
View File
@@ -740,14 +740,19 @@ pub(super) async fn force_join_room(
&self, &self,
user_id: String, user_id: String,
room_id: OwnedRoomOrAliasId, room_id: OwnedRoomOrAliasId,
via: Option<String>,
) -> Result { ) -> Result {
let user_id = parse_local_user_id(self.services, &user_id)?; let user_id = parse_local_user_id(self.services, &user_id)?;
let (room_id, servers) = self let (room_id, mut servers) = self
.services .services
.rooms .rooms
.alias .alias
.resolve_with_servers(&room_id, None) .resolve_with_servers(&room_id, None)
.await?; .await?;
if let Some(via) = via.map(ServerName::parse).transpose()? {
servers.retain(|n| *n != via);
servers.insert(0, via);
}
assert!( assert!(
self.services.globals.user_is_local(&user_id), self.services.globals.user_is_local(&user_id),
@@ -763,41 +768,6 @@ pub(super) async fn force_join_room(
.await .await
} }
#[admin_command]
pub(super) async fn force_join_room_remotely(
&self,
user_id: String,
room_id: OwnedRoomOrAliasId,
via: String,
) -> Result {
let via = ServerName::parse(&via)?;
let user_id = parse_local_user_id(self.services, &user_id)?;
let (room_id, mut servers) = self
.services
.rooms
.alias
.resolve_with_servers(&room_id, None)
.await?;
if servers.contains(&via) {
servers.retain(|n| *n != via);
}
servers.insert(0, via);
assert!(
self.services.globals.user_is_local(&user_id),
"Parsed user_id must be a local user"
);
let state_lock = self.services.rooms.state.mutex.lock(&*room_id).await;
self.services
.rooms
.membership
.join_remote_room(&user_id, &room_id, None, &servers, state_lock)
.await?;
self.write_str(&format!("{user_id} has been joined to {room_id}."))
.await
}
#[admin_command] #[admin_command]
pub(super) async fn force_leave_room( pub(super) async fn force_leave_room(
&self, &self,
+1 -8
View File
@@ -179,13 +179,6 @@ pub enum UserCommand {
/// Manually join a local user to a room. /// Manually join a local user to a room.
ForceJoinRoom { ForceJoinRoom {
user_id: String,
room_id: OwnedRoomOrAliasId,
},
/// Manually join a local user to a room via a remote server, regardless of
/// our current residency.
ForceJoinRoomRemotely {
/// The user to join /// The user to join
user_id: String, user_id: String,
/// The room to join /// The room to join
@@ -194,7 +187,7 @@ pub enum UserCommand {
/// ///
/// This server will always be tried first, however if more are /// This server will always be tried first, however if more are
/// available, they may be tried after. /// available, they may be tried after.
via: String, via: Option<String>,
}, },
/// Manually leave a local user from a room. /// Manually leave a local user from a room.
@@ -1,17 +1,17 @@
use std::{borrow::Borrow, collections::BTreeMap, sync::Arc, time::Instant}; use std::{borrow::Borrow, collections::BTreeMap, sync::Arc, time::Instant};
use conduwuit::{ use conduwuit::{
debug, debug_info, debug_warn, err, implement, is_equal_to, matrix::{state_res, Event, EventTypeExt, PduEvent, StateKey}, trace, Err, Result, debug, debug_info, debug_warn, err, implement, is_equal_to,
matrix::{Event, EventTypeExt, PduEvent, StateKey, state_res},
trace,
utils::{ utils::{
stream::{BroadbandExt, ReadyExt},
IterStream, IterStream,
stream::{BroadbandExt, ReadyExt},
}, },
warn, warn,
Err,
Result,
}; };
use futures::{future::ready, FutureExt, StreamExt}; use futures::{FutureExt, StreamExt, future::ready};
use ruma::{events::StateEventType, CanonicalJsonValue, RoomId, ServerName}; use ruma::{CanonicalJsonValue, RoomId, ServerName, events::StateEventType};
use tokio::join; use tokio::join;
use super::get_room_version_rules; use super::get_room_version_rules;