From 1fd29f7b6d5fc5659e51ee44b47c5c381a836ca0 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Mon, 13 May 2024 16:56:43 +0200 Subject: [PATCH] room preview: allow passing through a list of servers to discover a room with MSC3266 Fixes #3395.` --- bindings/matrix-sdk-ffi/src/client.rs | 15 +++++++++++++-- crates/matrix-sdk/src/client/mod.rs | 8 ++++++-- crates/matrix-sdk/src/room_preview.rs | 18 +++++++++++++----- .../src/tests/sliding_sync/room.rs | 9 +++++---- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/bindings/matrix-sdk-ffi/src/client.rs b/bindings/matrix-sdk-ffi/src/client.rs index 43653cd5787..347a29f53c9 100644 --- a/bindings/matrix-sdk-ffi/src/client.rs +++ b/bindings/matrix-sdk-ffi/src/client.rs @@ -49,7 +49,7 @@ use ruma::{ room::power_levels::RoomPowerLevelsEventContent, GlobalAccountDataEventType, }, push::{HttpPusherData as RumaHttpPusherData, PushFormat as RumaPushFormat}, - OwnedServerName, RoomAliasId, RoomOrAliasId, + OwnedServerName, RoomAliasId, RoomOrAliasId, ServerName, }; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -772,9 +772,14 @@ impl Client { } /// Get the preview of a room, to interact with it. + /// + /// The (optional) list of `via_servers` must be a list of servers that know + /// about the room and can resolve it, and that may appear as a `via` + /// parameter in e.g. a permalink URL. It can be empty. pub async fn get_room_preview( &self, room_id_or_alias: String, + via_servers: Vec, ) -> Result { let room_id = if let Ok(parsed_room_id) = RoomId::parse(&room_id_or_alias) { parsed_room_id @@ -787,7 +792,13 @@ impl Client { response.room_id }; - let sdk_room_preview = self.inner.get_room_preview(&room_id).await?; + let via_servers = via_servers + .into_iter() + .map(ServerName::parse) + .collect::, _>>() + .context("invalid via server name")?; + + let sdk_room_preview = self.inner.get_room_preview(&room_id, via_servers).await?; Ok(RoomPreview::from_sdk(room_id, sdk_room_preview)) } diff --git a/crates/matrix-sdk/src/client/mod.rs b/crates/matrix-sdk/src/client/mod.rs index 91470963e93..9d58fdc2eed 100644 --- a/crates/matrix-sdk/src/client/mod.rs +++ b/crates/matrix-sdk/src/client/mod.rs @@ -944,11 +944,15 @@ impl Client { /// Gets the preview of a room, whether the current user knows it (because /// they've joined/left/been invited to it) or not. - pub async fn get_room_preview(&self, room_id: &RoomId) -> Result { + pub async fn get_room_preview( + &self, + room_id: &RoomId, + via: Vec, + ) -> Result { if let Some(room) = self.get_room(room_id) { return Ok(RoomPreview::from_known(&room)); } - RoomPreview::from_unknown(self, room_id).await + RoomPreview::from_unknown(self, room_id, via).await } /// Resolve a room alias to a room id and a list of servers which know diff --git a/crates/matrix-sdk/src/room_preview.rs b/crates/matrix-sdk/src/room_preview.rs index a113f80e152..b67461e2d54 100644 --- a/crates/matrix-sdk/src/room_preview.rs +++ b/crates/matrix-sdk/src/room_preview.rs @@ -24,7 +24,7 @@ use ruma::{ events::room::{history_visibility::HistoryVisibility, join_rules::JoinRule}, room::RoomType, space::SpaceRoomJoinRule, - OwnedMxcUri, OwnedRoomAliasId, RoomId, + OwnedMxcUri, OwnedRoomAliasId, OwnedServerName, RoomId, }; use tokio::try_join; use tracing::{instrument, warn}; @@ -108,10 +108,14 @@ impl RoomPreview { } #[instrument(skip(client))] - pub(crate) async fn from_unknown(client: &Client, room_id: &RoomId) -> crate::Result { + pub(crate) async fn from_unknown( + client: &Client, + room_id: &RoomId, + via: Vec, + ) -> crate::Result { // Use the room summary endpoint, if available, as described in // https://github.com/deepbluev7/matrix-doc/blob/room-summaries/proposals/3266-room-summary.md - match Self::from_room_summary(client, room_id).await { + match Self::from_room_summary(client, room_id, via).await { Ok(res) => return Ok(res), Err(err) => { warn!("error when previewing room from the room summary endpoint: {err}"); @@ -132,10 +136,14 @@ impl RoomPreview { /// /// This method is exposed for testing purposes; clients should prefer /// `Client::get_room_preview` in general over this. - pub async fn from_room_summary(client: &Client, room_id: &RoomId) -> crate::Result { + pub async fn from_room_summary( + client: &Client, + room_id: &RoomId, + via: Vec, + ) -> crate::Result { let request = ruma::api::client::room::get_summary::msc3266::Request::new( room_id.to_owned().into(), - Vec::new(), + via, ); let response = client.send(request, None).await?; diff --git a/testing/matrix-sdk-integration-testing/src/tests/sliding_sync/room.rs b/testing/matrix-sdk-integration-testing/src/tests/sliding_sync/room.rs index f167701c7e2..293c505508c 100644 --- a/testing/matrix-sdk-integration-testing/src/tests/sliding_sync/room.rs +++ b/testing/matrix-sdk-integration-testing/src/tests/sliding_sync/room.rs @@ -1118,7 +1118,7 @@ async fn test_room_preview() -> Result<()> { { // Dummy test for `Client::get_room_preview` which may call one or the other // methods. - let preview = alice.get_room_preview(room_id).await.unwrap(); + let preview = alice.get_room_preview(room_id, Vec::new()).await.unwrap(); assert_room_preview(&preview, &room_alias); assert_eq!(preview.state, Some(RoomState::Joined)); } @@ -1169,20 +1169,21 @@ async fn get_room_preview_with_room_summary( public_no_history_room_id: &RoomId, ) { // Alice has joined the room, so they get the full details. - let preview = RoomPreview::from_room_summary(alice, room_id).await.unwrap(); + let preview = RoomPreview::from_room_summary(alice, room_id, Vec::new()).await.unwrap(); assert_room_preview(&preview, room_alias); assert_eq!(preview.state, Some(RoomState::Joined)); // Bob definitely doesn't know about the room, but they can get a preview of the // room too. - let preview = RoomPreview::from_room_summary(bob, room_id).await.unwrap(); + let preview = RoomPreview::from_room_summary(bob, room_id, Vec::new()).await.unwrap(); assert_room_preview(&preview, room_alias); assert!(preview.state.is_none()); // Bob can preview the second room with the room summary (because its join rule // is set to public, or because Alice is a member of that room). - let preview = RoomPreview::from_room_summary(bob, public_no_history_room_id).await.unwrap(); + let preview = + RoomPreview::from_room_summary(bob, public_no_history_room_id, Vec::new()).await.unwrap(); assert_eq!(preview.name.unwrap(), "Alice's Room 2"); assert!(preview.state.is_none()); }