Skip to content

Commit

Permalink
room preview: allow passing through a list of servers to discover a r…
Browse files Browse the repository at this point in the history
…oom with MSC3266

Fixes #3395.`
  • Loading branch information
bnjbvr committed May 16, 2024
1 parent c8f6fe4 commit 1fd29f7
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 13 deletions.
15 changes: 13 additions & 2 deletions bindings/matrix-sdk-ffi/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<String>,
) -> Result<RoomPreview, ClientError> {
let room_id = if let Ok(parsed_room_id) = RoomId::parse(&room_id_or_alias) {
parsed_room_id
Expand All @@ -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::<Result<Vec<_>, _>>()
.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))
}
Expand Down
8 changes: 6 additions & 2 deletions crates/matrix-sdk/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<RoomPreview> {
pub async fn get_room_preview(
&self,
room_id: &RoomId,
via: Vec<OwnedServerName>,
) -> Result<RoomPreview> {
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
Expand Down
18 changes: 13 additions & 5 deletions crates/matrix-sdk/src/room_preview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -108,10 +108,14 @@ impl RoomPreview {
}

#[instrument(skip(client))]
pub(crate) async fn from_unknown(client: &Client, room_id: &RoomId) -> crate::Result<Self> {
pub(crate) async fn from_unknown(
client: &Client,
room_id: &RoomId,
via: Vec<OwnedServerName>,
) -> crate::Result<Self> {
// 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}");
Expand All @@ -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<Self> {
pub async fn from_room_summary(
client: &Client,
room_id: &RoomId,
via: Vec<OwnedServerName>,
) -> crate::Result<Self> {
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?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down Expand Up @@ -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());
}

0 comments on commit 1fd29f7

Please sign in to comment.