From 00638ba74c2e63cfb09921a6d2db0035f39dd234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= <76261501+zecakeh@users.noreply.github.com> Date: Thu, 2 Feb 2023 13:06:11 +0100 Subject: [PATCH 1/3] feat(sdk): Allow to fetch replied to messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Commaille --- bindings/matrix-sdk-ffi/src/timeline.rs | 2 +- crates/matrix-sdk/src/error.rs | 5 + .../src/room/timeline/event_handler.rs | 10 +- .../src/room/timeline/event_item.rs | 113 ++++++++++-- crates/matrix-sdk/src/room/timeline/inner.rs | 85 ++++++++- crates/matrix-sdk/src/room/timeline/mod.rs | 49 +++++- .../tests/integration/room/timeline.rs | 165 +++++++++++++++++- 7 files changed, 405 insertions(+), 24 deletions(-) diff --git a/bindings/matrix-sdk-ffi/src/timeline.rs b/bindings/matrix-sdk-ffi/src/timeline.rs index a079b44d4..132c79b06 100644 --- a/bindings/matrix-sdk-ffi/src/timeline.rs +++ b/bindings/matrix-sdk-ffi/src/timeline.rs @@ -463,7 +463,7 @@ impl Message { // This event ID string will be replaced by something more useful later. pub fn in_reply_to(&self) -> Option { - self.0.in_reply_to().map(ToString::to_string) + self.0.in_reply_to().map(|r| r.event_id.to_string()) } pub fn is_edited(&self) -> bool { diff --git a/crates/matrix-sdk/src/error.rs b/crates/matrix-sdk/src/error.rs index de68e557b..687c14867 100644 --- a/crates/matrix-sdk/src/error.rs +++ b/crates/matrix-sdk/src/error.rs @@ -241,6 +241,11 @@ pub enum Error { #[error(transparent)] SlidingSync(#[from] crate::sliding_sync::Error), + /// An error occurred in the timeline. + #[cfg(feature = "experimental-timeline")] + #[error(transparent)] + Timeline(#[from] crate::room::timeline::Error), + /// The client is in inconsistent state. This happens when we set a room to /// a specific type, but then cannot get it in this type. #[error("The internal client state is inconsistent.")] diff --git a/crates/matrix-sdk/src/room/timeline/event_handler.rs b/crates/matrix-sdk/src/room/timeline/event_handler.rs index 3ad83729d..d0fbc3442 100644 --- a/crates/matrix-sdk/src/room/timeline/event_handler.rs +++ b/crates/matrix-sdk/src/room/timeline/event_handler.rs @@ -46,8 +46,9 @@ use super::{ MemberProfileChange, OtherState, Profile, RemoteEventTimelineItem, RoomMembershipChange, Sticker, }, - find_read_marker, rfind_event_by_id, rfind_event_item, EventTimelineItem, Message, - ReactionGroup, TimelineInnerMetadata, TimelineItem, TimelineItemContent, VirtualTimelineItem, + find_read_marker, rfind_event_by_id, rfind_event_item, EventTimelineItem, InReplyToDetails, + Message, ReactionGroup, TimelineInnerMetadata, TimelineItem, TimelineItemContent, + VirtualTimelineItem, }; use crate::{events::SyncTimelineEventWithoutContent, room::timeline::MembershipChange}; @@ -821,10 +822,7 @@ impl NewEventTimelineItem { let edited = relations.replace.is_some(); let content = TimelineItemContent::Message(Message { msgtype: c.msgtype, - in_reply_to: c.relates_to.and_then(|rel| match rel { - message::Relation::Reply { in_reply_to } => Some(in_reply_to.event_id), - _ => None, - }), + in_reply_to: c.relates_to.and_then(InReplyToDetails::from_relation), edited, }); diff --git a/crates/matrix-sdk/src/room/timeline/event_item.rs b/crates/matrix-sdk/src/room/timeline/event_item.rs index a78024b1c..cb0ed7c72 100644 --- a/crates/matrix-sdk/src/room/timeline/event_item.rs +++ b/crates/matrix-sdk/src/room/timeline/event_item.rs @@ -15,7 +15,7 @@ use std::{fmt, ops::Deref, sync::Arc}; use indexmap::IndexMap; -use matrix_sdk_base::deserialized_responses::EncryptionInfo; +use matrix_sdk_base::deserialized_responses::{EncryptionInfo, TimelineEvent}; use ruma::{ events::{ policy::rule::{ @@ -33,7 +33,7 @@ use ruma::{ history_visibility::RoomHistoryVisibilityEventContent, join_rules::RoomJoinRulesEventContent, member::{Change, RoomMemberEventContent}, - message::MessageType, + message::{self, MessageType, Relation}, name::RoomNameEventContent, pinned_events::RoomPinnedEventsEventContent, power_levels::RoomPowerLevelsEventContent, @@ -44,15 +44,16 @@ use ruma::{ }, space::{child::SpaceChildEventContent, parent::SpaceParentEventContent}, sticker::StickerEventContent, - AnyFullStateEventContent, AnySyncTimelineEvent, FullStateEventContent, - MessageLikeEventType, StateEventType, + AnyFullStateEventContent, AnyMessageLikeEventContent, AnySyncTimelineEvent, + AnyTimelineEvent, FullStateEventContent, MessageLikeEventType, StateEventType, }, serde::Raw, EventId, MilliSecondsSinceUnixEpoch, OwnedDeviceId, OwnedEventId, OwnedMxcUri, OwnedTransactionId, OwnedUserId, TransactionId, UserId, }; -use crate::Error; +use super::inner::ProfileProvider; +use crate::{Error, Result}; /// An item in the timeline that represents at least one event. /// @@ -295,6 +296,11 @@ impl RemoteEventTimelineItem { Self { reactions, ..self.clone() } } + /// Clone the current event item, and update its `content`. + pub(super) fn with_content(&self, content: TimelineItemContent) -> Self { + Self { content, ..self.clone() } + } + /// Clone the current event item, change its `content` to /// [`TimelineItemContent::RedactedMessage`], and reset its `reactions`. pub(super) fn to_redacted(&self) -> Self { @@ -364,6 +370,9 @@ pub enum TimelineDetails { /// The details are available. Ready(T), + + /// An error occurred when fetching the details. + Error(Arc), } /// The content of an [`EventTimelineItem`]. @@ -436,10 +445,7 @@ impl TimelineItemContent { #[derive(Clone)] pub struct Message { pub(super) msgtype: MessageType, - // TODO: Add everything required to display the replied-to event, plus a - // 'loading' state that is entered at first, until the user requests the - // reply to be loaded. - pub(super) in_reply_to: Option, + pub(super) in_reply_to: Option, pub(super) edited: bool, } @@ -456,15 +462,19 @@ impl Message { self.msgtype.body() } - /// Get the event ID of the event this message is replying to, if any. - pub fn in_reply_to(&self) -> Option<&EventId> { - self.in_reply_to.as_deref() + /// Get the event this message is replying to, if any. + pub fn in_reply_to(&self) -> Option<&InReplyToDetails> { + self.in_reply_to.as_ref() } /// Get the edit state of this message (has been edited: `true` / `false`). pub fn is_edited(&self) -> bool { self.edited } + + pub(super) fn with_in_reply_to(&self, in_reply_to: InReplyToDetails) -> Self { + Self { in_reply_to: Some(in_reply_to), ..self.clone() } + } } impl fmt::Debug for Message { @@ -475,6 +485,85 @@ impl fmt::Debug for Message { } } +/// Details about an event being replied to. +#[derive(Clone, Debug)] +pub struct InReplyToDetails { + /// The ID of the event. + pub event_id: OwnedEventId, + + /// The details of the event. + /// + /// Use [`Timeline::fetch_item_details`] to fetch the data if it is + /// unavailable. The `replies_nesting_level` field in + /// [`TimelineDetailsSettings`] decides if this should be fetched. + /// + /// [`Timeline::fetch_item_details`]: super::Timeline::fetch_item_details + /// [`TimelineDetailsSettings`]: super::TimelineDetailsSettings + pub details: TimelineDetails>, +} + +impl InReplyToDetails { + pub(super) fn from_relation(relation: Relation) -> Option { + match relation { + message::Relation::Reply { in_reply_to } => { + Some(Self { event_id: in_reply_to.event_id, details: TimelineDetails::Unavailable }) + } + _ => None, + } + } +} + +/// An event that is replied to. +#[derive(Clone, Debug)] +pub struct RepliedToEvent { + pub(super) message: Message, + pub(super) sender: OwnedUserId, + pub(super) sender_profile: Profile, +} + +impl RepliedToEvent { + /// Get the message of this event. + pub fn message(&self) -> &Message { + &self.message + } + + /// Get the sender of this event. + pub fn sender(&self) -> &UserId { + &self.sender + } + + /// Get the profile of the sender. + pub fn sender_profile(&self) -> &Profile { + &self.sender_profile + } + + pub(super) async fn try_from_timeline_event( + timeline_event: TimelineEvent, + profile_provider: &P, + ) -> Result { + let event = match timeline_event.event.deserialize() { + Ok(AnyTimelineEvent::MessageLike(event)) => event, + _ => { + return Err(super::Error::UnsupportedEvent.into()); + } + }; + + let Some(AnyMessageLikeEventContent::RoomMessage(c)) = event.original_content() else { + return Err(super::Error::UnsupportedEvent.into()); + }; + + let message = Message { + msgtype: c.msgtype, + in_reply_to: c.relates_to.and_then(InReplyToDetails::from_relation), + edited: event.relations().replace.is_some(), + }; + let sender = event.sender().to_owned(); + let sender_profile = profile_provider.profile(&sender).await; + + Ok(Self { message, sender, sender_profile }) + } +} + /// Metadata about an `m.room.encrypted` event that could not be decrypted. #[derive(Clone, Debug)] pub enum EncryptedMessage { diff --git a/crates/matrix-sdk/src/room/timeline/inner.rs b/crates/matrix-sdk/src/room/timeline/inner.rs index 139408c4e..7d6b726ed 100644 --- a/crates/matrix-sdk/src/room/timeline/inner.rs +++ b/crates/matrix-sdk/src/room/timeline/inner.rs @@ -31,11 +31,13 @@ use super::{ update_read_marker, Flow, HandleEventResult, TimelineEventHandler, TimelineEventKind, TimelineEventMetadata, TimelineItemPosition, }, - rfind_event_item, EventSendState, EventTimelineItem, Profile, TimelineItem, + rfind_event_by_id, rfind_event_item, EventSendState, EventTimelineItem, InReplyToDetails, + Message, Profile, RepliedToEvent, TimelineDetails, TimelineItem, TimelineItemContent, }; use crate::{ events::SyncTimelineEventWithoutContent, room::{self, timeline::event_item::RemoteEventTimelineItem}, + Result, }; #[derive(Debug)] @@ -368,12 +370,93 @@ impl TimelineInner

{ .await; } } + + fn update_event_item(&self, index: usize, event_item: EventTimelineItem) { + self.items.lock_mut().set_cloned(index, Arc::new(TimelineItem::Event(event_item))) + } } impl TimelineInner { pub(super) fn room(&self) -> &room::Common { &self.profile_provider } + + pub(super) async fn fetch_in_reply_to_details( + &self, + index: usize, + mut item: RemoteEventTimelineItem, + ) -> Result { + let TimelineItemContent::Message(message) = item.content.clone() else { + return Ok(item); + }; + let Some(in_reply_to) = message.in_reply_to() else { + return Ok(item); + }; + + let details = + self.fetch_replied_to_event(index, &item, &message, &in_reply_to.event_id).await; + + // We need to be sure to have the latest position of the event as it might have + // changed while waiting for the request. + let (index, _) = rfind_event_by_id(&self.items(), &item.event_id) + .ok_or(super::Error::RemoteEventNotInTimeline)?; + + item = item.with_content(TimelineItemContent::Message(message.with_in_reply_to( + InReplyToDetails { event_id: in_reply_to.event_id.clone(), details }, + ))); + self.update_event_item(index, item.clone().into()); + + Ok(item) + } + + async fn fetch_replied_to_event( + &self, + index: usize, + item: &RemoteEventTimelineItem, + message: &Message, + in_reply_to: &EventId, + ) -> TimelineDetails> { + if let Some((_, item)) = rfind_event_by_id(&self.items(), in_reply_to) { + let details = match item.content() { + TimelineItemContent::Message(message) => { + TimelineDetails::Ready(Box::new(RepliedToEvent { + message: message.clone(), + sender: item.sender().to_owned(), + sender_profile: item.sender_profile().clone(), + })) + } + _ => TimelineDetails::Error(Arc::new(super::Error::UnsupportedEvent.into())), + }; + + return details; + }; + + self.update_event_item( + index, + item.with_content(TimelineItemContent::Message(message.with_in_reply_to( + InReplyToDetails { + event_id: in_reply_to.to_owned(), + details: TimelineDetails::Pending, + }, + ))) + .into(), + ); + + match self.room().event(in_reply_to).await { + Ok(timeline_event) => { + match RepliedToEvent::try_from_timeline_event( + timeline_event, + &self.profile_provider, + ) + .await + { + Ok(event) => TimelineDetails::Ready(Box::new(event)), + Err(e) => TimelineDetails::Error(Arc::new(e)), + } + } + Err(e) => TimelineDetails::Error(Arc::new(e)), + } + } } #[async_trait] diff --git a/crates/matrix-sdk/src/room/timeline/mod.rs b/crates/matrix-sdk/src/room/timeline/mod.rs index 234dd0be4..458c54d5a 100644 --- a/crates/matrix-sdk/src/room/timeline/mod.rs +++ b/crates/matrix-sdk/src/room/timeline/mod.rs @@ -28,6 +28,7 @@ use ruma::{ events::{fully_read::FullyReadEventContent, AnyMessageLikeEventContent}, EventId, MilliSecondsSinceUnixEpoch, TransactionId, }; +use thiserror::Error; use tracing::{error, instrument, warn}; use super::Joined; @@ -50,8 +51,9 @@ mod virtual_item; pub use self::{ event_item::{ AnyOtherFullStateEventContent, BundledReactions, EncryptedMessage, EventSendState, - EventTimelineItem, MemberProfileChange, MembershipChange, Message, OtherState, Profile, - ReactionGroup, RoomMembershipChange, Sticker, TimelineDetails, TimelineItemContent, + EventTimelineItem, InReplyToDetails, MemberProfileChange, MembershipChange, Message, + OtherState, Profile, ReactionGroup, RepliedToEvent, RoomMembershipChange, Sticker, + TimelineDetails, TimelineItemContent, }, pagination::{PaginationOptions, PaginationOutcome}, virtual_item::VirtualTimelineItem, @@ -389,6 +391,36 @@ impl Timeline { }; self.inner.update_event_send_state(&txn_id, send_state); } + + /// Fetch unavailable details about the event with the given ID. + /// + /// This method only works for IDs of [`RemoteEventTimelineItem`]s, to + /// prevent losing details when a local echo is replaced by its remote + /// echo. + /// + /// This method tries to make all the requests it can. If an error is + /// encountered for a given request, it is forwarded with the + /// [`TimelineDetails::Error`] variant. + /// + /// # Arguments + /// + /// * `event_id` - The event ID of the event to fetch details for. + /// + /// # Errors + /// + /// Returns an error if the identifier doesn't match any event with a remote + /// echo in the timeline, or if the event is removed from the timeline + /// before all requests are handled. + #[instrument(skip(self), fields(room_id = ?self.room().room_id()))] + pub async fn fetch_event_details(&self, event_id: &EventId) -> Result<()> { + let (index, item) = rfind_event_by_id(&self.inner.items(), event_id) + .and_then(|(pos, item)| item.as_remote().map(|item| (pos, item.clone()))) + .ok_or(Error::RemoteEventNotInTimeline)?; + + self.inner.fetch_in_reply_to_details(index, item).await?; + + Ok(()) + } } /// A single entry in timeline. @@ -473,3 +505,16 @@ fn rfind_event_by_id<'a>( fn find_read_marker(items: &[Arc]) -> Option { items.iter().rposition(|item| item.is_read_marker()) } + +/// Errors specific to the timeline. +#[derive(Error, Debug)] +#[non_exhaustive] +pub enum Error { + /// The requested event with a remote echo is not in the timeline. + #[error("Event with remote echo not found in timeline")] + RemoteEventNotInTimeline, + + /// The event is currently unsupported for this use case. + #[error("Unsupported event")] + UnsupportedEvent, +} diff --git a/crates/matrix-sdk/tests/integration/room/timeline.rs b/crates/matrix-sdk/tests/integration/room/timeline.rs index 0bb890a24..8aab02552 100644 --- a/crates/matrix-sdk/tests/integration/room/timeline.rs +++ b/crates/matrix-sdk/tests/integration/room/timeline.rs @@ -8,10 +8,11 @@ use futures_util::StreamExt; use matrix_sdk::{ config::SyncSettings, room::timeline::{ - AnyOtherFullStateEventContent, EventSendState, PaginationOptions, TimelineItemContent, - VirtualTimelineItem, + AnyOtherFullStateEventContent, Error as TimelineError, EventSendState, PaginationOptions, + TimelineDetails, TimelineItemContent, VirtualTimelineItem, }, ruma::MilliSecondsSinceUnixEpoch, + Error, }; use matrix_sdk_common::executor::spawn; use matrix_sdk_test::{ @@ -553,3 +554,163 @@ async fn read_marker() { assert_matches!(timeline_stream.next().await, Some(VecDiff::Push { value }) => value); assert_matches!(marker.as_virtual().unwrap(), VirtualTimelineItem::ReadMarker); } + +#[async_test] +async fn in_reply_to_details() { + let room_id = room_id!("!a98sd12bjh:example.org"); + let (client, server) = logged_in_client().await; + let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000)); + + let mut ev_builder = EventBuilder::new(); + ev_builder.add_joined_room(JoinedRoomBuilder::new(room_id)); + + mock_sync(&server, ev_builder.build_json_sync_response(), None).await; + let _response = client.sync_once(sync_settings.clone()).await.unwrap(); + server.reset().await; + + let room = client.get_room(room_id).unwrap(); + let timeline = room.timeline().await; + let mut timeline_stream = timeline.signal().to_stream(); + + // The event doesn't exist. + assert_matches!( + timeline.fetch_event_details(event_id!("$fakeevent")).await, + Err(Error::Timeline(TimelineError::RemoteEventNotInTimeline)) + ); + + ev_builder.add_joined_room( + JoinedRoomBuilder::new(room_id) + .add_timeline_event(TimelineTestEvent::Custom(json!({ + "content": { + "body": "hello", + "msgtype": "m.text", + }, + "event_id": "$event1", + "origin_server_ts": 152037280, + "sender": "@alice:example.org", + "type": "m.room.message", + }))) + .add_timeline_event(TimelineTestEvent::Custom(json!({ + "content": { + "body": "hello to you too", + "msgtype": "m.text", + "m.relates_to": { + "m.in_reply_to": { + "event_id": "$event1", + }, + }, + }, + "event_id": "$event2", + "origin_server_ts": 152045456, + "sender": "@bob:example.org", + "type": "m.room.message", + }))), + ); + + mock_sync(&server, ev_builder.build_json_sync_response(), None).await; + let _response = client.sync_once(sync_settings.clone()).await.unwrap(); + server.reset().await; + + let _day_divider = + assert_matches!(timeline_stream.next().await, Some(VecDiff::Push { value }) => value); + let first = + assert_matches!(timeline_stream.next().await, Some(VecDiff::Push { value }) => value); + assert_matches!(first.as_event().unwrap().content(), TimelineItemContent::Message(_)); + let second = + assert_matches!(timeline_stream.next().await, Some(VecDiff::Push { value }) => value); + let second_event = second.as_event().unwrap().as_remote().unwrap(); + let message = + assert_matches!(&second_event.content, TimelineItemContent::Message(message) => message); + let in_reply_to = message.in_reply_to().unwrap(); + assert_eq!(in_reply_to.event_id, event_id!("$event1")); + assert_matches!(in_reply_to.details, TimelineDetails::Unavailable); + + // Fetch details locally first. + timeline.fetch_event_details(&second_event.event_id).await.unwrap(); + + let second = assert_matches!(timeline_stream.next().await, Some(VecDiff::UpdateAt { index: 2, value }) => value); + let message = assert_matches!(second.as_event().unwrap().content(), TimelineItemContent::Message(message) => message); + assert_matches!(message.in_reply_to().unwrap().details, TimelineDetails::Ready(_)); + + ev_builder.add_joined_room(JoinedRoomBuilder::new(room_id).add_timeline_event( + TimelineTestEvent::Custom(json!({ + "content": { + "body": "you were right", + "msgtype": "m.text", + "m.relates_to": { + "m.in_reply_to": { + "event_id": "$remoteevent", + }, + }, + }, + "event_id": "$event3", + "origin_server_ts": 152046694, + "sender": "@bob:example.org", + "type": "m.room.message", + })), + )); + + mock_sync(&server, ev_builder.build_json_sync_response(), None).await; + let _response = client.sync_once(sync_settings.clone()).await.unwrap(); + server.reset().await; + + let third = + assert_matches!(timeline_stream.next().await, Some(VecDiff::Push { value }) => value); + let third_event = third.as_event().unwrap().as_remote().unwrap(); + let message = + assert_matches!(&third_event.content, TimelineItemContent::Message(message) => message); + let in_reply_to = message.in_reply_to().unwrap(); + assert_eq!(in_reply_to.event_id, event_id!("$remoteevent")); + assert_matches!(in_reply_to.details, TimelineDetails::Unavailable); + + Mock::given(method("GET")) + .and(path_regex(r"^/_matrix/client/r0/rooms/.*/event/\$remoteevent")) + .and(header("authorization", "Bearer 1234")) + .respond_with(ResponseTemplate::new(404).set_body_json(json!({ + "errcode": "M_NOT_FOUND", + "error": "Event not found.", + }))) + .expect(1) + .mount(&server) + .await; + + // Fetch details remotely if we can't find them locally. + timeline.fetch_event_details(&third_event.event_id).await.unwrap(); + server.reset().await; + + let third = assert_matches!(timeline_stream.next().await, Some(VecDiff::UpdateAt { index: 3, value }) => value); + let message = assert_matches!(third.as_event().unwrap().content(), TimelineItemContent::Message(message) => message); + assert_matches!(message.in_reply_to().unwrap().details, TimelineDetails::Pending); + + let third = assert_matches!(timeline_stream.next().await, Some(VecDiff::UpdateAt { index: 3, value }) => value); + let message = assert_matches!(third.as_event().unwrap().content(), TimelineItemContent::Message(message) => message); + assert_matches!(message.in_reply_to().unwrap().details, TimelineDetails::Error(_)); + + Mock::given(method("GET")) + .and(path_regex(r"^/_matrix/client/r0/rooms/.*/event/\$remoteevent")) + .and(header("authorization", "Bearer 1234")) + .respond_with(ResponseTemplate::new(200).set_body_json(json!({ + "content": { + "body": "Alice is gonna arrive soon", + "msgtype": "m.text", + }, + "room_id": room_id, + "event_id": "$event0", + "origin_server_ts": 152024004, + "sender": "@admin:example.org", + "type": "m.room.message", + }))) + .expect(1) + .mount(&server) + .await; + + timeline.fetch_event_details(&third_event.event_id).await.unwrap(); + + let third = assert_matches!(timeline_stream.next().await, Some(VecDiff::UpdateAt { index: 3, value }) => value); + let message = assert_matches!(third.as_event().unwrap().content(), TimelineItemContent::Message(message) => message); + assert_matches!(message.in_reply_to().unwrap().details, TimelineDetails::Pending); + + let third = assert_matches!(timeline_stream.next().await, Some(VecDiff::UpdateAt { index: 3, value }) => value); + let message = assert_matches!(third.as_event().unwrap().content(), TimelineItemContent::Message(message) => message); + assert_matches!(message.in_reply_to().unwrap().details, TimelineDetails::Ready(_)); +} From a9ba2dd54608e548c8027cdee51c666e5dbe73a4 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 2 Feb 2023 13:25:36 +0100 Subject: [PATCH 2/3] feat(sdk): `SlidingSync::get_room` now takes a ref to `OwnedRoomId`. Before this patch, `SlidingSync::get_room` was taking ownership of an `OwnedRoomId`, to only use it as a reference. Thus, calling this method was creating useless clones. This patch updates `SlidingSync::get_room` to receive a reference to `OwnedRoomId`. --- bindings/matrix-sdk-ffi/src/sliding_sync.rs | 3 ++- crates/matrix-sdk/src/sliding_sync.rs | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/bindings/matrix-sdk-ffi/src/sliding_sync.rs b/bindings/matrix-sdk-ffi/src/sliding_sync.rs index 1c3d76bd4..1e3c749ff 100644 --- a/bindings/matrix-sdk-ffi/src/sliding_sync.rs +++ b/bindings/matrix-sdk-ffi/src/sliding_sync.rs @@ -642,7 +642,8 @@ impl SlidingSync { pub fn get_room(&self, room_id: String) -> anyhow::Result>> { let runner = self.inner.clone(); - Ok(self.inner.get_room(OwnedRoomId::try_from(room_id)?).map(|inner| { + + Ok(self.inner.get_room(&OwnedRoomId::try_from(room_id)?).map(|inner| { Arc::new(SlidingSyncRoom { inner, runner, diff --git a/crates/matrix-sdk/src/sliding_sync.rs b/crates/matrix-sdk/src/sliding_sync.rs index bf91446d1..f6aa77bab 100644 --- a/crates/matrix-sdk/src/sliding_sync.rs +++ b/crates/matrix-sdk/src/sliding_sync.rs @@ -814,8 +814,8 @@ impl SlidingSync { } /// Lookup a specific room - pub fn get_room(&self, room_id: OwnedRoomId) -> Option { - self.rooms.lock_ref().get(&room_id).cloned() + pub fn get_room(&self, room_id: &OwnedRoomId) -> Option { + self.rooms.lock_ref().get(room_id).cloned() } fn update_to_device_since(&self, since: String) { From ae8a8c6cc3d7c9eb00afe547dc436299a88be122 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 2 Feb 2023 13:36:32 +0100 Subject: [PATCH 3/3] feat(sdk): `SldingSync::get_room` takes a `&RoomId`. --- bindings/matrix-sdk-ffi/src/sliding_sync.rs | 4 ++-- crates/matrix-sdk/src/sliding_sync.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bindings/matrix-sdk-ffi/src/sliding_sync.rs b/bindings/matrix-sdk-ffi/src/sliding_sync.rs index 1e3c749ff..408e93745 100644 --- a/bindings/matrix-sdk-ffi/src/sliding_sync.rs +++ b/bindings/matrix-sdk-ffi/src/sliding_sync.rs @@ -13,7 +13,7 @@ use matrix_sdk::ruma::{ v4::RoomSubscription as RumaRoomSubscription, UnreadNotificationsCount as RumaUnreadNotificationsCount, }, - assign, IdParseError, OwnedRoomId, UInt, + assign, IdParseError, OwnedRoomId, RoomId, UInt, }; pub use matrix_sdk::{ room::timeline::Timeline, ruma::api::client::sync::sync_events::v4::SyncRequestListFilters, @@ -643,7 +643,7 @@ impl SlidingSync { pub fn get_room(&self, room_id: String) -> anyhow::Result>> { let runner = self.inner.clone(); - Ok(self.inner.get_room(&OwnedRoomId::try_from(room_id)?).map(|inner| { + Ok(self.inner.get_room(<&RoomId>::try_from(room_id.as_str())?).map(|inner| { Arc::new(SlidingSyncRoom { inner, runner, diff --git a/crates/matrix-sdk/src/sliding_sync.rs b/crates/matrix-sdk/src/sliding_sync.rs index f6aa77bab..56d693a71 100644 --- a/crates/matrix-sdk/src/sliding_sync.rs +++ b/crates/matrix-sdk/src/sliding_sync.rs @@ -814,7 +814,7 @@ impl SlidingSync { } /// Lookup a specific room - pub fn get_room(&self, room_id: &OwnedRoomId) -> Option { + pub fn get_room(&self, room_id: &RoomId) -> Option { self.rooms.lock_ref().get(room_id).cloned() }