From 2bcc70beb941e2207cf6ae1fa8785c5906a7a386 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Tue, 6 Jun 2023 11:57:05 +0200 Subject: [PATCH] ui: Move timeline-internal traits into separate module --- .../src/timeline/event_item/content.rs | 2 +- crates/matrix-sdk-ui/src/timeline/inner.rs | 105 ++------------- crates/matrix-sdk-ui/src/timeline/mod.rs | 1 + .../src/timeline/read_receipts.rs | 6 +- .../matrix-sdk-ui/src/timeline/tests/mod.rs | 2 +- crates/matrix-sdk-ui/src/timeline/traits.rs | 120 ++++++++++++++++++ 6 files changed, 133 insertions(+), 103 deletions(-) create mode 100644 crates/matrix-sdk-ui/src/timeline/traits.rs diff --git a/crates/matrix-sdk-ui/src/timeline/event_item/content.rs b/crates/matrix-sdk-ui/src/timeline/event_item/content.rs index d8bffe40d..921c92d33 100644 --- a/crates/matrix-sdk-ui/src/timeline/event_item/content.rs +++ b/crates/matrix-sdk-ui/src/timeline/event_item/content.rs @@ -60,7 +60,7 @@ use tracing::{debug, error}; use super::{EventTimelineItem, Profile, TimelineDetails}; use crate::timeline::{ - inner::RoomDataProvider, Error as TimelineError, TimelineItem, DEFAULT_SANITIZER_MODE, + traits::RoomDataProvider, Error as TimelineError, TimelineItem, DEFAULT_SANITIZER_MODE, }; /// The content of an [`EventTimelineItem`][super::EventTimelineItem]. diff --git a/crates/matrix-sdk-ui/src/timeline/inner.rs b/crates/matrix-sdk-ui/src/timeline/inner.rs index 082ddf8b6..517cec2db 100644 --- a/crates/matrix-sdk-ui/src/timeline/inner.rs +++ b/crates/matrix-sdk-ui/src/timeline/inner.rs @@ -16,12 +16,11 @@ use std::collections::BTreeSet; use std::{collections::HashMap, sync::Arc}; -use async_trait::async_trait; use eyeball_im::{ObservableVector, VectorSubscriber}; #[cfg(feature = "testing")] use eyeball_im_util::{FilterMapVectorSubscriber, VectorExt}; use imbl::Vector; -use indexmap::{IndexMap, IndexSet}; +use indexmap::IndexSet; #[cfg(all(test, feature = "e2e-encryption"))] use matrix_sdk::crypto::OlmMachine; use matrix_sdk::{ @@ -41,10 +40,8 @@ use ruma::{ receipt::{Receipt, ReceiptThread, ReceiptType}, relation::Annotation, AnyMessageLikeEventContent, AnyRoomAccountDataEvent, AnySyncEphemeralRoomEvent, - AnySyncTimelineEvent, }, - push::{Action, PushConditionRoomCtx, Ruleset}, - serde::Raw, + push::Action, EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedTransactionId, OwnedUserId, TransactionId, UserId, }; @@ -53,15 +50,18 @@ use tracing::{debug, error, field::debug, info, instrument, trace, warn}; #[cfg(feature = "e2e-encryption")] use tracing::{field, info_span, Instrument as _}; +#[cfg(feature = "e2e-encryption")] +use super::traits::Decryptor; use super::{ compare_events_positions, event_handler::{ update_read_marker, Flow, HandleEventResult, TimelineEventHandler, TimelineEventKind, TimelineEventMetadata, TimelineItemPosition, }, - rfind_event_by_id, rfind_event_item, EventSendState, EventTimelineItem, InReplyToDetails, - Message, Profile, RelativePosition, RepliedToEvent, TimelineDetails, TimelineItem, - TimelineItemContent, + rfind_event_by_id, rfind_event_item, + traits::RoomDataProvider, + EventSendState, EventTimelineItem, InReplyToDetails, Message, Profile, RelativePosition, + RepliedToEvent, TimelineDetails, TimelineItem, TimelineItemContent, }; use crate::events::SyncTimelineEventWithoutContent; @@ -928,92 +928,3 @@ async fn fetch_replied_to_event( }; Ok(res) } - -#[async_trait] -pub(super) trait RoomDataProvider { - fn own_user_id(&self) -> &UserId; - async fn profile(&self, user_id: &UserId) -> Option; - async fn read_receipts_for_event(&self, event_id: &EventId) -> IndexMap; - async fn push_rules_and_context(&self) -> Option<(Ruleset, PushConditionRoomCtx)>; -} - -#[async_trait] -impl RoomDataProvider for room::Common { - fn own_user_id(&self) -> &UserId { - (**self).own_user_id() - } - - async fn profile(&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 { - display_name: None, - display_name_ambiguous: false, - avatar_url: None, - }), - Ok(None) => None, - Err(e) => { - error!(%user_id, "Failed to getch room member information: {e}"); - None - } - } - } - - async fn read_receipts_for_event(&self, event_id: &EventId) -> IndexMap { - match self.event_receipts(ReceiptType::Read, ReceiptThread::Unthreaded, event_id).await { - Ok(receipts) => receipts.into_iter().collect(), - Err(e) => { - error!(?event_id, "Failed to get read receipts for event: {e}"); - IndexMap::new() - } - } - } - - 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)), - 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 context: {e}"); - None - } - } - } -} - -// 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 -#[async_trait] -trait Decryptor: Copy { - async fn decrypt_event_impl(&self, raw: &Raw) -> Result; -} - -#[async_trait] -impl Decryptor for &room::Common { - async fn decrypt_event_impl(&self, raw: &Raw) -> Result { - self.decrypt_event(raw.cast_ref()).await - } -} - -#[cfg(all(test, feature = "e2e-encryption"))] -#[async_trait] -impl Decryptor for (&OlmMachine, &RoomId) { - async fn decrypt_event_impl(&self, raw: &Raw) -> Result { - let (olm_machine, room_id) = self; - let event = olm_machine.decrypt_room_event(raw.cast_ref(), room_id).await?; - Ok(event) - } -} diff --git a/crates/matrix-sdk-ui/src/timeline/mod.rs b/crates/matrix-sdk-ui/src/timeline/mod.rs index d1fb5f0bd..be88636c0 100644 --- a/crates/matrix-sdk-ui/src/timeline/mod.rs +++ b/crates/matrix-sdk-ui/src/timeline/mod.rs @@ -58,6 +58,7 @@ mod sliding_sync_ext; mod tests; #[cfg(feature = "e2e-encryption")] mod to_device; +mod traits; mod virtual_item; pub(crate) use self::builder::TimelineBuilder; diff --git a/crates/matrix-sdk-ui/src/timeline/read_receipts.rs b/crates/matrix-sdk-ui/src/timeline/read_receipts.rs index e155f8efa..7de92bab1 100644 --- a/crates/matrix-sdk-ui/src/timeline/read_receipts.rs +++ b/crates/matrix-sdk-ui/src/timeline/read_receipts.rs @@ -24,10 +24,8 @@ use ruma::{ use tracing::{error, warn}; use super::{ - compare_events_positions, - event_item::EventTimelineItemKind, - inner::{RoomDataProvider, TimelineInnerState}, - rfind_event_by_id, EventTimelineItem, RelativePosition, TimelineItem, + compare_events_positions, event_item::EventTimelineItemKind, inner::TimelineInnerState, + rfind_event_by_id, traits::RoomDataProvider, EventTimelineItem, RelativePosition, TimelineItem, }; struct FullReceipt<'a> { diff --git a/crates/matrix-sdk-ui/src/timeline/tests/mod.rs b/crates/matrix-sdk-ui/src/timeline/tests/mod.rs index f5e4f0731..7db755289 100644 --- a/crates/matrix-sdk-ui/src/timeline/tests/mod.rs +++ b/crates/matrix-sdk-ui/src/timeline/tests/mod.rs @@ -45,7 +45,7 @@ use ruma::{ }; use serde_json::{json, Value as JsonValue}; -use super::{inner::RoomDataProvider, Profile, TimelineInner, TimelineItem}; +use super::{traits::RoomDataProvider, Profile, TimelineInner, TimelineItem}; mod basic; mod echo; diff --git a/crates/matrix-sdk-ui/src/timeline/traits.rs b/crates/matrix-sdk-ui/src/timeline/traits.rs new file mode 100644 index 000000000..c29a3065d --- /dev/null +++ b/crates/matrix-sdk-ui/src/timeline/traits.rs @@ -0,0 +1,120 @@ +// Copyright 2023 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use async_trait::async_trait; +use indexmap::IndexMap; +use matrix_sdk::room; +#[cfg(feature = "e2e-encryption")] +use matrix_sdk::{deserialized_responses::TimelineEvent, Result}; +use ruma::{ + events::receipt::{Receipt, ReceiptThread, ReceiptType}, + push::{PushConditionRoomCtx, Ruleset}, + EventId, OwnedUserId, UserId, +}; +#[cfg(feature = "e2e-encryption")] +use ruma::{events::AnySyncTimelineEvent, serde::Raw}; +use tracing::{debug, error}; + +use super::Profile; + +#[async_trait] +pub(super) trait RoomDataProvider { + fn own_user_id(&self) -> &UserId; + async fn profile(&self, user_id: &UserId) -> Option; + async fn read_receipts_for_event(&self, event_id: &EventId) -> IndexMap; + async fn push_rules_and_context(&self) -> Option<(Ruleset, PushConditionRoomCtx)>; +} + +#[async_trait] +impl RoomDataProvider for room::Common { + fn own_user_id(&self) -> &UserId { + (**self).own_user_id() + } + + async fn profile(&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 { + display_name: None, + display_name_ambiguous: false, + avatar_url: None, + }), + Ok(None) => None, + Err(e) => { + error!(%user_id, "Failed to getch room member information: {e}"); + None + } + } + } + + async fn read_receipts_for_event(&self, event_id: &EventId) -> IndexMap { + match self.event_receipts(ReceiptType::Read, ReceiptThread::Unthreaded, event_id).await { + Ok(receipts) => receipts.into_iter().collect(), + Err(e) => { + error!(?event_id, "Failed to get read receipts for event: {e}"); + IndexMap::new() + } + } + } + + 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)), + 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 context: {e}"); + None + } + } + } +} + +// 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: Copy { + async fn decrypt_event_impl(&self, raw: &Raw) -> Result; +} + +#[cfg(feature = "e2e-encryption")] +#[async_trait] +impl Decryptor for &room::Common { + async fn decrypt_event_impl(&self, raw: &Raw) -> Result { + self.decrypt_event(raw.cast_ref()).await + } +} + +#[cfg(all(test, feature = "e2e-encryption"))] +#[async_trait] +impl Decryptor for (&matrix_sdk_base::crypto::OlmMachine, &ruma::RoomId) { + async fn decrypt_event_impl(&self, raw: &Raw) -> Result { + let (olm_machine, room_id) = self; + let event = olm_machine.decrypt_room_event(raw.cast_ref(), room_id).await?; + Ok(event) + } +}