Skip to content

Commit e11dd09

Browse files
committed
feat(sdk): Add Timeline::fetch_members
1 parent c294a37 commit e11dd09

File tree

4 files changed

+106
-3
lines changed

4 files changed

+106
-3
lines changed

crates/matrix-sdk/src/room/common.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ impl Common {
390390
}
391391
}
392392

393-
async fn ensure_members(&self) -> Result<()> {
393+
pub(crate) async fn ensure_members(&self) -> Result<()> {
394394
if !self.are_events_visible() {
395395
return Ok(());
396396
}

crates/matrix-sdk/src/room/timeline/event_item.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,18 @@ impl EventTimelineItem {
209209
}
210210
}
211211
}
212+
213+
/// Clone the current event item, and update its `sender_profile`.
214+
pub(super) fn with_sender_profile(&self, sender_profile: TimelineDetails<Profile>) -> Self {
215+
match self {
216+
EventTimelineItem::Local(item) => {
217+
Self::Local(LocalEventTimelineItem { sender_profile, ..item.clone() })
218+
}
219+
EventTimelineItem::Remote(item) => {
220+
Self::Remote(RemoteEventTimelineItem { sender_profile, ..item.clone() })
221+
}
222+
}
223+
}
212224
}
213225

214226
/// This type represents the "send state" of a local event timeline item.
@@ -342,7 +354,7 @@ impl fmt::Debug for RemoteEventTimelineItem {
342354
}
343355

344356
/// The display name and avatar URL of a room member.
345-
#[derive(Clone, Debug)]
357+
#[derive(Clone, Debug, PartialEq, Eq)]
346358
pub struct Profile {
347359
/// The display name, if set.
348360
pub display_name: Option<String>,
@@ -382,6 +394,17 @@ impl<T> TimelineDetails<T> {
382394
None => Self::Unavailable,
383395
}
384396
}
397+
398+
pub(crate) fn is_unavailable(&self) -> bool {
399+
matches!(self, Self::Unavailable)
400+
}
401+
402+
pub(crate) fn contains<U>(&self, value: &U) -> bool
403+
where
404+
T: PartialEq<U>,
405+
{
406+
matches!(self, Self::Ready(v) if v == value)
407+
}
385408
}
386409

387410
/// The content of an [`EventTimelineItem`].

crates/matrix-sdk/src/room/timeline/inner.rs

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ use super::{
3737
use crate::{
3838
events::SyncTimelineEventWithoutContent,
3939
room::{self, timeline::event_item::RemoteEventTimelineItem},
40-
Result,
40+
Error, Result,
4141
};
4242

4343
#[derive(Debug)]
@@ -372,6 +372,66 @@ impl<P: ProfileProvider> TimelineInner<P> {
372372
}
373373
}
374374

375+
pub(super) fn set_sender_profiles_pending(&self) {
376+
self.set_non_ready_sender_profiles(TimelineDetails::Pending);
377+
}
378+
379+
pub(super) fn set_sender_profiles_error(&self, error: Arc<Error>) {
380+
self.set_non_ready_sender_profiles(TimelineDetails::Error(error));
381+
}
382+
383+
fn set_non_ready_sender_profiles(&self, state: TimelineDetails<Profile>) {
384+
let mut timeline_items = self.items.lock_mut();
385+
for idx in 0..timeline_items.len() {
386+
let Some(event_item) = timeline_items[idx].as_event() else { continue };
387+
if !matches!(event_item.sender_profile(), TimelineDetails::Ready(_)) {
388+
timeline_items.set_cloned(
389+
idx,
390+
Arc::new(TimelineItem::Event(event_item.with_sender_profile(state.clone()))),
391+
);
392+
}
393+
}
394+
}
395+
396+
pub(super) async fn update_sender_profiles(&self) {
397+
// Can't lock the timeline items across .await points without making the
398+
// resulting future `!Send`. As a (brittle) hack around that, lock the
399+
// timeline items in each loop iteration but keep a lock of the metadata
400+
// so no event handler runs in parallel and assert the number of items
401+
// doesn't change between iterations.
402+
let _guard = self.metadata.lock().await;
403+
let num_items = self.items().len();
404+
405+
for idx in 0..num_items {
406+
let sender = match self.items()[idx].as_event() {
407+
Some(event_item) => event_item.sender().to_owned(),
408+
None => continue,
409+
};
410+
let maybe_profile = self.profile_provider.profile(&sender).await;
411+
412+
let mut timeline_items = self.items.lock_mut();
413+
assert_eq!(timeline_items.len(), num_items);
414+
415+
let event_item = timeline_items[idx].as_event().unwrap();
416+
match maybe_profile {
417+
Some(profile) => {
418+
if !event_item.sender_profile().contains(&profile) {
419+
let updated_item =
420+
event_item.with_sender_profile(TimelineDetails::Ready(profile));
421+
timeline_items.set_cloned(idx, Arc::new(TimelineItem::Event(updated_item)));
422+
}
423+
}
424+
None => {
425+
if !event_item.sender_profile().is_unavailable() {
426+
let updated_item =
427+
event_item.with_sender_profile(TimelineDetails::Unavailable);
428+
timeline_items.set_cloned(idx, Arc::new(TimelineItem::Event(updated_item)));
429+
}
430+
}
431+
}
432+
}
433+
}
434+
375435
fn update_event_item(&self, index: usize, event_item: EventTimelineItem) {
376436
self.items.lock_mut().set_cloned(index, Arc::new(TimelineItem::Event(event_item)))
377437
}

crates/matrix-sdk/src/room/timeline/mod.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,26 @@ impl Timeline {
421421

422422
Ok(())
423423
}
424+
425+
/// Fetch all member events for the room this timeline is displaying.
426+
///
427+
/// If the full member list is not known, sender profiles are currently
428+
/// likely not going to be available. This will be fixed in the future.
429+
///
430+
/// If fetching the members fails, any affected timeline items will have
431+
/// the `sender_profile` set to [`TimelineDetails::Error`].
432+
#[instrument(skip_all)]
433+
pub async fn fetch_members(&self) {
434+
self.inner.set_sender_profiles_pending();
435+
match self.room().ensure_members().await {
436+
Ok(_) => {
437+
self.inner.update_sender_profiles().await;
438+
}
439+
Err(e) => {
440+
self.inner.set_sender_profiles_error(Arc::new(e));
441+
}
442+
}
443+
}
424444
}
425445

426446
/// A single entry in timeline.

0 commit comments

Comments
 (0)