Commit 60454002af5f
tarball7 files changed+71-51
@@ -151,10 +151,12 @@ the latest reply's preview, and a preview's own reply target comes back
151151
152152
a lagged listener can't know what it missed, so the list fetches its first page153153
again and sends a `ThreadListReset` with it. leaving the room, or being kicked154
-or banned, closes the list with `ThreadListClosed` naming why, the same as155
-`Close` does. a list's media belongs to its own scope, bounded like an event156
-context's so a long open list sheds the previews its threads moved past, and157
-released on close154
+or banned, closes the list with `ThreadListClosed` and `RoomLeft`, the shape an155
+event context closing on a leave has. `Close` sends one too, with `Requested`,156
+since a mirror holds the list and has to drop it. a list's media belongs to its157
+own scope and its ids carry it, like an event context's, bounded the same way so158
+a long open list sheds the previews its threads moved past, and released on159
+close158160
159161
## warming up to send160162
@@ -21,8 +21,8 @@ use super::{
2121
executor::{AbortHandle, TaskSet, is_panic, resume_unwind},2222
};2323
use crate::{24
- Error, ErrorKind, Event, HistoryState, ThreadListClosure, ThreadListCommand, ThreadListEntry,25
- ThreadSummary, TimelineItem,24
+ Error, ErrorKind, Event, HistoryState, ThreadListCloseReason, ThreadListCommand,25
+ ThreadListEntry, ThreadSummary, TimelineItem,2626
normalise::{2727
MediaRegistration, MediaScope, member_sender, normalise_observed, resolve_replies,2828
},@@ -67,7 +67,7 @@ enum Arrival {
6767
Left {6868
room_id: OwnedRoomId,6969
generation: u64,70
- reason: ThreadListClosure,70
+ reason: ThreadListCloseReason,7171
},7272
}7373
@@ -111,6 +111,7 @@ struct List {
111111
room: Room,112112
generation: u64,113113
scope: MediaScope,114
+ media_prefix: String,114115
entries: Vector<ThreadListEntry>,115116
token: Option<String>,116117
end_reached: bool,@@ -184,7 +185,7 @@ impl ThreadLists {
184185
return reply.done(Err(not_open()));185186
};186187
let closed = self187
- .finish(room_id, list, ThreadListClosure::Requested)188
+ .finish(room_id, list, ThreadListCloseReason::Requested)188189
.await;189190
reply.done(closed);190191
}@@ -204,10 +205,13 @@ impl ThreadLists {
204205
};205206
self.next_generation = self.next_generation.wrapping_add(1);206207
let generation = self.next_generation;208
+ let scope = self.media.context_scope();209
+ let media_prefix = format!("{}#", scope.nonce());207210
let listener = self.tasks.spawn(listen(208211
room.clone(),209212
generation,210213
self.current_user_id.clone(),214
+ media_prefix.clone(),211215
self.arrivals.clone(),212216
));213217
self.lists.insert(@@ -215,7 +219,8 @@ impl ThreadLists {
215219
List {216220
room,217221
generation,218
- scope: self.media.context_scope(),222
+ scope,223
+ media_prefix,219224
entries: Vector::new(),220225
token: None,221226
end_reached: false,@@ -268,6 +273,7 @@ impl ThreadLists {
268273
if refresh { None } else { list.token.clone() },269274
list.page_limit,270275
self.current_user_id.clone(),276
+ list.media_prefix.clone(),271277
);272278
let generation = list.generation;273279
let arrivals = self.arrivals.clone();@@ -293,7 +299,7 @@ impl ThreadLists {
293299
&mut self,294300
room_id: OwnedRoomId,295301
list: List,296
- reason: ThreadListClosure,302
+ reason: ThreadListCloseReason,297303
) -> Result<(), Error> {298304
list.listener.abort();299305
if let Load::Page(waiting) | Load::Refresh(waiting) = list.load {@@ -486,9 +492,11 @@ impl ThreadLists {
486492
let room = list.room.clone();487493
let generation = list.generation;488494
let current_user_id = self.current_user_id.clone();495
+ let media_prefix = list.media_prefix.clone();489496
let arrivals = self.arrivals.clone();490497
self.tasks.spawn(async move {491
- let fetched = fetch_root(&room, &root_event_id, current_user_id).await;498
+ let fetched =499
+ fetch_root(&room, &root_event_id, current_user_id, &media_prefix).await;492500
let _ = arrivals.send(Arrival::Root {493501
room_id: room.room_id().to_owned(),494502
generation,@@ -677,6 +685,7 @@ async fn fetch_page(
677685
from: Option<String>,678686
limit: u16,679687
current_user_id: Option<OwnedUserId>,688
+ media_prefix: String,680689
) -> Result<Page, Error> {681690
let roots = room682691
.list_threads(ListThreadsOptions {@@ -688,7 +697,9 @@ async fn fetch_page(
688697
.map_err(|source| Error::from_sdk("listing threads failed", source))?;689698
let mut entries = Vec::with_capacity(roots.chunk.len());690699
for root in roots.chunk {691
- if let Some(built) = build_entry(&room, root, current_user_id.as_deref()).await {700
+ if let Some(built) =701
+ build_entry(&room, root, current_user_id.as_deref(), &media_prefix).await702
+ {692703
entries.push(built);693704
}694705
}@@ -702,6 +713,7 @@ async fn fetch_root(
702713
room: &Room,703714
root_event_id: &OwnedEventId,704715
current_user_id: Option<OwnedUserId>,716
+ media_prefix: &str,705717
) -> Fetched {706718
let root = match room.load_or_fetch_event(root_event_id, None).await {707719
Ok(root) => root,@@ -719,7 +731,7 @@ async fn fetch_root(
719731
};720732
}721733
};722
- match build_entry(room, root, current_user_id.as_deref()).await {734
+ match build_entry(room, root, current_user_id.as_deref(), media_prefix).await {723735
Some(built) => Fetched::Built(built),724736
None => Fetched::Missing,725737
}@@ -729,12 +741,13 @@ async fn build_entry(
729741
room: &Room,730742
root: SdkTimelineEvent,731743
current_user_id: Option<&ruma::UserId>,744
+ media_prefix: &str,732745
) -> Option<Built> {733746
let summary = root.thread_summary.summary().cloned();734747
let latest = root.bundled_latest_thread_event.clone();735
- let root = normalise(room, &root, current_user_id).await?;748
+ let root = normalise(room, &root, current_user_id, media_prefix).await?;736749
let latest = match latest {737
- Some(latest) => normalise(room, &latest, current_user_id).await,750
+ Some(latest) => normalise(room, &latest, current_user_id, media_prefix).await,738751
None => None,739752
};740753
let summary = ThreadSummary {@@ -769,11 +782,12 @@ async fn normalise(
769782
room: &Room,770783
event: &SdkTimelineEvent,771784
current_user_id: Option<&ruma::UserId>,785
+ media_prefix: &str,772786
) -> Option<Normalised> {773787
let event_id = event.event_id()?;774788
let timestamp_ms = u64::from(event.timestamp()?.get());775789
let value: serde_json::Value = serde_json::from_str(event.raw().json().get()).ok()?;776
- let identity = format!("{}\n{event_id}", room.room_id());790
+ let identity = format!("{media_prefix}{}\n{event_id}", room.room_id());777791
let (mut item, media) = normalise_observed(&value, current_user_id, &identity)?;778792
let TimelineItem::Event(normalised) = &mut item else {779793
return None;@@ -795,10 +809,9 @@ async fn normalise(
795809
})796810
}797811
798
-fn closure(state: RoomState) -> Option<ThreadListClosure> {812
+fn closure(state: RoomState) -> Option<ThreadListCloseReason> {799813
match state {800
- RoomState::Left => Some(ThreadListClosure::Left),801
- RoomState::Banned => Some(ThreadListClosure::Banned),814
+ RoomState::Left | RoomState::Banned => Some(ThreadListCloseReason::RoomLeft),802815
_ => None,803816
}804817
}@@ -808,6 +821,7 @@ async fn listen(
808821
room: Room,809822
generation: u64,810823
current_user_id: Option<OwnedUserId>,824
+ media_prefix: String,811825
arrivals: mpsc::UnboundedSender<Arrival>,812826
) {813827
let room_id = room.room_id().to_owned();@@ -869,7 +883,8 @@ async fn listen(
869883
if thread_root.is_none() && event.thread_summary.summary().is_none() {870884
continue;871885
}872
- let Some(normalised) = normalise(&room, &event, current_user_id.as_deref()).await886
+ let Some(normalised) =887
+ normalise(&room, &event, current_user_id.as_deref(), &media_prefix).await873888
else {874889
continue;875890
};@@ -8,9 +8,9 @@ use futures_util::StreamExt;
88
use matrix_sdk::{99
Client, Room,1010
event_handler::EventHandlerHandle,11
- serde_helpers::extract_thread_root,1211
ruma::events::{AnyMessageLikeEventContent, room::message::MessageType},1312
send_queue::{LocalEchoContent, RoomSendQueueUpdate, SendQueueUpdate},13
+ serde_helpers::extract_thread_root,1414
};1515
use matrix_sdk_base::RoomInfoNotableUpdateReasons;1616
use matrix_sdk_ui::sync_service::{State as SyncState, SyncService};@@ -57,23 +57,22 @@ pub use mirror::{
5757
pub use model::{5858
AccountCommand, AttachmentEncryption, AttachmentUpload, Change, Command, CommandOutput,5959
ConnectionState, CreateRoomOptions, EncryptionCommand, EncryptionState, EngineErrorKind,60
- EngineFailure, Event, EventContext, EventContextCloseReason, EventContextCommand, EventContextPage, EventContextSession,61
- EventRef, HistoryState, ImagePack, ImagePackSource, ImagePacks, KeyBackupState, LatestEvent,62
- LifecycleCommand, LinkPreview, LinkPreviewImage, Media, MediaCommand, MediaDescriptor,63
- MediaFile, MediaId, MediaKind, MediaLocation, MediaSize, MemberFilter, MemberMembership,64
- MemberSummary, MembershipChange, Message, MessageContent, MessageEditContent, MessageKind,65
- MessageMentions, NotificationCommand, OwnDevice, PackCommand, PackImage, PackImageInfo,66
- PackUsage, Patch, PowerLevelChanges, Profile, PushNotification, PushNotificationEvent,67
- PushNotificationRoom, PushNotificationSender, PushNotificationStatus, Reaction,68
- RecentHistoryState, RecoveryState, ReplyDetails, ReplyReference, Retain, RichText,60
+ EngineFailure, Event, EventContext, EventContextCloseReason, EventContextCommand,61
+ EventContextPage, EventContextSession, EventRef, HistoryState, ImagePack, ImagePackSource,62
+ ImagePacks, KeyBackupState, LatestEvent, LifecycleCommand, LinkPreview, LinkPreviewImage,63
+ Media, MediaCommand, MediaDescriptor, MediaFile, MediaId, MediaKind, MediaLocation, MediaSize,64
+ MemberFilter, MemberMembership, MemberSummary, MembershipChange, Message, MessageContent,65
+ MessageEditContent, MessageKind, MessageMentions, NotificationCommand, OwnDevice, PackCommand,66
+ PackImage, PackImageInfo, PackUsage, Patch, PowerLevelChanges, Profile, PushNotification,67
+ PushNotificationEvent, PushNotificationRoom, PushNotificationSender, PushNotificationStatus,68
+ Reaction, RecentHistoryState, RecoveryState, ReplyDetails, ReplyReference, Retain, RichText,6969
RoomCategory, RoomCommand, RoomHero, RoomListFilter, RoomMatcher, RoomMembership,7070
RoomNotificationMode, RoomNotificationSettings, RoomPowerLevels, RoomPreset, RoomSummary,71
- RoomVisibility, SendState, Sender, SpaceChild, Termination, ThreadListClosure,72
- ThreadListCommand, ThreadListEntry,73
- ThreadSummary, ThreadUnread, TimelineCommand, TimelineContent, TimelineDiff, TimelineDiffError,74
- TimelineEvent, TimelineId, TimelineItem, TimelineItemId, TypingState, UploadDetails,75
- UploadOutcome, UploadThumbnail, UtdCause, VerificationAction, VerificationFailure,76
- VerificationState, VerificationTarget,71
+ RoomVisibility, SendState, Sender, SpaceChild, Termination, ThreadListCloseReason,72
+ ThreadListCommand, ThreadListEntry, ThreadSummary, ThreadUnread, TimelineCommand,73
+ TimelineContent, TimelineDiff, TimelineDiffError, TimelineEvent, TimelineId, TimelineItem,74
+ TimelineItemId, TypingState, UploadDetails, UploadOutcome, UploadThumbnail, UtdCause,75
+ VerificationAction, VerificationFailure, VerificationState, VerificationTarget,7776
};7877
pub use repair_model::{7978
HistoryContinuity, HistoryGap, HistoryGapLifecycle, HistoryRepairCommand, HistoryRepairPhase,@@ -21,10 +21,9 @@ use tokio::sync::broadcast;
2121
use crate::{2222
ClientHandle, Command, ConnectionState, EncryptionState, EngineFailure, ErrorKind, Event,2323
EventContextCloseReason, HistoryRepairReport, HistoryState, ImagePacks, RecentHistoryState,24
- RoomSummary, ThreadListClosure, ThreadListEntry, TimelineCommand, TimelineDiff, TimelineId,25
- TimelineItem, TypingState,26
- UploadOutcome, VerificationState, VerificationTarget, engine::executor::EngineBoxFuture,27
- transport::PublicationRegistration,24
+ RoomSummary, ThreadListCloseReason, ThreadListEntry, TimelineCommand, TimelineDiff, TimelineId,25
+ TimelineItem, TypingState, UploadOutcome, VerificationState, VerificationTarget,26
+ engine::executor::EngineBoxFuture, transport::PublicationRegistration,2827
};2928
3029
#[cfg(not(target_family = "wasm"))]@@ -201,7 +200,7 @@ pub enum ThreadListChange {
201200
entries: Vector<ThreadListEntry>,202201
},203202
History(HistoryState),204
- Closed(ThreadListClosure),203
+ Closed(ThreadListCloseReason),205204
}206205
207206
/// drains the event stream into a `State` that any number of `MirrorHandle`s watch@@ -982,7 +982,7 @@ pub enum Event {
982982
/// nothing more comes for it until another `ThreadListReset`983983
ThreadListClosed {984984
room_id: OwnedRoomId,985
- reason: ThreadListClosure,985
+ reason: ThreadListCloseReason,986986
},987987
/// a room that stops being watched says so with an empty `users`988988
TypingChanged(TypingState),@@ -1917,12 +1917,11 @@ pub struct ThreadSummary {
19171917
19181918
#[derive(Clone, Copy, Debug, Eq, PartialEq)]19191919
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]1920
-pub enum ThreadListClosure {1920
+pub enum ThreadListCloseReason {19211921
/// `Close` asked for it19221922
Requested,1923
- /// left or kicked1924
- Left,1925
- Banned,1923
+ /// left, kicked or banned1924
+ RoomLeft,19261925
}19271926
19281927
#[derive(Clone, Debug, Eq, PartialEq)]@@ -25,7 +25,12 @@ pub(crate) async fn stored_thread_unreads(room: &Room) -> BTreeMap<OwnedEventId,
2525
if room.state() != RoomState::Joined {2626
return BTreeMap::new();2727
}28
- match room.client().state_store().get_custom_value(&key(room)).await {28
+ match room29
+ .client()30
+ .state_store()31
+ .get_custom_value(&key(room))32
+ .await33
+ {2934
Ok(Some(bytes)) => decode(&bytes),3035
Ok(None) => BTreeMap::new(),3136
Err(error) => {@@ -51,9 +56,9 @@ pub(crate) async fn recount_thread_unreads(
5156
return None;5257
}5358
let store = match room.client().event_cache_store().lock().await {54
- Ok(MappedCrossProcessLockState::Clean(store) | MappedCrossProcessLockState::Dirty(store)) => {55
- store56
- }59
+ Ok(60
+ MappedCrossProcessLockState::Clean(store) | MappedCrossProcessLockState::Dirty(store),61
+ ) => store,5762
Err(error) => {5863
tracing::debug!(room_id = %room.room_id(), %error, "locking the event cache store failed");5964
return None;@@ -76,7 +81,8 @@ pub(crate) async fn recount_thread_unreads(
7681
continue;7782
}7883
};79
- let mut read = unthreaded.max(read_through(room, &store, ReceiptThread::Thread(root.clone())).await);84
+ let mut read =85
+ unthreaded.max(read_through(room, &store, ReceiptThread::Thread(root.clone())).await);8086
for (reply, _) in &replies {8187
if reply.sender().as_deref() == Some(own_user_id) {8288
read = read.max(timestamp_ms(reply));