feat(sdk): Add Timeline::fetch_members

This commit is contained in:
Jonas Platte
2023-02-02 16:23:40 +01:00
committed by Jonas Platte
parent c294a376e8
commit e11dd099d8
4 changed files with 106 additions and 3 deletions

View File

@@ -390,7 +390,7 @@ impl Common {
}
}
async fn ensure_members(&self) -> Result<()> {
pub(crate) async fn ensure_members(&self) -> Result<()> {
if !self.are_events_visible() {
return Ok(());
}

View File

@@ -209,6 +209,18 @@ impl EventTimelineItem {
}
}
}
/// Clone the current event item, and update its `sender_profile`.
pub(super) fn with_sender_profile(&self, sender_profile: TimelineDetails<Profile>) -> Self {
match self {
EventTimelineItem::Local(item) => {
Self::Local(LocalEventTimelineItem { sender_profile, ..item.clone() })
}
EventTimelineItem::Remote(item) => {
Self::Remote(RemoteEventTimelineItem { sender_profile, ..item.clone() })
}
}
}
}
/// This type represents the "send state" of a local event timeline item.
@@ -342,7 +354,7 @@ impl fmt::Debug for RemoteEventTimelineItem {
}
/// The display name and avatar URL of a room member.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Profile {
/// The display name, if set.
pub display_name: Option<String>,
@@ -382,6 +394,17 @@ impl<T> TimelineDetails<T> {
None => Self::Unavailable,
}
}
pub(crate) fn is_unavailable(&self) -> bool {
matches!(self, Self::Unavailable)
}
pub(crate) fn contains<U>(&self, value: &U) -> bool
where
T: PartialEq<U>,
{
matches!(self, Self::Ready(v) if v == value)
}
}
/// The content of an [`EventTimelineItem`].

View File

@@ -37,7 +37,7 @@ use super::{
use crate::{
events::SyncTimelineEventWithoutContent,
room::{self, timeline::event_item::RemoteEventTimelineItem},
Result,
Error, Result,
};
#[derive(Debug)]
@@ -372,6 +372,66 @@ impl<P: ProfileProvider> TimelineInner<P> {
}
}
pub(super) fn set_sender_profiles_pending(&self) {
self.set_non_ready_sender_profiles(TimelineDetails::Pending);
}
pub(super) fn set_sender_profiles_error(&self, error: Arc<Error>) {
self.set_non_ready_sender_profiles(TimelineDetails::Error(error));
}
fn set_non_ready_sender_profiles(&self, state: TimelineDetails<Profile>) {
let mut timeline_items = self.items.lock_mut();
for idx in 0..timeline_items.len() {
let Some(event_item) = timeline_items[idx].as_event() else { continue };
if !matches!(event_item.sender_profile(), TimelineDetails::Ready(_)) {
timeline_items.set_cloned(
idx,
Arc::new(TimelineItem::Event(event_item.with_sender_profile(state.clone()))),
);
}
}
}
pub(super) async fn update_sender_profiles(&self) {
// Can't lock the timeline items across .await points without making the
// resulting future `!Send`. As a (brittle) hack around that, lock the
// timeline items in each loop iteration but keep a lock of the metadata
// so no event handler runs in parallel and assert the number of items
// doesn't change between iterations.
let _guard = self.metadata.lock().await;
let num_items = self.items().len();
for idx in 0..num_items {
let sender = match self.items()[idx].as_event() {
Some(event_item) => event_item.sender().to_owned(),
None => continue,
};
let maybe_profile = self.profile_provider.profile(&sender).await;
let mut timeline_items = self.items.lock_mut();
assert_eq!(timeline_items.len(), num_items);
let event_item = timeline_items[idx].as_event().unwrap();
match maybe_profile {
Some(profile) => {
if !event_item.sender_profile().contains(&profile) {
let updated_item =
event_item.with_sender_profile(TimelineDetails::Ready(profile));
timeline_items.set_cloned(idx, Arc::new(TimelineItem::Event(updated_item)));
}
}
None => {
if !event_item.sender_profile().is_unavailable() {
let updated_item =
event_item.with_sender_profile(TimelineDetails::Unavailable);
timeline_items.set_cloned(idx, Arc::new(TimelineItem::Event(updated_item)));
}
}
}
}
}
fn update_event_item(&self, index: usize, event_item: EventTimelineItem) {
self.items.lock_mut().set_cloned(index, Arc::new(TimelineItem::Event(event_item)))
}

View File

@@ -421,6 +421,26 @@ impl Timeline {
Ok(())
}
/// Fetch all member events for the room this timeline is displaying.
///
/// If the full member list is not known, sender profiles are currently
/// likely not going to be available. This will be fixed in the future.
///
/// If fetching the members fails, any affected timeline items will have
/// the `sender_profile` set to [`TimelineDetails::Error`].
#[instrument(skip_all)]
pub async fn fetch_members(&self) {
self.inner.set_sender_profiles_pending();
match self.room().ensure_members().await {
Ok(_) => {
self.inner.update_sender_profiles().await;
}
Err(e) => {
self.inner.set_sender_profiles_error(Arc::new(e));
}
}
}
}
/// A single entry in timeline.