From e3a954982477f642a9e9a53435dfe1df474c97bb Mon Sep 17 00:00:00 2001 From: Ginger Date: Wed, 27 May 2026 14:14:19 -0400 Subject: [PATCH] fix: Correctly sync newly created rooms --- src/api/client/sync/v3/joined.rs | 44 ++++++++++++-------------------- src/api/client/sync/v3/left.rs | 27 +++----------------- src/api/client/sync/v3/state.rs | 16 ++++++------ 3 files changed, 28 insertions(+), 59 deletions(-) diff --git a/src/api/client/sync/v3/joined.rs b/src/api/client/sync/v3/joined.rs index 5392776af..d225a1e5c 100644 --- a/src/api/client/sync/v3/joined.rs +++ b/src/api/client/sync/v3/joined.rs @@ -381,21 +381,25 @@ async fn fetch_shortstatehashes( | Some((_, pdu_after_last_sync_end)) => { trace!(?pdu_after_last_sync_end.event_id, "pdu at last sync end"); - services - .rooms - .state_accessor - .pdu_shortstatehash(&pdu_after_last_sync_end.event_id) - .await - .map_err(|err| err!("Last sync end PDU has no shortstatehash: {err}")) + Some( + services + .rooms + .state_accessor + .pdu_shortstatehash(&pdu_after_last_sync_end.event_id) + .await + .map_err(|err| { + err!("Last sync end PDU has no shortstatehash: {err}") + }), + ) }, | None => { - // No events have been sent since the last sync, or we just joined this room, - // so the state then is the same as the state now - Ok(current_shortstatehash) + // No events have been sent since the last sync, or we just joined this room + None }, } })) .await + .flatten() .transpose()?; Ok(ShortStateHashes { @@ -464,23 +468,10 @@ async fn build_state_events( last_sync_end_shortstatehash, } = shortstatehashes; - let timeline_start_shortstatehash = if let Some((count, pdu)) = timeline.pdus.front() { - if matches!(count, PduCount::Backfilled(_)) { - // We don't have shortstatehashes for backfilled PDUs, the best we can - // do is to use the current state - current_shortstatehash - } else { - services - .rooms - .state_accessor - .pdu_shortstatehash(&pdu.event_id) - .await - .map_err(|err| err!("Timeline start has no shortstatehash: {err}"))? - } - } else { - // if the timeline is empty there can't possibly be any changes to the state + if timeline.pdus.is_empty() { + // If the timeline is empty there can't possibly be any changes to the state return Ok(vec![]); - }; + } // the user IDs of members whose membership needs to be sent to the client, if // lazy-loading is enabled. @@ -499,7 +490,6 @@ async fn build_state_events( services, syncing_user, last_sync_end_shortstatehash, - timeline_start_shortstatehash, current_shortstatehash, timeline, use_state_after, @@ -516,8 +506,8 @@ async fn build_state_events( build_state_initial( services, syncing_user, - timeline_start_shortstatehash, current_shortstatehash, + timeline, use_state_after, lazily_loaded_members.as_ref(), ) diff --git a/src/api/client/sync/v3/left.rs b/src/api/client/sync/v3/left.rs index 63d14b9ce..209387713 100644 --- a/src/api/client/sync/v3/left.rs +++ b/src/api/client/sync/v3/left.rs @@ -4,7 +4,7 @@ use conduwuit::{ trace, utils::{self, IterStream, future::ReadyEqExt, stream::WidebandExt as _}, }; -use futures::{StreamExt, future::join}; +use futures::StreamExt; use ruma::{ EventId, OwnedRoomId, RoomId, api::client::sync::sync_events::v3::{ @@ -240,29 +240,8 @@ async fn build_left_state_and_timeline( ) .await?; - let timeline_start_shortstatehash = async { - if let Some((_, pdu)) = timeline.pdus.front() { - if let Ok(shortstatehash) = services - .rooms - .state_accessor - .pdu_shortstatehash(&pdu.event_id) - .await - { - return shortstatehash; - } - } - - // the timeline generally should not be empty (see the TODO further down), - // but in case it is we use `leave_shortstatehash` as the state to - // send - leave_shortstatehash - }; - let lazily_loaded_members = - prepare_lazily_loaded_members(services, sync_context, room_id, timeline.senders()); - - let (timeline_start_shortstatehash, lazily_loaded_members) = - join(timeline_start_shortstatehash, lazily_loaded_members).await; + prepare_lazily_loaded_members(services, sync_context, room_id, timeline.senders()).await; // TODO: calculate incremental state for incremental syncs. // always calculating initial state _works_ but returns more data and does @@ -270,8 +249,8 @@ async fn build_left_state_and_timeline( let mut state = build_state_initial( services, syncing_user, - timeline_start_shortstatehash, leave_shortstatehash, + &timeline, sync_context.use_state_after, lazily_loaded_members.as_ref(), ) diff --git a/src/api/client/sync/v3/state.rs b/src/api/client/sync/v3/state.rs index 0da053d65..3f6f0aa32 100644 --- a/src/api/client/sync/v3/state.rs +++ b/src/api/client/sync/v3/state.rs @@ -33,19 +33,21 @@ use crate::client::TimelinePdus; pub(super) async fn build_state_initial( services: &Services, sender_user: &UserId, - timeline_start_shortstatehash: ShortStateHash, timeline_end_shortstatehash: ShortStateHash, + timeline: &TimelinePdus, use_state_after: bool, lazily_loaded_members: Option<&MemberSet>, ) -> Result> { + let event_ids_in_timeline: HashSet<_> = + timeline.pdus.iter().map(|pdu| &pdu.1.event_id).collect(); + // load the keys and event IDs of the state events at the start of the timeline let (shortstatekeys, event_ids): (Vec<_>, Vec<_>) = services .rooms .state_accessor - .state_full_ids(if use_state_after { - timeline_end_shortstatehash - } else { - timeline_start_shortstatehash + .state_full_ids(timeline_end_shortstatehash) + .ready_filter(|(_, event_id)| { + use_state_after || !event_ids_in_timeline.contains(event_id) }) .unzip() .await; @@ -94,7 +96,6 @@ pub(super) async fn build_state_incremental<'a>( services: &Services, sender_user: &'a UserId, last_sync_end_shortstatehash: ShortStateHash, - timeline_start_shortstatehash: ShortStateHash, timeline_end_shortstatehash: ShortStateHash, timeline: &TimelinePdus, use_state_after: bool, @@ -105,7 +106,6 @@ pub(super) async fn build_state_incremental<'a>( trace!( %use_state_after, %last_sync_end_shortstatehash, - %timeline_start_shortstatehash, %timeline_end_shortstatehash, "computing state for incremental sync" ); @@ -132,7 +132,7 @@ pub(super) async fn build_state_incremental<'a>( .rooms .state_accessor .state_get_shortid( - timeline_start_shortstatehash, + timeline_end_shortstatehash, &StateEventType::RoomMember, user_id.as_str(), )