mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-05-26 20:49:55 +00:00
fix: Correctly update space children on upgrade
This commit is contained in:
@@ -2,7 +2,9 @@ use std::cmp::max;
|
|||||||
|
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use conduwuit::{
|
use conduwuit::{
|
||||||
Err, Error, Event, Result, err,
|
Err, Error, Event, Result, debug,
|
||||||
|
debug::DebugInspect,
|
||||||
|
err, error,
|
||||||
info::room_version::UNSTABLE_ROOM_VERSIONS,
|
info::room_version::UNSTABLE_ROOM_VERSIONS,
|
||||||
matrix::{StateKey, pdu::PartialPdu},
|
matrix::{StateKey, pdu::PartialPdu},
|
||||||
};
|
};
|
||||||
@@ -29,7 +31,7 @@ use serde_json::value::to_raw_value;
|
|||||||
use crate::router::Ruma;
|
use crate::router::Ruma;
|
||||||
|
|
||||||
/// Recommended transferable state events list from the spec
|
/// Recommended transferable state events list from the spec
|
||||||
const TRANSFERABLE_STATE_EVENTS: &[StateEventType; 11] = &[
|
const TRANSFERABLE_STATE_EVENTS: &[StateEventType; 9] = &[
|
||||||
StateEventType::RoomServerAcl,
|
StateEventType::RoomServerAcl,
|
||||||
StateEventType::RoomEncryption,
|
StateEventType::RoomEncryption,
|
||||||
StateEventType::RoomName,
|
StateEventType::RoomName,
|
||||||
@@ -39,9 +41,6 @@ const TRANSFERABLE_STATE_EVENTS: &[StateEventType; 11] = &[
|
|||||||
StateEventType::RoomHistoryVisibility,
|
StateEventType::RoomHistoryVisibility,
|
||||||
StateEventType::RoomJoinRules,
|
StateEventType::RoomJoinRules,
|
||||||
StateEventType::RoomPowerLevels,
|
StateEventType::RoomPowerLevels,
|
||||||
// MSC4168: https://github.com/matrix-org/matrix-spec-proposals/pull/4168
|
|
||||||
StateEventType::SpaceChild,
|
|
||||||
StateEventType::SpaceParent,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/// Updates spaces that are marked as parents of old_room_id to instead point to
|
/// Updates spaces that are marked as parents of old_room_id to instead point to
|
||||||
@@ -61,7 +60,8 @@ async fn msc4168_update_parent_spaces(
|
|||||||
.rooms
|
.rooms
|
||||||
.state_accessor
|
.state_accessor
|
||||||
.room_state_keys(old_room_id, &StateEventType::SpaceParent)
|
.room_state_keys(old_room_id, &StateEventType::SpaceParent)
|
||||||
.await?;
|
.await
|
||||||
|
.debug_inspect(|k| debug!(?old_room_id, "Parents: {k:?}"))?;
|
||||||
|
|
||||||
for raw_parent_id in parents {
|
for raw_parent_id in parents {
|
||||||
let parent_id = RoomId::parse(&raw_parent_id)?;
|
let parent_id = RoomId::parse(&raw_parent_id)?;
|
||||||
@@ -77,6 +77,15 @@ async fn msc4168_update_parent_spaces(
|
|||||||
old_room_id.as_str(),
|
old_room_id.as_str(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
.debug_inspect_err(|e| {
|
||||||
|
error!(
|
||||||
|
?parent_id,
|
||||||
|
old_room_id=?old_room_id,
|
||||||
|
new_room_id=?new_room_id,
|
||||||
|
%e,
|
||||||
|
"failed to fetch m.space.child from parent"
|
||||||
|
)
|
||||||
|
})
|
||||||
else {
|
else {
|
||||||
// If the space does not have a child event for this room, we can skip it
|
// If the space does not have a child event for this room, we can skip it
|
||||||
continue;
|
continue;
|
||||||
@@ -105,6 +114,15 @@ async fn msc4168_update_parent_spaces(
|
|||||||
)
|
)
|
||||||
.boxed()
|
.boxed()
|
||||||
.await
|
.await
|
||||||
|
.debug_inspect_err(|e| {
|
||||||
|
error!(
|
||||||
|
?parent_id,
|
||||||
|
old_room_id=?old_room_id,
|
||||||
|
new_room_id=?new_room_id,
|
||||||
|
%e,
|
||||||
|
"failed to send m.space.child to parent during room upgrade"
|
||||||
|
)
|
||||||
|
})
|
||||||
.ok();
|
.ok();
|
||||||
drop(state_lock);
|
drop(state_lock);
|
||||||
}
|
}
|
||||||
@@ -128,11 +146,14 @@ async fn msc4168_update_space_children(
|
|||||||
// children.
|
// children.
|
||||||
|
|
||||||
// In rooms that reference the old room via m.space.parent events...
|
// In rooms that reference the old room via m.space.parent events...
|
||||||
|
// NOTE: Doing that would be expensive. We'll instead fetch rooms which the
|
||||||
|
// space claims are children.
|
||||||
let parents = services
|
let parents = services
|
||||||
.rooms
|
.rooms
|
||||||
.state_accessor
|
.state_accessor
|
||||||
.room_state_keys(old_room_id, &StateEventType::SpaceParent)
|
.room_state_keys(old_room_id, &StateEventType::SpaceChild)
|
||||||
.await?;
|
.await
|
||||||
|
.debug_inspect(|k| debug!(?old_room_id, "Children: {k:?}"))?;
|
||||||
|
|
||||||
for raw_child_id in parents {
|
for raw_child_id in parents {
|
||||||
let child_id = RoomId::parse(&raw_child_id)?;
|
let child_id = RoomId::parse(&raw_child_id)?;
|
||||||
@@ -148,6 +169,15 @@ async fn msc4168_update_space_children(
|
|||||||
old_room_id.as_str(),
|
old_room_id.as_str(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
.debug_inspect_err(|e| {
|
||||||
|
error!(
|
||||||
|
?child_id,
|
||||||
|
old_room_id=?old_room_id,
|
||||||
|
new_room_id=?new_room_id,
|
||||||
|
%e,
|
||||||
|
"failed to fetch m.space.parent from child"
|
||||||
|
)
|
||||||
|
})
|
||||||
else {
|
else {
|
||||||
// If the child does not have a parent event for this room, we can skip it.
|
// If the child does not have a parent event for this room, we can skip it.
|
||||||
continue;
|
continue;
|
||||||
@@ -169,6 +199,13 @@ async fn msc4168_update_space_children(
|
|||||||
)
|
)
|
||||||
.boxed()
|
.boxed()
|
||||||
.await
|
.await
|
||||||
|
.debug_inspect_err(|e| error!(
|
||||||
|
child_id=?child_id,
|
||||||
|
old_room_id=?old_room_id,
|
||||||
|
new_room_id=?new_room_id,
|
||||||
|
%e,
|
||||||
|
"failed to send updated m.space.parent to child during room upgrade"
|
||||||
|
))
|
||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
// If the previous m.space.parent event has canonical set to true in content,
|
// If the previous m.space.parent event has canonical set to true in content,
|
||||||
@@ -179,19 +216,25 @@ async fn msc4168_update_space_children(
|
|||||||
.rooms
|
.rooms
|
||||||
.timeline
|
.timeline
|
||||||
.build_and_append_pdu(
|
.build_and_append_pdu(
|
||||||
PartialPdu {
|
PartialPdu::state(
|
||||||
event_type: StateEventType::SpaceParent.into(),
|
old_room_id.as_str(),
|
||||||
content: to_raw_value(&assign!(parent.clone(), {canonical: false}))
|
&assign!(parent.clone(), {canonical: false}),
|
||||||
.expect("event is valid, we just created it"),
|
),
|
||||||
state_key: Some(old_room_id.as_str().into()),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
sender,
|
sender,
|
||||||
Some(&child_id),
|
Some(&child_id),
|
||||||
&state_lock,
|
&state_lock,
|
||||||
)
|
)
|
||||||
.boxed()
|
.boxed()
|
||||||
.await
|
.await
|
||||||
|
.debug_inspect_err(|e| {
|
||||||
|
error!(
|
||||||
|
child_id=?child_id,
|
||||||
|
old_room_id=?old_room_id,
|
||||||
|
new_room_id=?new_room_id,
|
||||||
|
%e,
|
||||||
|
"failed to send non-canonical m.space.parent to child room"
|
||||||
|
)
|
||||||
|
})
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
drop(state_lock);
|
drop(state_lock);
|
||||||
@@ -334,6 +377,7 @@ pub(crate) async fn upgrade_room_route(
|
|||||||
// risk of concurrent in-flight collisions.
|
// risk of concurrent in-flight collisions.
|
||||||
services.rooms.state.mutex.lock("!new-room").await
|
services.rooms.state.mutex.lock("!new-room").await
|
||||||
};
|
};
|
||||||
|
debug!("Upgrading {} to room version {}", &body.room_id, &body.new_version);
|
||||||
let create_event_id = services
|
let create_event_id = services
|
||||||
.rooms
|
.rooms
|
||||||
.timeline
|
.timeline
|
||||||
@@ -372,6 +416,7 @@ pub(crate) async fn upgrade_room_route(
|
|||||||
(Some(new_room_id), lock)
|
(Some(new_room_id), lock)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
debug!("Upgraded {} to {}", &body.room_id, replacement_room_id.as_deref().unwrap());
|
||||||
// Join the new room
|
// Join the new room
|
||||||
services
|
services
|
||||||
.rooms
|
.rooms
|
||||||
@@ -446,6 +491,7 @@ pub(crate) async fn upgrade_room_route(
|
|||||||
.expect("event is valid, we just deserialized and modified it");
|
.expect("event is valid, we just deserialized and modified it");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug!(%event_type, ?state_key, "Transferring state event to new room");
|
||||||
services
|
services
|
||||||
.rooms
|
.rooms
|
||||||
.timeline
|
.timeline
|
||||||
@@ -473,6 +519,7 @@ pub(crate) async fn upgrade_room_route(
|
|||||||
.boxed();
|
.boxed();
|
||||||
|
|
||||||
while let Some(alias) = local_aliases.next().await {
|
while let Some(alias) = local_aliases.next().await {
|
||||||
|
debug!(?alias, "Migrating alias");
|
||||||
services
|
services
|
||||||
.rooms
|
.rooms
|
||||||
.alias
|
.alias
|
||||||
@@ -488,6 +535,7 @@ pub(crate) async fn upgrade_room_route(
|
|||||||
|
|
||||||
// 5. Send a `m.room.tombstone` event to the old room to indicate that it is not
|
// 5. Send a `m.room.tombstone` event to the old room to indicate that it is not
|
||||||
// intended to be used any further.
|
// intended to be used any further.
|
||||||
|
debug!(target=?body.room_id, "Sending tombstone to old room");
|
||||||
services
|
services
|
||||||
.rooms
|
.rooms
|
||||||
.timeline
|
.timeline
|
||||||
@@ -529,6 +577,7 @@ pub(crate) async fn upgrade_room_route(
|
|||||||
// 6. Modify the power levels in the old room to prevent sending of events and
|
// 6. Modify the power levels in the old room to prevent sending of events and
|
||||||
// inviting new users
|
// inviting new users
|
||||||
// Spec dictates that this is allowed to fail.
|
// Spec dictates that this is allowed to fail.
|
||||||
|
debug!(target=?body.room_id, ?new_level, "Raising power level in old room to lock it");
|
||||||
services
|
services
|
||||||
.rooms
|
.rooms
|
||||||
.timeline
|
.timeline
|
||||||
@@ -546,6 +595,7 @@ pub(crate) async fn upgrade_room_route(
|
|||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
// MSC4168: Update spaces that reference this room to point at the new room.
|
// MSC4168: Update spaces that reference this room to point at the new room.
|
||||||
|
debug!("Updating parent spaces");
|
||||||
msc4168_update_parent_spaces(
|
msc4168_update_parent_spaces(
|
||||||
&services,
|
&services,
|
||||||
sender_user,
|
sender_user,
|
||||||
@@ -553,8 +603,18 @@ pub(crate) async fn upgrade_room_route(
|
|||||||
replacement_room_id.as_deref().unwrap(),
|
replacement_room_id.as_deref().unwrap(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
.inspect_err(|e| {
|
||||||
|
error!(
|
||||||
|
old_room_id=?body.room_id,
|
||||||
|
new_room_id=?replacement_room_id.as_deref().unwrap(),
|
||||||
|
%e,
|
||||||
|
"failed to update parent spaces during room upgrade"
|
||||||
|
)
|
||||||
|
})
|
||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
// MSC4168: Update child rooms to point at the new space, where possible
|
// MSC4168: Update child rooms to point at the new space, where possible
|
||||||
|
debug!("Updating space children");
|
||||||
msc4168_update_space_children(
|
msc4168_update_space_children(
|
||||||
&services,
|
&services,
|
||||||
sender_user,
|
sender_user,
|
||||||
@@ -562,6 +622,14 @@ pub(crate) async fn upgrade_room_route(
|
|||||||
replacement_room_id.as_deref().unwrap(),
|
replacement_room_id.as_deref().unwrap(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
.inspect_err(|e| {
|
||||||
|
error!(
|
||||||
|
old_room_id=?body.room_id,
|
||||||
|
new_room_id=?replacement_room_id.as_deref().unwrap(),
|
||||||
|
%e,
|
||||||
|
"failed to update space children during room upgrade"
|
||||||
|
)
|
||||||
|
})
|
||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
// Return the replacement room id
|
// Return the replacement room id
|
||||||
|
|||||||
Reference in New Issue
Block a user