diff --git a/Cargo.lock b/Cargo.lock index e5d321023fa..a65a9edadc7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3526,7 +3526,6 @@ dependencies = [ "async-once-cell", "async-rx", "async-stream", - "async-trait", "async_cell", "chrono", "eyeball", diff --git a/crates/matrix-sdk-ui/Cargo.toml b/crates/matrix-sdk-ui/Cargo.toml index a73328061d4..9edaddb9622 100644 --- a/crates/matrix-sdk-ui/Cargo.toml +++ b/crates/matrix-sdk-ui/Cargo.toml @@ -26,7 +26,6 @@ async_cell = "0.2.2" async-once-cell = "0.5.2" async-rx = { workspace = true } async-stream = { workspace = true } -async-trait = { workspace = true } chrono = "0.4.23" eyeball = { workspace = true } eyeball-im = { workspace = true } diff --git a/crates/matrix-sdk-ui/src/room_list_service/state.rs b/crates/matrix-sdk-ui/src/room_list_service/state.rs index d401c249a95..edf189cbb64 100644 --- a/crates/matrix-sdk-ui/src/room_list_service/state.rs +++ b/crates/matrix-sdk-ui/src/room_list_service/state.rs @@ -16,9 +16,7 @@ use std::future::ready; -use async_trait::async_trait; use matrix_sdk::{sliding_sync::Range, SlidingSync, SlidingSyncMode}; -use once_cell::sync::Lazy; use super::Error; @@ -54,11 +52,16 @@ impl State { pub(super) async fn next(&self, sliding_sync: &SlidingSync) -> Result { use State::*; - let (next_state, actions) = match self { - Init => (SettingUp, Actions::none()), - SettingUp => (Running, Actions::prepare_for_next_syncs_once_first_rooms_are_loaded()), - Recovering => (Running, Actions::prepare_for_next_syncs_once_recovered()), - Running => (Running, Actions::none()), + let next_state = match self { + Init => SettingUp, + + SettingUp | Recovering => { + set_all_rooms_to_growing_sync_mode(sliding_sync).await?; + Running + } + + Running => Running, + Error { from: previous_state } | Terminated { from: previous_state } => { match previous_state.as_ref() { // Unreachable state. @@ -69,131 +72,53 @@ impl State { } // If the previous state was `Running`, we enter the `Recovering` state. - Running => (Recovering, Actions::prepare_to_recover()), + Running => { + set_all_rooms_to_selective_sync_mode(sliding_sync).await?; + Recovering + } // Jump back to the previous state that led to this termination. - state => (state.to_owned(), Actions::none()), + state => state.to_owned(), } } }; - for action in actions.iter() { - action.run(sliding_sync).await?; - } - Ok(next_state) } } -/// A trait to define what an `Action` is. -#[async_trait] -trait Action { - async fn run(&self, sliding_sync: &SlidingSync) -> Result<(), Error>; +async fn set_all_rooms_to_growing_sync_mode(sliding_sync: &SlidingSync) -> Result<(), Error> { + sliding_sync + .on_list(ALL_ROOMS_LIST_NAME, |list| { + list.set_sync_mode(SlidingSyncMode::new_growing(ALL_ROOMS_DEFAULT_GROWING_BATCH_SIZE)); + + ready(()) + }) + .await + .ok_or_else(|| Error::UnknownList(ALL_ROOMS_LIST_NAME.to_owned())) } -struct SetAllRoomsToSelectiveSyncMode; +async fn set_all_rooms_to_selective_sync_mode(sliding_sync: &SlidingSync) -> Result<(), Error> { + sliding_sync + .on_list(ALL_ROOMS_LIST_NAME, |list| { + list.set_sync_mode( + SlidingSyncMode::new_selective().add_range(ALL_ROOMS_DEFAULT_SELECTIVE_RANGE), + ); + + ready(()) + }) + .await + .ok_or_else(|| Error::UnknownList(ALL_ROOMS_LIST_NAME.to_owned())) +} /// Default `batch_size` for the selective sync-mode of the /// `ALL_ROOMS_LIST_NAME` list. pub const ALL_ROOMS_DEFAULT_SELECTIVE_RANGE: Range = 0..=19; -#[async_trait] -impl Action for SetAllRoomsToSelectiveSyncMode { - async fn run(&self, sliding_sync: &SlidingSync) -> Result<(), Error> { - sliding_sync - .on_list(ALL_ROOMS_LIST_NAME, |list| { - list.set_sync_mode( - SlidingSyncMode::new_selective().add_range(ALL_ROOMS_DEFAULT_SELECTIVE_RANGE), - ); - - ready(()) - }) - .await - .ok_or_else(|| Error::UnknownList(ALL_ROOMS_LIST_NAME.to_owned()))?; - - Ok(()) - } -} - -struct SetAllRoomsToGrowingSyncMode; - /// Default `batch_size` for the growing sync-mode of the `ALL_ROOMS_LIST_NAME` /// list. pub const ALL_ROOMS_DEFAULT_GROWING_BATCH_SIZE: u32 = 100; -#[async_trait] -impl Action for SetAllRoomsToGrowingSyncMode { - async fn run(&self, sliding_sync: &SlidingSync) -> Result<(), Error> { - sliding_sync - .on_list(ALL_ROOMS_LIST_NAME, |list| { - list.set_sync_mode(SlidingSyncMode::new_growing( - ALL_ROOMS_DEFAULT_GROWING_BATCH_SIZE, - )); - - ready(()) - }) - .await - .ok_or_else(|| Error::UnknownList(ALL_ROOMS_LIST_NAME.to_owned()))?; - - Ok(()) - } -} - -/// Type alias to represent one action. -type OneAction = Box; - -/// Type alias to represent many actions. -type ManyActions = Vec; - -/// A type to represent multiple actions. -/// -/// It contains helper methods to create pre-configured set of actions. -struct Actions { - actions: &'static Lazy, -} - -macro_rules! actions { - ( - $( - $action_group_name:ident => [ - $( $action_name:ident ),* $(,)? - ] - ),* - $(,)? - ) => { - $( - fn $action_group_name () -> Self { - static ACTIONS: Lazy = Lazy::new(|| { - vec![ - $( Box::new( $action_name ) ),* - ] - }); - - Self { actions: &ACTIONS } - } - )* - }; -} - -impl Actions { - actions! { - none => [], - prepare_for_next_syncs_once_first_rooms_are_loaded => [ - SetAllRoomsToGrowingSyncMode, - ], - prepare_for_next_syncs_once_recovered => [ - SetAllRoomsToGrowingSyncMode, - ], - prepare_to_recover => [ - SetAllRoomsToSelectiveSyncMode, - ], - } - - fn iter(&self) -> &[OneAction] { - self.actions.as_slice() - } -} - #[cfg(test)] mod tests { use matrix_sdk_test::async_test; @@ -316,7 +241,7 @@ mod tests { ); // Run the action! - SetAllRoomsToGrowingSyncMode.run(sliding_sync).await.unwrap(); + set_all_rooms_to_growing_sync_mode(sliding_sync).await.unwrap(); // List is still present, in Growing mode. assert_eq!( @@ -332,7 +257,7 @@ mod tests { ); // Run the other action! - SetAllRoomsToSelectiveSyncMode.run(sliding_sync).await.unwrap(); + set_all_rooms_to_selective_sync_mode(sliding_sync).await.unwrap(); // List is still present, in Selective mode. assert_eq!( diff --git a/crates/matrix-sdk-ui/src/timeline/event_handler.rs b/crates/matrix-sdk-ui/src/timeline/event_handler.rs index e93b6304632..0528854b30b 100644 --- a/crates/matrix-sdk-ui/src/timeline/event_handler.rs +++ b/crates/matrix-sdk-ui/src/timeline/event_handler.rs @@ -14,7 +14,6 @@ use std::sync::Arc; -use as_variant::as_variant; use eyeball_im::{ObservableVectorTransaction, ObservableVectorTransactionEntry}; use indexmap::IndexMap; use matrix_sdk::{ @@ -43,8 +42,7 @@ use ruma::{ }, html::RemoveReplyFallback, serde::Raw, - EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedTransactionId, OwnedUserId, - RoomVersionId, + MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedTransactionId, OwnedUserId, RoomVersionId, }; use tracing::{debug, error, field::debug, info, instrument, trace, warn}; @@ -73,7 +71,6 @@ use crate::{ }; /// When adding an event, useful information related to the source of the event. -#[derive(Clone)] pub(super) enum Flow { /// The event was locally created. Local { @@ -103,7 +100,6 @@ pub(super) enum Flow { }, } -#[derive(Clone)] pub(super) struct TimelineEventContext { pub(super) sender: OwnedUserId, pub(super) sender_profile: Option, @@ -506,61 +502,57 @@ impl<'a, 'o> TimelineEventHandler<'a, 'o> { &mut self, replacement: Replacement, ) { - let found = self.update_timeline_item(&replacement.event_id, |this, event_item| { - if this.ctx.sender != event_item.sender() { - info!( - original_sender = ?event_item.sender(), edit_sender = ?this.ctx.sender, - "Edit event applies to another user's timeline item, discarding" - ); - return None; - } - - let TimelineItemContent::Message(msg) = event_item.content() else { - info!( - "Edit of message event applies to {:?}, discarding", - event_item.content().debug_string(), - ); - return None; - }; + let Some((item_pos, item)) = rfind_event_by_id(self.items, &replacement.event_id) else { + debug!("Timeline item not found, discarding edit"); + return; + }; - let mut msgtype = replacement.new_content.msgtype; - // Edit's content is never supposed to contain the reply fallback. - msgtype.sanitize(DEFAULT_SANITIZER_MODE, RemoveReplyFallback::No); - - let new_content = TimelineItemContent::Message(Message { - msgtype, - in_reply_to: msg.in_reply_to.clone(), - thread_root: msg.thread_root.clone(), - edited: true, - mentions: replacement.new_content.mentions, - }); - - let edit_json = match &this.ctx.flow { - Flow::Local { .. } => None, - Flow::Remote { raw_event, .. } => Some(raw_event.clone()), - }; + if self.ctx.sender != item.sender() { + info!( + original_sender = ?item.sender(), edit_sender = ?self.ctx.sender, + "Edit event applies to another user's timeline item, discarding" + ); + return; + } - trace!("Applying edit"); + let TimelineItemContent::Message(msg) = item.content() else { + info!( + "Edit of message event applies to {:?}, discarding", + item.content().debug_string(), + ); + return; + }; - if let EventTimelineItemKind::Remote(remote_event) = &event_item.kind { - let new_encryption_info = match &this.ctx.flow { - Flow::Local { .. } => None, - Flow::Remote { encryption_info, .. } => encryption_info.clone(), - }; + let mut msgtype = replacement.new_content.msgtype; + // Edit's content is never supposed to contain the reply fallback. + msgtype.sanitize(DEFAULT_SANITIZER_MODE, RemoveReplyFallback::No); - Some(event_item.with_content(new_content, edit_json).with_kind( - EventTimelineItemKind::Remote( - remote_event.with_encryption_info(new_encryption_info), - ), - )) - } else { - Some(event_item.with_content(new_content, edit_json)) - } + let new_content = TimelineItemContent::Message(Message { + msgtype, + in_reply_to: msg.in_reply_to.clone(), + thread_root: msg.thread_root.clone(), + edited: true, + mentions: replacement.new_content.mentions, }); - if !found { - debug!("Timeline item not found, discarding edit"); + let edit_json = match &self.ctx.flow { + Flow::Local { .. } => None, + Flow::Remote { raw_event, .. } => Some(raw_event.clone()), + }; + + let mut new_item = item.with_content(new_content, edit_json); + + if let EventTimelineItemKind::Remote(remote_event) = &item.kind { + if let Flow::Remote { encryption_info, .. } = &self.ctx.flow { + new_item = new_item.with_kind(EventTimelineItemKind::Remote( + remote_event.with_encryption_info(encryption_info.clone()), + )); + } } + + trace!("Applying edit"); + self.items.set(item_pos, TimelineItem::new(new_item, item.internal_id.to_owned())); + self.result.items_updated += 1; } // Redacted reaction events are no-ops so don't need to be handled @@ -652,51 +644,54 @@ impl<'a, 'o> TimelineEventHandler<'a, 'o> { &mut self, replacement: Replacement, ) { - let found = self.update_timeline_item(&replacement.event_id, |this, event_item| { - if this.ctx.sender != event_item.sender() { - info!( - original_sender = ?event_item.sender(), edit_sender = ?this.ctx.sender, - "Edit event applies to another user's timeline item, discarding" - ); - return None; - } + let Some((item_pos, item)) = rfind_event_by_id(self.items, &replacement.event_id) else { + debug!("Timeline item not found, discarding poll edit"); + return; + }; - let TimelineItemContent::Poll(poll_state) = &event_item.content() else { - info!( - "Edit of poll event applies to {}, discarding", - event_item.content().debug_string(), - ); - return None; - }; + if self.ctx.sender != item.sender() { + info!( + original_sender = ?item.sender(), edit_sender = ?self.ctx.sender, + "Edit event applies to another user's timeline item, discarding" + ); + return; + } - let new_content = match poll_state.edit(&replacement.new_content) { - Ok(edited_poll_state) => TimelineItemContent::Poll(edited_poll_state), - Err(e) => { - info!("Failed to apply poll edit: {e:?}"); - return None; - } - }; + let TimelineItemContent::Poll(poll_state) = &item.content() else { + info!("Edit of poll event applies to {}, discarding", item.content().debug_string(),); + return; + }; - let edit_json = match &this.ctx.flow { - Flow::Local { .. } => None, - Flow::Remote { raw_event, .. } => Some(raw_event.clone()), - }; + let new_content = match poll_state.edit(&replacement.new_content) { + Ok(edited_poll_state) => TimelineItemContent::Poll(edited_poll_state), + Err(e) => { + info!("Failed to apply poll edit: {e:?}"); + return; + } + }; - trace!("Applying edit"); - Some(event_item.with_content(new_content, edit_json)) - }); + let edit_json = match &self.ctx.flow { + Flow::Local { .. } => None, + Flow::Remote { raw_event, .. } => Some(raw_event.clone()), + }; - if !found { - debug!("Timeline item not found, discarding poll edit"); - } + trace!("Applying poll start edit."); + self.items.set( + item_pos, + TimelineItem::new( + item.with_content(new_content, edit_json), + item.internal_id.to_owned(), + ), + ); + self.result.items_updated += 1; } fn handle_poll_start(&mut self, c: NewUnstablePollStartEventContent, should_add: bool) { let mut poll_state = PollState::new(c); - if let Flow::Remote { event_id, .. } = self.ctx.flow.clone() { + if let Flow::Remote { event_id, .. } = &self.ctx.flow { // Applying the cache to remote events only because local echoes // don't have an event ID that could be referenced by responses yet. - self.meta.poll_pending_events.apply(&event_id, &mut poll_state); + self.meta.poll_pending_events.apply(event_id, &mut poll_state); } if should_add { @@ -705,44 +700,55 @@ impl<'a, 'o> TimelineEventHandler<'a, 'o> { } fn handle_poll_response(&mut self, c: UnstablePollResponseEventContent) { - let found = self.update_timeline_item(&c.relates_to.event_id, |this, event_item| { - let poll_state = as_variant!(event_item.content(), TimelineItemContent::Poll)?; - Some(event_item.with_content( - TimelineItemContent::Poll(poll_state.add_response( - &this.ctx.sender, - this.ctx.timestamp, - &c, - )), - None, - )) - }); - - if !found { + let Some((item_pos, item)) = rfind_event_by_id(self.items, &c.relates_to.event_id) else { self.meta.poll_pending_events.add_response( &c.relates_to.event_id, &self.ctx.sender, self.ctx.timestamp, &c, ); - } + return; + }; + + let TimelineItemContent::Poll(poll_state) = item.content() else { + return; + }; + + let new_item = item.with_content( + TimelineItemContent::Poll(poll_state.add_response( + &self.ctx.sender, + self.ctx.timestamp, + &c, + )), + None, + ); + + trace!("Adding poll response."); + self.items.set(item_pos, TimelineItem::new(new_item, item.internal_id.to_owned())); + self.result.items_updated += 1; } fn handle_poll_end(&mut self, c: UnstablePollEndEventContent) { - let found = self.update_timeline_item(&c.relates_to.event_id, |this, event_item| { - let poll_state = as_variant!(event_item.content(), TimelineItemContent::Poll)?; - match poll_state.end(this.ctx.timestamp) { - Ok(poll_state) => { - Some(event_item.with_content(TimelineItemContent::Poll(poll_state), None)) - } - Err(_) => { - info!("Got multiple poll end events, discarding"); - None - } - } - }); - - if !found { + let Some((item_pos, item)) = rfind_event_by_id(self.items, &c.relates_to.event_id) else { self.meta.poll_pending_events.add_end(&c.relates_to.event_id, self.ctx.timestamp); + return; + }; + + let TimelineItemContent::Poll(poll_state) = item.content() else { + return; + }; + + match poll_state.end(self.ctx.timestamp) { + Ok(poll_state) => { + let new_item = item.with_content(TimelineItemContent::Poll(poll_state), None); + + trace!("Ending poll."); + self.items.set(item_pos, TimelineItem::new(new_item, item.internal_id.to_owned())); + self.result.items_updated += 1; + } + Err(_) => { + info!("Got multiple poll end events, discarding"); + } } } @@ -767,28 +773,21 @@ impl<'a, 'o> TimelineEventHandler<'a, 'o> { } // General path: redact another kind of (non-reaction) event. - let found_redacted_event = self.update_timeline_item(&redacted, |this, event_item| { - if event_item.as_remote().is_none() { + if let Some((idx, item)) = rfind_event_by_id(self.items, &redacted) { + if item.as_remote().is_some() { + if let TimelineItemContent::RedactedMessage = &item.content { + debug!("event item is already redacted"); + } else { + let new_item = item.redact(&self.meta.room_version); + self.items.set(idx, TimelineItem::new(new_item, item.internal_id.to_owned())); + self.result.items_updated += 1; + } + } else { error!("inconsistent state: redaction received on a non-remote event item"); - return None; - } - - if let TimelineItemContent::RedactedMessage = &event_item.content { - debug!("event item is already redacted"); - return None; } - - Some(event_item.redact(&this.meta.room_version)) - }); - - if !found_redacted_event { + } else { debug!("Timeline item not found, discarding redaction"); - } - - if self.result.items_updated == 0 { - // We will want to know this when debugging redaction issues. - debug!("redaction affected no event"); - } + }; // Look for any timeline event that's a reply to the redacted event, and redact // the replied-to event there as well. @@ -822,43 +821,38 @@ impl<'a, 'o> TimelineEventHandler<'a, 'o> { sender, }) = self.meta.reactions.map.remove(&reaction_id) { - let updated_event = - self.update_timeline_item(&reacted_to_event_id, |_this, event_item| { - let Some(remote_event_item) = event_item.as_remote() else { - error!("inconsistent state: redaction received on a non-remote event item"); - return None; - }; - - let mut reactions = remote_event_item.reactions.clone(); - if reactions.remove_reaction(&sender, &key).is_some() { - trace!("Removing reaction"); - Some(event_item.with_kind(remote_event_item.with_reactions(reactions))) - } else { - warn!("Reaction to redact was missing from the reaction or user map"); - None - } - }); - - if !updated_event { + let Some((item_pos, item)) = rfind_event_by_id(self.items, &reacted_to_event_id) else { + // The remote event wasn't in the timeline. if let TimelineEventItemId::EventId(event_id) = reaction_id { - // If the remote event wasn't in the timeline, remove any possibly pending - // reactions to that event, as this redaction would affect them. + // Remove any possibly pending reactions to that event, as this redaction would + // affect them. if let Some(reactions) = self.meta.reactions.pending.get_mut(&reacted_to_event_id) { reactions.swap_remove(&event_id); } } - } - return updated_event; - } + // We haven't redacted the reaction. + return false; + }; + + let Some(remote_event_item) = item.as_remote() else { + error!("inconsistent state: redaction received on a non-remote event item"); + return false; + }; - if self.result.items_updated == 0 { - // We will want to know this when debugging redaction issues. - error!("redaction affected no event"); + let mut reactions = remote_event_item.reactions.clone(); + if reactions.remove_reaction(&sender, &key).is_some() { + trace!("Removing reaction"); + let new_item = item.with_kind(remote_event_item.with_reactions(reactions)); + self.items.set(item_pos, TimelineItem::new(new_item, item.internal_id.to_owned())); + self.result.items_updated += 1; + return true; + } } + warn!("Reaction to redact was missing from the reaction or user map"); false } @@ -1079,28 +1073,6 @@ impl<'a, 'o> TimelineEventHandler<'a, 'o> { } } } - - /// Updates the given timeline item. - /// - /// Returns true iff the item has been found (not necessarily updated), - /// false if it's not been found. - fn update_timeline_item( - &mut self, - event_id: &EventId, - update: impl FnOnce(&Self, &EventTimelineItem) -> Option, - ) -> bool { - if let Some((idx, item)) = rfind_event_by_id(self.items, event_id) { - trace!("Found timeline item to update"); - if let Some(new_item) = update(self, item.inner) { - trace!("Updating item"); - self.items.set(idx, TimelineItem::new(new_item, item.internal_id.to_owned())); - self.result.items_updated += 1; - } - true - } else { - false - } - } } /// Transfer `TimelineDetails` that weren't available on the original item and diff --git a/crates/matrix-sdk-ui/src/timeline/event_item/mod.rs b/crates/matrix-sdk-ui/src/timeline/event_item/mod.rs index fc0c00ee1b8..192d34da86c 100644 --- a/crates/matrix-sdk-ui/src/timeline/event_item/mod.rs +++ b/crates/matrix-sdk-ui/src/timeline/event_item/mod.rs @@ -188,7 +188,7 @@ impl EventTimelineItem { let room = client.get_room(room_id); let sender_profile = if let Some(room) = room { - let mut profile = room.profile_from_latest_event(&latest_event).await; + let mut profile = room.profile_from_latest_event(&latest_event); // Fallback to the slow path. if profile.is_none() { diff --git a/crates/matrix-sdk-ui/src/timeline/inner/mod.rs b/crates/matrix-sdk-ui/src/timeline/inner/mod.rs index ec2adcb2ca8..999e0768685 100644 --- a/crates/matrix-sdk-ui/src/timeline/inner/mod.rs +++ b/crates/matrix-sdk-ui/src/timeline/inner/mod.rs @@ -81,7 +81,7 @@ mod state; /// Data associated to the current timeline focus. #[derive(Debug)] -enum TimelineFocusData { +enum TimelineFocusData { /// The timeline receives live events from the sync. Live, @@ -91,7 +91,7 @@ enum TimelineFocusData { /// The event id we've started to focus on. event_id: OwnedEventId, /// The paginator instance. - paginator: Paginator, + paginator: Paginator

, /// Number of context events to request for the first request. num_context_events: u16, }, @@ -107,7 +107,7 @@ pub(super) struct TimelineInner { state: Arc>, /// Inner mutable focus state. - focus: Arc>, + focus: Arc>>, /// A [`RoomDataProvider`] implementation, providing data. /// @@ -239,7 +239,7 @@ impl TimelineInner

{ let (focus_data, is_live) = match focus { TimelineFocus::Live => (TimelineFocusData::Live, LiveTimelineUpdatesAllowed::All), TimelineFocus::Event { target, num_context_events } => { - let paginator = Paginator::new(Box::new(room_data_provider.clone())); + let paginator = Paginator::new(room_data_provider.clone()); ( TimelineFocusData::Event { paginator, event_id: target, num_context_events }, LiveTimelineUpdatesAllowed::None, diff --git a/crates/matrix-sdk-ui/src/timeline/pinned_events_loader.rs b/crates/matrix-sdk-ui/src/timeline/pinned_events_loader.rs index 642b2f0b013..e20b7f6d0e0 100644 --- a/crates/matrix-sdk-ui/src/timeline/pinned_events_loader.rs +++ b/crates/matrix-sdk-ui/src/timeline/pinned_events_loader.rs @@ -14,10 +14,10 @@ use std::{fmt::Formatter, num::NonZeroUsize, sync::Arc}; -use futures_util::future::join_all; +use futures_util::{future::join_all, FutureExt as _}; use matrix_sdk::{ - config::RequestConfig, event_cache::paginator::PaginatorError, Room, SendOutsideWasm, - SyncOutsideWasm, + config::RequestConfig, event_cache::paginator::PaginatorError, BoxFuture, Room, + SendOutsideWasm, SyncOutsideWasm, }; use matrix_sdk_base::deserialized_responses::SyncTimelineEvent; use ruma::{EventId, MilliSecondsSinceUnixEpoch, OwnedEventId}; @@ -101,15 +101,13 @@ impl PinnedEventsLoader { } } -#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] pub trait PinnedEventsRoom: SendOutsideWasm + SyncOutsideWasm { /// Load a single room event using the cache or network. - async fn load_event( - &self, - event_id: &EventId, + fn load_event<'a>( + &'a self, + event_id: &'a EventId, request_config: Option, - ) -> Result; + ) -> BoxFuture<'a, Result>; /// Get the pinned event ids for a room. fn pinned_event_ids(&self) -> Vec; @@ -121,26 +119,27 @@ pub trait PinnedEventsRoom: SendOutsideWasm + SyncOutsideWasm { fn is_pinned_event(&self, event_id: &EventId) -> bool; } -#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] impl PinnedEventsRoom for Room { - async fn load_event( - &self, - event_id: &EventId, + fn load_event<'a>( + &'a self, + event_id: &'a EventId, request_config: Option, - ) -> Result { - if let Ok((cache, _handles)) = self.event_cache().await { - if let Some(event) = cache.event(event_id).await { - debug!("Loaded pinned event {event_id} from cache"); - return Ok(event); + ) -> BoxFuture<'a, Result> { + async move { + if let Ok((cache, _handles)) = self.event_cache().await { + if let Some(event) = cache.event(event_id).await { + debug!("Loaded pinned event {event_id} from cache"); + return Ok(event); + } } - } - debug!("Loading pinned event {event_id} from HS"); - self.event(event_id, request_config) - .await - .map(|e| e.into()) - .map_err(|err| PaginatorError::SdkError(Box::new(err))) + debug!("Loading pinned event {event_id} from HS"); + self.event(event_id, request_config) + .await + .map(|e| e.into()) + .map_err(|err| PaginatorError::SdkError(Box::new(err))) + } + .boxed() } fn pinned_event_ids(&self) -> Vec { diff --git a/crates/matrix-sdk-ui/src/timeline/tests/mod.rs b/crates/matrix-sdk-ui/src/timeline/tests/mod.rs index 7b4e67468bb..c641fbd618b 100644 --- a/crates/matrix-sdk-ui/src/timeline/tests/mod.rs +++ b/crates/matrix-sdk-ui/src/timeline/tests/mod.rs @@ -16,12 +16,13 @@ use std::{ collections::{BTreeMap, HashMap}, + future::ready, sync::Arc, }; -use async_trait::async_trait; use eyeball_im::VectorDiff; use futures_core::Stream; +use futures_util::FutureExt as _; use indexmap::IndexMap; use matrix_sdk::{ config::RequestConfig, @@ -30,6 +31,7 @@ use matrix_sdk::{ room::{EventWithContextResponse, Messages, MessagesOptions}, send_queue::RoomSendQueueUpdate, test_utils::events::EventFactory, + BoxFuture, }; use matrix_sdk_base::latest_event::LatestEvent; use matrix_sdk_test::{EventBuilder, ALICE, BOB}; @@ -301,8 +303,6 @@ impl TestRoomDataProvider { } } -#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] impl PaginableRoom for TestRoomDataProvider { async fn event_with_context( &self, @@ -318,14 +318,12 @@ impl PaginableRoom for TestRoomDataProvider { } } -#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] impl PinnedEventsRoom for TestRoomDataProvider { - async fn load_event( - &self, - _event_id: &EventId, + fn load_event<'a>( + &'a self, + _event_id: &'a EventId, _config: Option, - ) -> Result { + ) -> BoxFuture<'a, Result> { unimplemented!(); } @@ -338,7 +336,6 @@ impl PinnedEventsRoom for TestRoomDataProvider { } } -#[async_trait] impl RoomDataProvider for TestRoomDataProvider { fn own_user_id(&self) -> &UserId { &ALICE @@ -348,36 +345,43 @@ impl RoomDataProvider for TestRoomDataProvider { RoomVersionId::V10 } - async fn profile_from_user_id(&self, _user_id: &UserId) -> Option { - None + fn profile_from_user_id<'a>(&'a self, _user_id: &'a UserId) -> BoxFuture<'a, Option> { + ready(None).boxed() } - async fn profile_from_latest_event(&self, _latest_event: &LatestEvent) -> Option { + fn profile_from_latest_event(&self, _latest_event: &LatestEvent) -> Option { None } - async fn load_user_receipt( + fn load_user_receipt( &self, receipt_type: ReceiptType, thread: ReceiptThread, user_id: &UserId, - ) -> Option<(OwnedEventId, Receipt)> { - self.initial_user_receipts - .get(&receipt_type) - .and_then(|thread_map| thread_map.get(&thread)) - .and_then(|user_map| user_map.get(user_id)) - .cloned() - } - - async fn load_event_receipts(&self, event_id: &EventId) -> IndexMap { - if event_id == event_id!("$event_with_bob_receipt") { + ) -> BoxFuture<'_, Option<(OwnedEventId, Receipt)>> { + ready( + self.initial_user_receipts + .get(&receipt_type) + .and_then(|thread_map| thread_map.get(&thread)) + .and_then(|user_map| user_map.get(user_id)) + .cloned(), + ) + .boxed() + } + + fn load_event_receipts( + &self, + event_id: &EventId, + ) -> BoxFuture<'_, IndexMap> { + ready(if event_id == event_id!("$event_with_bob_receipt") { [(BOB.to_owned(), Receipt::new(MilliSecondsSinceUnixEpoch(uint!(10))))].into() } else { IndexMap::new() - } + }) + .boxed() } - async fn push_rules_and_context(&self) -> Option<(Ruleset, PushConditionRoomCtx)> { + fn push_rules_and_context(&self) -> BoxFuture<'_, Option<(Ruleset, PushConditionRoomCtx)>> { let push_rules = Ruleset::server_default(&ALICE); let power_levels = PushConditionPowerLevelsCtx { users: BTreeMap::new(), @@ -392,25 +396,31 @@ impl RoomDataProvider for TestRoomDataProvider { power_levels: Some(power_levels), }; - Some((push_rules, push_context)) + ready(Some((push_rules, push_context))).boxed() } - async fn load_fully_read_marker(&self) -> Option { - self.fully_read_marker.clone() + fn load_fully_read_marker(&self) -> BoxFuture<'_, Option> { + ready(self.fully_read_marker.clone()).boxed() } - async fn send(&self, content: AnyMessageLikeEventContent) -> Result<(), super::Error> { - self.sent_events.write().await.push(content); - Ok(()) + fn send(&self, content: AnyMessageLikeEventContent) -> BoxFuture<'_, Result<(), super::Error>> { + async move { + self.sent_events.write().await.push(content); + Ok(()) + } + .boxed() } - async fn redact( - &self, - event_id: &EventId, - _reason: Option<&str>, + fn redact<'a>( + &'a self, + event_id: &'a EventId, + _reason: Option<&'a str>, _transaction_id: Option, - ) -> Result<(), super::Error> { - self.redacted.write().await.push(event_id.to_owned()); - Ok(()) + ) -> BoxFuture<'a, Result<(), super::Error>> { + async move { + self.redacted.write().await.push(event_id.to_owned()); + Ok(()) + } + .boxed() } } diff --git a/crates/matrix-sdk-ui/src/timeline/traits.rs b/crates/matrix-sdk-ui/src/timeline/traits.rs index 53a0730ec94..c55973d1c6e 100644 --- a/crates/matrix-sdk-ui/src/timeline/traits.rs +++ b/crates/matrix-sdk-ui/src/timeline/traits.rs @@ -12,11 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -use async_trait::async_trait; +use std::future::Future; + +use futures_util::FutureExt as _; use indexmap::IndexMap; #[cfg(feature = "e2e-encryption")] use matrix_sdk::{deserialized_responses::TimelineEvent, Result}; -use matrix_sdk::{event_cache::paginator::PaginableRoom, Room}; +use matrix_sdk::{event_cache::paginator::PaginableRoom, BoxFuture, Room}; use matrix_sdk_base::latest_event::LatestEvent; #[cfg(feature = "e2e-encryption")] use ruma::{events::AnySyncTimelineEvent, serde::Raw}; @@ -34,7 +36,6 @@ use tracing::{debug, error}; use super::{Profile, TimelineBuilder}; use crate::timeline::{self, pinned_events_loader::PinnedEventsRoom, Timeline}; -#[async_trait] pub trait RoomExt { /// Get a [`Timeline`] for this room. /// @@ -43,7 +44,7 @@ pub trait RoomExt { /// independent events. /// /// This is the same as using `room.timeline_builder().build()`. - async fn timeline(&self) -> Result; + fn timeline(&self) -> impl Future> + Send; /// Get a [`TimelineBuilder`] for this room. /// @@ -56,7 +57,6 @@ pub trait RoomExt { fn timeline_builder(&self) -> TimelineBuilder; } -#[async_trait] impl RoomExt for Room { async fn timeline(&self) -> Result { self.timeline_builder().build().await @@ -67,44 +67,46 @@ impl RoomExt for Room { } } -#[async_trait] pub(super) trait RoomDataProvider: Clone + Send + Sync + 'static + PaginableRoom + PinnedEventsRoom { fn own_user_id(&self) -> &UserId; fn room_version(&self) -> RoomVersionId; - async fn profile_from_user_id(&self, user_id: &UserId) -> Option; - async fn profile_from_latest_event(&self, latest_event: &LatestEvent) -> Option; + + fn profile_from_user_id<'a>(&'a self, user_id: &'a UserId) -> BoxFuture<'a, Option>; + fn profile_from_latest_event(&self, latest_event: &LatestEvent) -> Option; /// Loads a user receipt from the storage backend. - async fn load_user_receipt( - &self, + fn load_user_receipt<'a>( + &'a self, receipt_type: ReceiptType, thread: ReceiptThread, - user_id: &UserId, - ) -> Option<(OwnedEventId, Receipt)>; + user_id: &'a UserId, + ) -> BoxFuture<'a, Option<(OwnedEventId, Receipt)>>; /// Loads read receipts for an event from the storage backend. - async fn load_event_receipts(&self, event_id: &EventId) -> IndexMap; + fn load_event_receipts<'a>( + &'a self, + event_id: &'a EventId, + ) -> BoxFuture<'a, IndexMap>; /// Load the current fully-read event id, from storage. - async fn load_fully_read_marker(&self) -> Option; + fn load_fully_read_marker(&self) -> BoxFuture<'_, Option>; - async fn push_rules_and_context(&self) -> Option<(Ruleset, PushConditionRoomCtx)>; + fn push_rules_and_context(&self) -> BoxFuture<'_, Option<(Ruleset, PushConditionRoomCtx)>>; /// Send an event to that room. - async fn send(&self, content: AnyMessageLikeEventContent) -> Result<(), super::Error>; + fn send(&self, content: AnyMessageLikeEventContent) -> BoxFuture<'_, Result<(), super::Error>>; /// Redact an event from that room. - async fn redact( - &self, - event_id: &EventId, - reason: Option<&str>, + fn redact<'a>( + &'a self, + event_id: &'a EventId, + reason: Option<&'a str>, transaction_id: Option, - ) -> Result<(), super::Error>; + ) -> BoxFuture<'a, Result<(), super::Error>>; } -#[async_trait] impl RoomDataProvider for Room { fn own_user_id(&self) -> &UserId { (**self).own_user_id() @@ -114,23 +116,26 @@ impl RoomDataProvider for Room { (**self).clone_info().room_version_or_default() } - async fn profile_from_user_id(&self, user_id: &UserId) -> Option { - match self.get_member_no_sync(user_id).await { - Ok(Some(member)) => Some(Profile { - display_name: member.display_name().map(ToOwned::to_owned), - display_name_ambiguous: member.name_ambiguous(), - avatar_url: member.avatar_url().map(ToOwned::to_owned), - }), - Ok(None) if self.are_members_synced() => Some(Profile::default()), - Ok(None) => None, - Err(e) => { - error!(%user_id, "Failed to fetch room member information: {e}"); - None + fn profile_from_user_id<'a>(&'a self, user_id: &'a UserId) -> BoxFuture<'a, Option> { + async move { + match self.get_member_no_sync(user_id).await { + Ok(Some(member)) => Some(Profile { + display_name: member.display_name().map(ToOwned::to_owned), + display_name_ambiguous: member.name_ambiguous(), + avatar_url: member.avatar_url().map(ToOwned::to_owned), + }), + Ok(None) if self.are_members_synced() => Some(Profile::default()), + Ok(None) => None, + Err(e) => { + error!(%user_id, "Failed to fetch room member information: {e}"); + None + } } } + .boxed() } - async fn profile_from_latest_event(&self, latest_event: &LatestEvent) -> Option { + fn profile_from_latest_event(&self, latest_event: &LatestEvent) -> Option { if !latest_event.has_sender_profile() { return None; } @@ -142,119 +147,141 @@ impl RoomDataProvider for Room { }) } - async fn load_user_receipt( - &self, + fn load_user_receipt<'a>( + &'a self, receipt_type: ReceiptType, thread: ReceiptThread, - user_id: &UserId, - ) -> Option<(OwnedEventId, Receipt)> { - match self.load_user_receipt(receipt_type.clone(), thread.clone(), user_id).await { - Ok(receipt) => receipt, - Err(e) => { - error!( - ?receipt_type, - ?thread, - ?user_id, - "Failed to get read receipt for user: {e}" - ); - None + user_id: &'a UserId, + ) -> BoxFuture<'a, Option<(OwnedEventId, Receipt)>> { + async move { + match self.load_user_receipt(receipt_type.clone(), thread.clone(), user_id).await { + Ok(receipt) => receipt, + Err(e) => { + error!( + ?receipt_type, + ?thread, + ?user_id, + "Failed to get read receipt for user: {e}" + ); + None + } } } + .boxed() } - async fn load_event_receipts(&self, event_id: &EventId) -> IndexMap { - let mut unthreaded_receipts = match self - .load_event_receipts(ReceiptType::Read, ReceiptThread::Unthreaded, event_id) - .await - { - Ok(receipts) => receipts.into_iter().collect(), - Err(e) => { - error!(?event_id, "Failed to get unthreaded read receipts for event: {e}"); - IndexMap::new() - } - }; + fn load_event_receipts<'a>( + &'a self, + event_id: &'a EventId, + ) -> BoxFuture<'a, IndexMap> { + async move { + let mut unthreaded_receipts = match self + .load_event_receipts(ReceiptType::Read, ReceiptThread::Unthreaded, event_id) + .await + { + Ok(receipts) => receipts.into_iter().collect(), + Err(e) => { + error!(?event_id, "Failed to get unthreaded read receipts for event: {e}"); + IndexMap::new() + } + }; - let main_thread_receipts = match self - .load_event_receipts(ReceiptType::Read, ReceiptThread::Main, event_id) - .await - { - Ok(receipts) => receipts, - Err(e) => { - error!(?event_id, "Failed to get main thread read receipts for event: {e}"); - Vec::new() - } - }; + let main_thread_receipts = match self + .load_event_receipts(ReceiptType::Read, ReceiptThread::Main, event_id) + .await + { + Ok(receipts) => receipts, + Err(e) => { + error!(?event_id, "Failed to get main thread read receipts for event: {e}"); + Vec::new() + } + }; - unthreaded_receipts.extend(main_thread_receipts); - unthreaded_receipts + unthreaded_receipts.extend(main_thread_receipts); + unthreaded_receipts + } + .boxed() } - async fn push_rules_and_context(&self) -> Option<(Ruleset, PushConditionRoomCtx)> { - match self.push_context().await { - Ok(Some(push_context)) => match self.client().account().push_rules().await { - Ok(push_rules) => Some((push_rules, push_context)), + fn push_rules_and_context(&self) -> BoxFuture<'_, Option<(Ruleset, PushConditionRoomCtx)>> { + async { + match self.push_context().await { + Ok(Some(push_context)) => match self.client().account().push_rules().await { + Ok(push_rules) => Some((push_rules, push_context)), + Err(e) => { + error!("Could not get push rules: {e}"); + None + } + }, + Ok(None) => { + debug!("Could not aggregate push context"); + None + } Err(e) => { - error!("Could not get push rules: {e}"); + error!("Could not get push context: {e}"); None } - }, - Ok(None) => { - debug!("Could not aggregate push context"); - None - } - Err(e) => { - error!("Could not get push context: {e}"); - None } } + .boxed() } - async fn load_fully_read_marker(&self) -> Option { - match self.account_data_static::().await { - Ok(Some(fully_read)) => match fully_read.deserialize() { - Ok(fully_read) => Some(fully_read.content.event_id), + fn load_fully_read_marker(&self) -> BoxFuture<'_, Option> { + async { + match self.account_data_static::().await { + Ok(Some(fully_read)) => match fully_read.deserialize() { + Ok(fully_read) => Some(fully_read.content.event_id), + Err(e) => { + error!("Failed to deserialize fully-read account data: {e}"); + None + } + }, Err(e) => { - error!("Failed to deserialize fully-read account data: {e}"); + error!("Failed to get fully-read account data from the store: {e}"); None } - }, - Err(e) => { - error!("Failed to get fully-read account data from the store: {e}"); - None + _ => None, } - _ => None, } + .boxed() } - async fn send(&self, content: AnyMessageLikeEventContent) -> Result<(), super::Error> { - let _ = self.send_queue().send(content).await?; - Ok(()) + fn send(&self, content: AnyMessageLikeEventContent) -> BoxFuture<'_, Result<(), super::Error>> { + async move { + let _ = self.send_queue().send(content).await?; + Ok(()) + } + .boxed() } - async fn redact( - &self, - event_id: &EventId, - reason: Option<&str>, + fn redact<'a>( + &'a self, + event_id: &'a EventId, + reason: Option<&'a str>, transaction_id: Option, - ) -> Result<(), super::Error> { - let _ = self - .redact(event_id, reason, transaction_id) - .await - .map_err(super::Error::RedactError)?; - Ok(()) + ) -> BoxFuture<'a, Result<(), super::Error>> { + async move { + let _ = self + .redact(event_id, reason, transaction_id) + .await + .map_err(super::Error::RedactError)?; + Ok(()) + } + .boxed() } } // Internal helper to make most of retry_event_decryption independent of a room // object, which is annoying to create for testing and not really needed #[cfg(feature = "e2e-encryption")] -#[async_trait] pub(super) trait Decryptor: Clone + Send + Sync + 'static { - async fn decrypt_event_impl(&self, raw: &Raw) -> Result; + fn decrypt_event_impl( + &self, + raw: &Raw, + ) -> impl Future> + Send; } #[cfg(feature = "e2e-encryption")] -#[async_trait] impl Decryptor for Room { async fn decrypt_event_impl(&self, raw: &Raw) -> Result { self.decrypt_event(raw.cast_ref()).await @@ -262,7 +289,6 @@ impl Decryptor for Room { } #[cfg(all(test, feature = "e2e-encryption"))] -#[async_trait] impl Decryptor for (matrix_sdk_base::crypto::OlmMachine, ruma::OwnedRoomId) { async fn decrypt_event_impl(&self, raw: &Raw) -> Result { let (olm_machine, room_id) = self; diff --git a/crates/matrix-sdk/src/event_cache/mod.rs b/crates/matrix-sdk/src/event_cache/mod.rs index 57d8e36f857..0238ffd5e4e 100644 --- a/crates/matrix-sdk/src/event_cache/mod.rs +++ b/crates/matrix-sdk/src/event_cache/mod.rs @@ -609,7 +609,7 @@ struct RoomEventCacheInner { /// /// It's protected behind a lock to avoid multiple accesses to the paginator /// at the same time. - pagination: RoomPaginationData, + pagination: RoomPaginationData, } impl RoomEventCacheInner { @@ -630,7 +630,7 @@ impl RoomEventCacheInner { all_events_cache, sender, pagination: RoomPaginationData { - paginator: Paginator::new(Box::new(weak_room)), + paginator: Paginator::new(weak_room), waited_for_initial_prev_token: Mutex::new(false), token_notifier: Default::default(), }, diff --git a/crates/matrix-sdk/src/event_cache/pagination.rs b/crates/matrix-sdk/src/event_cache/pagination.rs index a24af594094..e81fdad8879 100644 --- a/crates/matrix-sdk/src/event_cache/pagination.rs +++ b/crates/matrix-sdk/src/event_cache/pagination.rs @@ -25,19 +25,19 @@ use tokio::{ use tracing::{debug, instrument, trace}; use super::{ - paginator::{PaginationResult, Paginator, PaginatorState}, + paginator::{PaginableRoom, PaginationResult, Paginator, PaginatorState}, store::Gap, BackPaginationOutcome, Result, RoomEventCacheInner, }; use crate::event_cache::{linked_chunk::ChunkContent, store::RoomEvents}; #[derive(Debug)] -pub(super) struct RoomPaginationData { +pub(super) struct RoomPaginationData { /// A notifier that we received a new pagination token. pub token_notifier: Notify, /// The stateful paginator instance used for the integrated pagination. - pub paginator: Paginator, + pub paginator: Paginator, /// Have we ever waited for a previous-batch-token to come from sync? We do /// this at most once per room, the first time we try to run backward diff --git a/crates/matrix-sdk/src/event_cache/paginator.rs b/crates/matrix-sdk/src/event_cache/paginator.rs index 42d82fb2a2f..228fd219fb3 100644 --- a/crates/matrix-sdk/src/event_cache/paginator.rs +++ b/crates/matrix-sdk/src/event_cache/paginator.rs @@ -17,7 +17,7 @@ //! makes it possible to paginate forward or backward, from that event, until //! one end of the timeline (front or back) is reached. -use std::sync::Mutex; +use std::{future::Future, sync::Mutex}; use eyeball::{SharedObservable, Subscriber}; use matrix_sdk_base::{deserialized_responses::TimelineEvent, SendOutsideWasm, SyncOutsideWasm}; @@ -94,9 +94,9 @@ impl From> for PaginationToken { /// forward from it. /// /// See also the module-level documentation. -pub struct Paginator { +pub struct Paginator { /// The room in which we're going to run the pagination. - room: Box, + room: PR, /// Current state of the paginator. state: SharedObservable, @@ -113,7 +113,7 @@ pub struct Paginator { } #[cfg(not(tarpaulin_include))] -impl std::fmt::Debug for Paginator { +impl std::fmt::Debug for Paginator { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // Don't include the room in the debug output. f.debug_struct("Paginator") @@ -186,9 +186,9 @@ impl Drop for ResetStateGuard { } } -impl Paginator { +impl Paginator { /// Create a new [`Paginator`], given a room implementation. - pub fn new(room: Box) -> Self { + pub fn new(room: PR) -> Self { Self { room, state: SharedObservable::new(PaginatorState::Initial), @@ -431,8 +431,6 @@ impl Paginator { /// /// Not [`crate::Room`] because we may want to paginate rooms we don't belong /// to. -#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] pub trait PaginableRoom: SendOutsideWasm + SyncOutsideWasm { /// Runs a /context query for the given room. /// @@ -440,28 +438,28 @@ pub trait PaginableRoom: SendOutsideWasm + SyncOutsideWasm { /// /// - `event_id` is the identifier of the target event. /// - `lazy_load_members` controls whether room membership events are lazily - /// loaded as context - /// state events. + /// loaded as context state events. /// - `num_events` is the number of events (including the fetched event) to - /// return as context. + /// return as context. /// /// ## Returns /// /// Must return [`PaginatorError::EventNotFound`] whenever the target event /// could not be found, instead of causing an http `Err` result. - async fn event_with_context( + fn event_with_context( &self, event_id: &EventId, lazy_load_members: bool, num_events: UInt, - ) -> Result; + ) -> impl Future> + SendOutsideWasm; /// Runs a /messages query for the given room. - async fn messages(&self, opts: MessagesOptions) -> Result; + fn messages( + &self, + opts: MessagesOptions, + ) -> impl Future> + SendOutsideWasm; } -#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] impl PaginableRoom for Room { async fn event_with_context( &self, @@ -474,8 +472,9 @@ impl PaginableRoom for Room { Ok(result) => result, Err(err) => { - // If the error was a 404, then the event wasn't found on the server; special - // case this to make it easy to react to such an error. + // If the error was a 404, then the event wasn't found on the server; + // special case this to make it easy to react to + // such an error. if let Some(error) = err.as_client_api_error() { if error.status_code == 404 { // Event not found @@ -496,8 +495,6 @@ impl PaginableRoom for Room { } } -#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] impl PaginableRoom for WeakRoom { async fn event_with_context( &self, @@ -513,7 +510,6 @@ impl PaginableRoom for WeakRoom { PaginableRoom::event_with_context(&room, event_id, lazy_load_members, num_events).await } - /// Runs a /messages query for the given room. async fn messages(&self, opts: MessagesOptions) -> Result { let Some(room) = self.get() else { // Client is shutting down, return a default response. @@ -529,7 +525,6 @@ mod tests { use std::sync::Arc; use assert_matches2::assert_let; - use async_trait::async_trait; use futures_core::Future; use futures_util::FutureExt as _; use matrix_sdk_base::deserialized_responses::TimelineEvent; @@ -589,7 +584,6 @@ mod tests { static ROOM_ID: Lazy<&RoomId> = Lazy::new(|| room_id!("!dune:herbert.org")); static USER_ID: Lazy<&UserId> = Lazy::new(|| user_id!("@paul:atreid.es")); - #[async_trait] impl PaginableRoom for TestRoom { async fn event_with_context( &self, @@ -632,14 +626,14 @@ mod tests { events_after[0..num_events.min(events_after.len())].to_vec() }; - return Ok(EventWithContextResponse { + Ok(EventWithContextResponse { event: Some(event), events_before, events_after, prev_batch_token: self.prev_batch_token.lock().await.clone(), next_batch_token: self.next_batch_token.lock().await.clone(), state: Vec::new(), - }); + }) } async fn messages(&self, opts: MessagesOptions) -> Result { @@ -674,12 +668,7 @@ mod tests { } }; - return Ok(Messages { - start: opts.from.unwrap(), - end, - chunk: events, - state: Vec::new(), - }); + Ok(Messages { start: opts.from.unwrap(), end, chunk: events, state: Vec::new() }) } } @@ -701,7 +690,7 @@ mod tests { #[async_test] async fn test_start_from() { // Prepare test data. - let room = Box::new(TestRoom::new(false, *ROOM_ID, *USER_ID)); + let room = TestRoom::new(false, *ROOM_ID, *USER_ID); let event_id = event_id!("$yoyoyo"); let event_factory = &room.event_factory; @@ -749,7 +738,7 @@ mod tests { #[async_test] async fn test_start_from_with_num_events() { // Prepare test data. - let room = Box::new(TestRoom::new(false, *ROOM_ID, *USER_ID)); + let room = TestRoom::new(false, *ROOM_ID, *USER_ID); let event_id = event_id!("$yoyoyo"); let event_factory = &room.event_factory; @@ -780,7 +769,7 @@ mod tests { #[async_test] async fn test_paginate_backward() { // Prepare test data. - let room = Box::new(TestRoom::new(false, *ROOM_ID, *USER_ID)); + let room = TestRoom::new(false, *ROOM_ID, *USER_ID); let event_id = event_id!("$yoyoyo"); let event_factory = &room.event_factory; @@ -852,7 +841,7 @@ mod tests { #[async_test] async fn test_paginate_backward_with_limit() { // Prepare test data. - let room = Box::new(TestRoom::new(false, *ROOM_ID, *USER_ID)); + let room = TestRoom::new(false, *ROOM_ID, *USER_ID); let event_id = event_id!("$yoyoyo"); let event_factory = &room.event_factory; @@ -896,7 +885,7 @@ mod tests { #[async_test] async fn test_paginate_forward() { // Prepare test data. - let room = Box::new(TestRoom::new(false, *ROOM_ID, *USER_ID)); + let room = TestRoom::new(false, *ROOM_ID, *USER_ID); let event_id = event_id!("$yoyoyo"); let event_factory = &room.event_factory; @@ -967,7 +956,7 @@ mod tests { #[async_test] async fn test_state() { - let room = Box::new(TestRoom::new(true, *ROOM_ID, *USER_ID)); + let room = TestRoom::new(true, *ROOM_ID, *USER_ID); *room.prev_batch_token.lock().await = Some("prev".to_owned()); *room.next_batch_token.lock().await = Some("next".to_owned()); @@ -1089,7 +1078,6 @@ mod tests { } } - #[async_trait] impl PaginableRoom for AbortingRoom { async fn event_with_context( &self, @@ -1107,7 +1095,7 @@ mod tests { #[async_test] async fn test_abort_while_starting_from() { - let room = Box::new(AbortingRoom::default()); + let room = AbortingRoom::default(); let paginator = Arc::new(Paginator::new(room.clone())); @@ -1140,7 +1128,7 @@ mod tests { #[async_test] async fn test_abort_while_paginating() { - let room = Box::new(AbortingRoom::default()); + let room = AbortingRoom::default(); // Assuming a paginator ready to back- or forward- paginate, let paginator = Paginator::new(room.clone()); diff --git a/crates/matrix-sdk/src/room/edit.rs b/crates/matrix-sdk/src/room/edit.rs index 9718b1e80f0..45e50f31d97 100644 --- a/crates/matrix-sdk/src/room/edit.rs +++ b/crates/matrix-sdk/src/room/edit.rs @@ -14,7 +14,9 @@ //! Facilities to edit existing events. -use matrix_sdk_base::deserialized_responses::SyncTimelineEvent; +use std::future::Future; + +use matrix_sdk_base::{deserialized_responses::SyncTimelineEvent, SendOutsideWasm}; use ruma::{ events::{ room::message::{Relation, ReplacementMetadata, RoomMessageEventContentWithoutRelation}, @@ -88,14 +90,13 @@ impl Room { } } -#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] trait EventSource { - async fn get_event(&self, event_id: &EventId) -> Result; + fn get_event( + &self, + event_id: &EventId, + ) -> impl Future> + SendOutsideWasm; } -#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] impl<'a> EventSource for &'a Room { async fn get_event(&self, event_id: &EventId) -> Result { match self.event_cache().await { @@ -225,8 +226,6 @@ mod tests { events: BTreeMap, } - #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] - #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] impl EventSource for TestEventCache { async fn get_event(&self, event_id: &EventId) -> Result { Ok(self.events.get(event_id).unwrap().clone())