mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-02-14 17:44:12 -05:00
room preview: rejigger public API to pass a RoomOrAliasId in place of a RoomId to get_room_preview
This commit is contained in:
@@ -771,36 +771,48 @@ impl Client {
|
||||
Ok(response.into())
|
||||
}
|
||||
|
||||
/// Get the preview of a room, to interact with it.
|
||||
/// Given a room id, get the preview of a room, to interact with it.
|
||||
///
|
||||
/// The (optional) list of `via_servers` must be a list of servers that know
|
||||
/// The 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(
|
||||
/// parameter in e.g. a permalink URL. This list can be empty.
|
||||
pub async fn get_room_preview_from_room_id(
|
||||
&self,
|
||||
room_id_or_alias: String,
|
||||
room_id: 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
|
||||
} else {
|
||||
// Try to resolve it as an alias.
|
||||
let Ok(room_alias) = RoomAliasId::parse(&room_id_or_alias) else {
|
||||
return Err(anyhow!("room_id_or_alias is neither a room id or an alias").into());
|
||||
};
|
||||
let response = self.inner.resolve_room_alias(&room_alias).await?;
|
||||
response.room_id
|
||||
};
|
||||
let room_id = RoomId::parse(&room_id).context("room_id is not a valid room id")?;
|
||||
|
||||
let via_servers = via_servers
|
||||
.into_iter()
|
||||
.map(ServerName::parse)
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.context("invalid via server name")?;
|
||||
.context("at least one `via` server name is invalid")?;
|
||||
|
||||
let sdk_room_preview = self.inner.get_room_preview(&room_id, via_servers).await?;
|
||||
// The `into()` call below doesn't work if I do `(&room_id).into()`, so I let
|
||||
// rustc win that one fight.
|
||||
let room_id: &RoomId = &room_id;
|
||||
|
||||
Ok(RoomPreview::from_sdk(room_id, sdk_room_preview))
|
||||
let sdk_room_preview = self.inner.get_room_preview(room_id.into(), via_servers).await?;
|
||||
|
||||
Ok(RoomPreview::from_sdk(sdk_room_preview))
|
||||
}
|
||||
|
||||
/// Given a room alias, get the preview of a room, to interact with it.
|
||||
pub async fn get_room_preview_from_room_alias(
|
||||
&self,
|
||||
room_alias: String,
|
||||
) -> Result<RoomPreview, ClientError> {
|
||||
let room_alias =
|
||||
RoomAliasId::parse(&room_alias).context("room_alias is not a valid room alias")?;
|
||||
|
||||
// The `into()` call below doesn't work if I do `(&room_id).into()`, so I let
|
||||
// rustc win that one fight.
|
||||
let room_alias: &RoomAliasId = &room_alias;
|
||||
|
||||
let sdk_room_preview = self.inner.get_room_preview(room_alias.into(), Vec::new()).await?;
|
||||
|
||||
Ok(RoomPreview::from_sdk(sdk_room_preview))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use matrix_sdk::{room_preview::RoomPreview as SdkRoomPreview, RoomState};
|
||||
use ruma::{space::SpaceRoomJoinRule, OwnedRoomId};
|
||||
use ruma::space::SpaceRoomJoinRule;
|
||||
|
||||
/// The preview of a room, be it invited/joined/left, or not.
|
||||
#[derive(uniffi::Record)]
|
||||
@@ -31,9 +31,9 @@ pub struct RoomPreview {
|
||||
}
|
||||
|
||||
impl RoomPreview {
|
||||
pub(crate) fn from_sdk(room_id: OwnedRoomId, preview: SdkRoomPreview) -> Self {
|
||||
pub(crate) fn from_sdk(preview: SdkRoomPreview) -> Self {
|
||||
Self {
|
||||
room_id: room_id.to_string(),
|
||||
room_id: preview.room_id.to_string(),
|
||||
canonical_alias: preview.canonical_alias.map(|alias| alias.to_string()),
|
||||
name: preview.name,
|
||||
topic: preview.topic,
|
||||
|
||||
@@ -946,13 +946,19 @@ impl Client {
|
||||
/// they've joined/left/been invited to it) or not.
|
||||
pub async fn get_room_preview(
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
room_or_alias_id: &RoomOrAliasId,
|
||||
via: Vec<OwnedServerName>,
|
||||
) -> Result<RoomPreview> {
|
||||
if let Some(room) = self.get_room(room_id) {
|
||||
let room_id = match <&RoomId>::try_from(room_or_alias_id) {
|
||||
Ok(room_id) => room_id.to_owned(),
|
||||
Err(alias) => self.resolve_room_alias(alias).await?.room_id,
|
||||
};
|
||||
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
return Ok(RoomPreview::from_known(&room));
|
||||
}
|
||||
RoomPreview::from_unknown(self, room_id, via).await
|
||||
|
||||
RoomPreview::from_unknown(self, room_id, room_or_alias_id, via).await
|
||||
}
|
||||
|
||||
/// Resolve a room alias to a room id and a list of servers which know
|
||||
|
||||
@@ -24,7 +24,7 @@ use ruma::{
|
||||
events::room::{history_visibility::HistoryVisibility, join_rules::JoinRule},
|
||||
room::RoomType,
|
||||
space::SpaceRoomJoinRule,
|
||||
OwnedMxcUri, OwnedRoomAliasId, OwnedServerName, RoomId,
|
||||
OwnedMxcUri, OwnedRoomAliasId, OwnedRoomId, OwnedServerName, RoomId, RoomOrAliasId,
|
||||
};
|
||||
use tokio::try_join;
|
||||
use tracing::{instrument, warn};
|
||||
@@ -34,6 +34,12 @@ use crate::{Client, Room};
|
||||
/// The preview of a room, be it invited/joined/left, or not.
|
||||
#[derive(Debug)]
|
||||
pub struct RoomPreview {
|
||||
/// The actual room id for this room.
|
||||
///
|
||||
/// Remember the room preview can be fetched from a room alias id, so we
|
||||
/// might not know ahead of time what the room id is.
|
||||
pub room_id: OwnedRoomId,
|
||||
|
||||
/// The canonical alias for the room.
|
||||
pub canonical_alias: Option<OwnedRoomAliasId>,
|
||||
|
||||
@@ -76,6 +82,7 @@ impl RoomPreview {
|
||||
state: Option<RoomState>,
|
||||
) -> Self {
|
||||
RoomPreview {
|
||||
room_id: room_info.room_id().to_owned(),
|
||||
canonical_alias: room_info.canonical_alias().map(ToOwned::to_owned),
|
||||
name: room_info.name().map(ToOwned::to_owned),
|
||||
topic: room_info.topic().map(ToOwned::to_owned),
|
||||
@@ -110,12 +117,13 @@ impl RoomPreview {
|
||||
#[instrument(skip(client))]
|
||||
pub(crate) async fn from_unknown(
|
||||
client: &Client,
|
||||
room_id: &RoomId,
|
||||
room_id: OwnedRoomId,
|
||||
room_or_alias_id: &RoomOrAliasId,
|
||||
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, via).await {
|
||||
match Self::from_room_summary(client, room_id.clone(), room_or_alias_id, via).await {
|
||||
Ok(res) => return Ok(res),
|
||||
Err(err) => {
|
||||
warn!("error when previewing room from the room summary endpoint: {err}");
|
||||
@@ -127,7 +135,7 @@ impl RoomPreview {
|
||||
// - then use a public room filter set to this room id
|
||||
|
||||
// Resort to using the room state endpoint, as well as the joined members one.
|
||||
Self::from_state_events(client, room_id).await
|
||||
Self::from_state_events(client, &room_id).await
|
||||
}
|
||||
|
||||
/// Get a [`RoomPreview`] using MSC3266, if available on the remote server.
|
||||
@@ -138,11 +146,12 @@ impl RoomPreview {
|
||||
/// `Client::get_room_preview` in general over this.
|
||||
pub async fn from_room_summary(
|
||||
client: &Client,
|
||||
room_id: &RoomId,
|
||||
room_id: OwnedRoomId,
|
||||
room_or_alias_id: &RoomOrAliasId,
|
||||
via: Vec<OwnedServerName>,
|
||||
) -> crate::Result<Self> {
|
||||
let request = ruma::api::client::room::get_summary::msc3266::Request::new(
|
||||
room_id.to_owned().into(),
|
||||
room_or_alias_id.to_owned(),
|
||||
via,
|
||||
);
|
||||
|
||||
@@ -151,13 +160,14 @@ impl RoomPreview {
|
||||
// The server returns a `Left` room state for rooms the user has not joined. Be
|
||||
// more precise than that, and set it to `None` if we haven't joined
|
||||
// that room.
|
||||
let state = if client.get_room(room_id).is_none() {
|
||||
let state = if client.get_room(&room_id).is_none() {
|
||||
None
|
||||
} else {
|
||||
response.membership.map(|membership| RoomState::from(&membership))
|
||||
};
|
||||
|
||||
Ok(RoomPreview {
|
||||
room_id,
|
||||
canonical_alias: response.canonical_alias,
|
||||
name: response.name,
|
||||
topic: response.topic,
|
||||
|
||||
@@ -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, Vec::new()).await.unwrap();
|
||||
let preview = alice.get_room_preview(room_id.into(), Vec::new()).await.unwrap();
|
||||
assert_room_preview(&preview, &room_alias);
|
||||
assert_eq!(preview.state, Some(RoomState::Joined));
|
||||
}
|
||||
@@ -1169,21 +1169,47 @@ 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, Vec::new()).await.unwrap();
|
||||
let preview =
|
||||
RoomPreview::from_room_summary(alice, room_id.to_owned(), room_id.into(), Vec::new())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_room_preview(&preview, room_alias);
|
||||
assert_eq!(preview.state, Some(RoomState::Joined));
|
||||
|
||||
// The preview also works when using the room alias parameter.
|
||||
let full_alias = format!("#{room_alias}:{}", alice.user_id().unwrap().server_name());
|
||||
let preview = RoomPreview::from_room_summary(
|
||||
alice,
|
||||
room_id.to_owned(),
|
||||
<_>::try_from(full_alias.as_str()).unwrap(),
|
||||
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, Vec::new()).await.unwrap();
|
||||
let preview =
|
||||
RoomPreview::from_room_summary(bob, room_id.to_owned(), room_id.into(), 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, Vec::new()).await.unwrap();
|
||||
let preview = RoomPreview::from_room_summary(
|
||||
bob,
|
||||
public_no_history_room_id.to_owned(),
|
||||
public_no_history_room_id.into(),
|
||||
Vec::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(preview.name.unwrap(), "Alice's Room 2");
|
||||
assert!(preview.state.is_none());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user