mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-05-26 20:49:55 +00:00
refactor(sync/v3): Extract left room timeline logic into its own function
This commit is contained in:
+103
-80
@@ -15,7 +15,7 @@ use ruma::{
|
|||||||
uint,
|
uint,
|
||||||
};
|
};
|
||||||
use serde_json::value::RawValue;
|
use serde_json::value::RawValue;
|
||||||
use service::Services;
|
use service::{Services, rooms::short::ShortStateHash};
|
||||||
|
|
||||||
use crate::client::{
|
use crate::client::{
|
||||||
TimelinePdus, ignored_filter,
|
TimelinePdus, ignored_filter,
|
||||||
@@ -41,7 +41,7 @@ pub(super) async fn load_left_room(
|
|||||||
services: &Services,
|
services: &Services,
|
||||||
sync_context: SyncContext<'_>,
|
sync_context: SyncContext<'_>,
|
||||||
ref room_id: OwnedRoomId,
|
ref room_id: OwnedRoomId,
|
||||||
leave_pdu: Option<PduEvent>,
|
leave_membership_event: Option<PduEvent>,
|
||||||
) -> Result<Option<LeftRoom>> {
|
) -> Result<Option<LeftRoom>> {
|
||||||
let SyncContext {
|
let SyncContext {
|
||||||
syncing_user,
|
syncing_user,
|
||||||
@@ -77,9 +77,9 @@ pub(super) async fn load_left_room(
|
|||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref leave_pdu) = leave_pdu {
|
if let Some(ref leave_membership_event) = leave_membership_event {
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
leave_pdu.kind,
|
leave_membership_event.kind,
|
||||||
TimelineEventType::RoomMember,
|
TimelineEventType::RoomMember,
|
||||||
"leave PDU should be m.room.member"
|
"leave PDU should be m.room.member"
|
||||||
);
|
);
|
||||||
@@ -87,36 +87,37 @@ pub(super) async fn load_left_room(
|
|||||||
|
|
||||||
let does_not_exist = services.rooms.metadata.exists(room_id).eq(&false).await;
|
let does_not_exist = services.rooms.metadata.exists(room_id).eq(&false).await;
|
||||||
|
|
||||||
let (timeline, state_events) = match leave_pdu {
|
let (timeline, state_events) = match leave_membership_event {
|
||||||
| Some(leave_pdu) if does_not_exist => {
|
| Some(leave_membership_event) if does_not_exist => {
|
||||||
/*
|
/*
|
||||||
we have none PDUs with left beef for this room, likely because it was a rejected invite to a room
|
we have none PDUs with left beef for this room, likely because it was a rejected invite to a room
|
||||||
which nobody on this homeserver is in. `leave_pdu` is the remote-assisted outlier leave event for the room,
|
which nobody on this homeserver is in. `leave_pdu` is the remote-assisted outlier leave event for the room,
|
||||||
which is all we can send to the client.
|
which is all we can send to the client.
|
||||||
*/
|
*/
|
||||||
trace!("syncing remote-assisted leave PDU");
|
trace!("syncing remote-assisted leave PDU");
|
||||||
(TimelinePdus::default(), vec![leave_pdu])
|
(TimelinePdus::default(), vec![leave_membership_event])
|
||||||
},
|
},
|
||||||
| Some(leave_pdu) => {
|
| Some(leave_membership_event) => {
|
||||||
// we have this room in our DB, and can fetch the state and timeline from when
|
// we have this room in our DB, and can fetch the state and timeline from when
|
||||||
// the user left if they're allowed to see it.
|
// the user left if they're allowed to see it.
|
||||||
|
|
||||||
let leave_state_key = syncing_user;
|
let leave_state_key = syncing_user;
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
Some(leave_state_key.as_str()),
|
Some(leave_state_key.as_str()),
|
||||||
leave_pdu.state_key(),
|
leave_membership_event.state_key(),
|
||||||
"leave PDU should be for the user requesting the sync"
|
"leave PDU should be for the user requesting the sync"
|
||||||
);
|
);
|
||||||
|
|
||||||
// the shortstatehash of the state _immediately before_ the syncing user left
|
// the shortstatehash of the state _immediately before_ the syncing user left
|
||||||
// this room. the state represented here _does not_ include `leave_pdu`.
|
// this room. the state represented here _does not_ include
|
||||||
|
// `leave_membership_event`.
|
||||||
let leave_shortstatehash = services
|
let leave_shortstatehash = services
|
||||||
.rooms
|
.rooms
|
||||||
.state_accessor
|
.state_accessor
|
||||||
.pdu_shortstatehash(&leave_pdu.event_id)
|
.pdu_shortstatehash(&leave_membership_event.event_id)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let prev_member_event = services
|
let prev_membership_event = services
|
||||||
.rooms
|
.rooms
|
||||||
.state_accessor
|
.state_accessor
|
||||||
.state_get(
|
.state_get(
|
||||||
@@ -125,20 +126,100 @@ pub(super) async fn load_left_room(
|
|||||||
leave_state_key.as_str(),
|
leave_state_key.as_str(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
let current_membership: RoomMemberEventContent = leave_pdu.get_content()?;
|
let current_membership: RoomMemberEventContent =
|
||||||
let prev_membership: RoomMemberEventContent = prev_member_event.get_content()?;
|
leave_membership_event.get_content()?;
|
||||||
|
let prev_membership: RoomMemberEventContent = prev_membership_event.get_content()?;
|
||||||
|
|
||||||
match current_membership.membership_change(
|
match current_membership.membership_change(
|
||||||
Some(prev_membership.details()),
|
Some(prev_membership.details()),
|
||||||
&leave_pdu.sender,
|
&leave_membership_event.sender,
|
||||||
leave_state_key,
|
leave_state_key,
|
||||||
) {
|
) {
|
||||||
| MembershipChange::Left => {
|
| MembershipChange::Left => {
|
||||||
// if the user went from `join` to `leave`, they should be able to view the
|
// if the user went from `join` to `leave`, they should be able to view the
|
||||||
// timeline.
|
// timeline.
|
||||||
|
|
||||||
let timeline_start_count =
|
build_left_state_and_timeline(
|
||||||
if let Some(last_sync_end_count) = last_sync_end_count {
|
services,
|
||||||
|
sync_context,
|
||||||
|
room_id,
|
||||||
|
leave_membership_event,
|
||||||
|
leave_shortstatehash,
|
||||||
|
prev_membership_event,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
},
|
||||||
|
| other_membership => {
|
||||||
|
// otherwise, the user should not be able to view the timeline.
|
||||||
|
// only return their leave event.
|
||||||
|
trace!(
|
||||||
|
?other_membership,
|
||||||
|
"user did not leave happily, only syncing leave event"
|
||||||
|
);
|
||||||
|
(TimelinePdus::default(), vec![leave_membership_event])
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
| None => {
|
||||||
|
/*
|
||||||
|
no leave event was actually sent in this room, but we still need to pretend
|
||||||
|
like the user left it. this is usually because the room was banned by a server admin.
|
||||||
|
if this is an incremental sync, generate a fake leave event to make the room vanish from clients.
|
||||||
|
otherwise we don't tell the client about this room at all.
|
||||||
|
*/
|
||||||
|
if last_sync_end_count.is_none() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
trace!("syncing dummy leave event");
|
||||||
|
(TimelinePdus::default(), vec![create_dummy_leave_event(
|
||||||
|
services,
|
||||||
|
sync_context,
|
||||||
|
room_id,
|
||||||
|
)])
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let raw_timeline_pdus = timeline
|
||||||
|
.pdus
|
||||||
|
.into_iter()
|
||||||
|
.stream()
|
||||||
|
// filter out ignored events from the timeline
|
||||||
|
.wide_filter_map(|item| ignored_filter(services, item, syncing_user))
|
||||||
|
.map(at!(1))
|
||||||
|
.map(Event::into_format)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
Ok(Some(LeftRoom {
|
||||||
|
account_data: RoomAccountData { events: Vec::new() },
|
||||||
|
timeline: Timeline {
|
||||||
|
limited: timeline.limited,
|
||||||
|
prev_batch: Some(current_count.to_string()),
|
||||||
|
events: raw_timeline_pdus,
|
||||||
|
},
|
||||||
|
state: State {
|
||||||
|
events: state_events.into_iter().map(Event::into_format).collect(),
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn build_left_state_and_timeline(
|
||||||
|
services: &Services,
|
||||||
|
sync_context: SyncContext<'_>,
|
||||||
|
room_id: &RoomId,
|
||||||
|
leave_membership_event: PduEvent,
|
||||||
|
leave_shortstatehash: ShortStateHash,
|
||||||
|
prev_membership_event: PduEvent,
|
||||||
|
) -> Result<(TimelinePdus, Vec<PduEvent>)> {
|
||||||
|
let SyncContext {
|
||||||
|
syncing_user,
|
||||||
|
last_sync_end_count,
|
||||||
|
filter,
|
||||||
|
..
|
||||||
|
} = sync_context;
|
||||||
|
|
||||||
|
let timeline_start_count = if let Some(last_sync_end_count) = last_sync_end_count {
|
||||||
// for incremental syncs, start the timeline after `since`
|
// for incremental syncs, start the timeline after `since`
|
||||||
PduCount::Normal(last_sync_end_count)
|
PduCount::Normal(last_sync_end_count)
|
||||||
} else {
|
} else {
|
||||||
@@ -149,7 +230,7 @@ pub(super) async fn load_left_room(
|
|||||||
services
|
services
|
||||||
.rooms
|
.rooms
|
||||||
.timeline
|
.timeline
|
||||||
.get_pdu_count(&prev_member_event.event_id)
|
.get_pdu_count(&prev_membership_event.event_id)
|
||||||
.await?
|
.await?
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -157,7 +238,7 @@ pub(super) async fn load_left_room(
|
|||||||
let timeline_end_count = services
|
let timeline_end_count = services
|
||||||
.rooms
|
.rooms
|
||||||
.timeline
|
.timeline
|
||||||
.get_pdu_count(leave_pdu.event_id())
|
.get_pdu_count(leave_membership_event.event_id())
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// limit the timeline using the same logic as for joined rooms
|
// limit the timeline using the same logic as for joined rooms
|
||||||
@@ -196,12 +277,8 @@ pub(super) async fn load_left_room(
|
|||||||
leave_shortstatehash
|
leave_shortstatehash
|
||||||
};
|
};
|
||||||
|
|
||||||
let lazily_loaded_members = prepare_lazily_loaded_members(
|
let lazily_loaded_members =
|
||||||
services,
|
prepare_lazily_loaded_members(services, sync_context, room_id, timeline.senders());
|
||||||
sync_context,
|
|
||||||
room_id,
|
|
||||||
timeline.senders(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let (timeline_start_shortstatehash, lazily_loaded_members) =
|
let (timeline_start_shortstatehash, lazily_loaded_members) =
|
||||||
join(timeline_start_shortstatehash, lazily_loaded_members).await;
|
join(timeline_start_shortstatehash, lazily_loaded_members).await;
|
||||||
@@ -255,61 +332,7 @@ pub(super) async fn load_left_room(
|
|||||||
state.len()
|
state.len()
|
||||||
);
|
);
|
||||||
|
|
||||||
(timeline, state)
|
Ok((timeline, state))
|
||||||
},
|
|
||||||
| other_membership => {
|
|
||||||
// otherwise, the user should not be able to view the timeline.
|
|
||||||
// only return their leave event.
|
|
||||||
trace!(
|
|
||||||
?other_membership,
|
|
||||||
"user did not leave happily, only syncing leave event"
|
|
||||||
);
|
|
||||||
(TimelinePdus::default(), vec![leave_pdu])
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
| None => {
|
|
||||||
/*
|
|
||||||
no leave event was actually sent in this room, but we still need to pretend
|
|
||||||
like the user left it. this is usually because the room was banned by a server admin.
|
|
||||||
if this is an incremental sync, generate a fake leave event to make the room vanish from clients.
|
|
||||||
otherwise we don't tell the client about this room at all.
|
|
||||||
*/
|
|
||||||
if last_sync_end_count.is_none() {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
trace!("syncing dummy leave event");
|
|
||||||
(TimelinePdus::default(), vec![create_dummy_leave_event(
|
|
||||||
services,
|
|
||||||
sync_context,
|
|
||||||
room_id,
|
|
||||||
)])
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let raw_timeline_pdus = timeline
|
|
||||||
.pdus
|
|
||||||
.into_iter()
|
|
||||||
.stream()
|
|
||||||
// filter out ignored events from the timeline
|
|
||||||
.wide_filter_map(|item| ignored_filter(services, item, syncing_user))
|
|
||||||
.map(at!(1))
|
|
||||||
.map(Event::into_format)
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.await;
|
|
||||||
|
|
||||||
Ok(Some(LeftRoom {
|
|
||||||
account_data: RoomAccountData { events: Vec::new() },
|
|
||||||
timeline: Timeline {
|
|
||||||
limited: timeline.limited,
|
|
||||||
prev_batch: Some(current_count.to_string()),
|
|
||||||
events: raw_timeline_pdus,
|
|
||||||
},
|
|
||||||
state: State {
|
|
||||||
events: state_events.into_iter().map(Event::into_format).collect(),
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_dummy_leave_event(
|
fn create_dummy_leave_event(
|
||||||
|
|||||||
Reference in New Issue
Block a user