ui: Move timeline-internal traits into separate module

This commit is contained in:
Jonas Platte 2023-06-06 11:57:05 +02:00 committed by Jonas Platte
parent 7552f4f72a
commit 2bcc70beb9
6 changed files with 133 additions and 103 deletions

View File

@ -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].

View File

@ -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<Profile>;
async fn read_receipts_for_event(&self, event_id: &EventId) -> IndexMap<OwnedUserId, Receipt>;
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<Profile> {
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<OwnedUserId, Receipt> {
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<AnySyncTimelineEvent>) -> Result<TimelineEvent>;
}
#[async_trait]
impl Decryptor for &room::Common {
async fn decrypt_event_impl(&self, raw: &Raw<AnySyncTimelineEvent>) -> Result<TimelineEvent> {
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<AnySyncTimelineEvent>) -> Result<TimelineEvent> {
let (olm_machine, room_id) = self;
let event = olm_machine.decrypt_room_event(raw.cast_ref(), room_id).await?;
Ok(event)
}
}

View File

@ -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;

View File

@ -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> {

View File

@ -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;

View File

@ -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<Profile>;
async fn read_receipts_for_event(&self, event_id: &EventId) -> IndexMap<OwnedUserId, Receipt>;
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<Profile> {
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<OwnedUserId, Receipt> {
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<AnySyncTimelineEvent>) -> Result<TimelineEvent>;
}
#[cfg(feature = "e2e-encryption")]
#[async_trait]
impl Decryptor for &room::Common {
async fn decrypt_event_impl(&self, raw: &Raw<AnySyncTimelineEvent>) -> Result<TimelineEvent> {
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<AnySyncTimelineEvent>) -> Result<TimelineEvent> {
let (olm_machine, room_id) = self;
let event = olm_machine.decrypt_room_event(raw.cast_ref(), room_id).await?;
Ok(event)
}
}