Remove Room enum

This commit is contained in:
Jonas Platte
2023-07-17 17:06:27 +02:00
committed by Jonas Platte
parent 85f66b1f96
commit 67ef9c3fa0
23 changed files with 250 additions and 395 deletions
+1 -2
View File
@@ -3,7 +3,6 @@ use std::sync::{Arc, RwLock};
use anyhow::{anyhow, Context};
use matrix_sdk::{
media::{MediaFileHandle as SdkMediaFileHandle, MediaFormat, MediaRequest, MediaThumbnailSize},
room::Room as SdkRoom,
ruma::{
api::client::{
account::whoami,
@@ -537,7 +536,7 @@ impl Client {
pub fn get_dm_room(&self, user_id: String) -> Result<Option<Arc<Room>>, ClientError> {
let user_id = UserId::parse(user_id)?;
let sdk_room = self.inner.get_dm_room(&user_id).map(SdkRoom::Joined);
let sdk_room = self.inner.get_dm_room(&user_id);
let dm = sdk_room.map(|room| Arc::new(Room::new(room)));
Ok(dm)
}
+33 -134
View File
@@ -7,7 +7,7 @@ use matrix_sdk::{
AttachmentConfig, AttachmentInfo, BaseAudioInfo, BaseFileInfo, BaseImageInfo,
BaseThumbnailInfo, BaseVideoInfo, Thumbnail,
},
room::{Receipts, Room as SdkRoom},
room::{Common as SdkRoom, Receipts},
ruma::{
api::client::{receipt::create_receipt::v3::ReceiptType, room::report_content},
events::{
@@ -21,7 +21,7 @@ use matrix_sdk::{
},
EventId, UserId,
},
RoomMemberships,
RoomMemberships, RoomState,
};
use matrix_sdk_ui::timeline::{BackPaginationStatus, RoomExt, Timeline};
use mime::Mime;
@@ -111,24 +111,25 @@ impl Room {
}
pub fn membership(&self) -> Membership {
match &self.inner {
SdkRoom::Invited(_) => Membership::Invited,
SdkRoom::Joined(_) => Membership::Joined,
SdkRoom::Left(_) => Membership::Left,
match self.inner.state() {
RoomState::Invited => Membership::Invited,
RoomState::Joined => Membership::Joined,
RoomState::Left => Membership::Left,
}
}
pub fn inviter(&self) -> Option<Arc<RoomMember>> {
match &self.inner {
SdkRoom::Invited(i) => RUNTIME.block_on(async move {
i.invite_details()
if self.inner.state() == RoomState::Invited {
RUNTIME.block_on(async move {
self.inner
.invite_details()
.await
.ok()
.and_then(|a| a.inviter)
.map(|m| Arc::new(RoomMember::new(m)))
}),
SdkRoom::Joined(_) => None,
SdkRoom::Left(_) => None,
})
} else {
None
}
}
@@ -297,19 +298,11 @@ impl Room {
}
pub fn send_read_receipt(&self, event_id: String) -> Result<(), ClientError> {
let room = match &self.inner {
SdkRoom::Joined(j) => j.clone(),
_ => {
return Err(
anyhow!("Can't send read receipts to room that isn't in joined state").into()
)
}
};
let event_id = EventId::parse(event_id)?;
RUNTIME.block_on(async move {
room.send_single_receipt(ReceiptType::Read, ReceiptThread::Unthreaded, event_id)
self.inner
.send_single_receipt(ReceiptType::Read, ReceiptThread::Unthreaded, event_id)
.await?;
Ok(())
})
@@ -320,15 +313,6 @@ impl Room {
fully_read_event_id: String,
read_receipt_event_id: Option<String>,
) -> Result<(), ClientError> {
let room = match &self.inner {
SdkRoom::Joined(j) => j.clone(),
_ => {
return Err(
anyhow!("Can't send read markers to room that isn't in joined state").into()
)
}
};
let fully_read =
EventId::parse(fully_read_event_id).context("parsing fully read event ID")?;
let read_receipt = read_receipt_event_id
@@ -339,7 +323,7 @@ impl Room {
Receipts::new().fully_read_marker(fully_read).public_read_receipt(read_receipt);
RUNTIME.block_on(async move {
room.send_multiple_receipts(receipts).await?;
self.inner.send_multiple_receipts(receipts).await?;
Ok(())
})
}
@@ -364,11 +348,6 @@ impl Room {
in_reply_to_event_id: String,
txn_id: Option<String>,
) -> Result<(), ClientError> {
let room = match &self.inner {
SdkRoom::Joined(j) => j.clone(),
_ => return Err(anyhow!("Can't send to a room that isn't in joined state").into()),
};
let timeline = match &*RUNTIME.block_on(self.timeline.read()) {
Some(t) => Arc::clone(t),
None => return Err(anyhow!("Timeline not set up, can't send message").into()),
@@ -378,7 +357,8 @@ impl Room {
in_reply_to_event_id.as_str().try_into().context("Failed to create EventId.")?;
let reply_content = RUNTIME.block_on(async move {
let timeline_event = room.event(event_id).await.context("Couldn't find event.")?;
let timeline_event =
self.inner.event(event_id).await.context("Couldn't find event.")?;
let event_content = timeline_event
.event
@@ -406,11 +386,6 @@ impl Room {
original_event_id: String,
txn_id: Option<String>,
) -> Result<(), ClientError> {
let room = match &self.inner {
SdkRoom::Joined(j) => j.clone(),
_ => return Err(anyhow!("Can't send to a room that isn't in joined state").into()),
};
let timeline = match &*RUNTIME.block_on(self.timeline.read()) {
Some(t) => Arc::clone(t),
None => return Err(anyhow!("Timeline not set up, can't send message").into()),
@@ -420,7 +395,8 @@ impl Room {
original_event_id.as_str().try_into().context("Failed to create EventId.")?;
let edited_content = RUNTIME.block_on(async move {
let timeline_event = room.event(event_id).await.context("Couldn't find event.")?;
let timeline_event =
self.inner.event(event_id).await.context("Couldn't find event.")?;
let event_content = timeline_event
.event
@@ -463,14 +439,9 @@ impl Room {
reason: Option<String>,
txn_id: Option<String>,
) -> Result<(), ClientError> {
let room = match &self.inner {
SdkRoom::Joined(j) => j.clone(),
_ => return Err(anyhow!("Can't redact in a room that isn't in joined state").into()),
};
RUNTIME.block_on(async move {
let event_id = EventId::parse(event_id)?;
room.redact(&event_id, reason.as_deref(), txn_id.map(Into::into)).await?;
self.inner.redact(&event_id, reason.as_deref(), txn_id.map(Into::into)).await?;
Ok(())
})
}
@@ -570,30 +541,16 @@ impl Room {
/// Sets a new name to the room.
pub fn set_name(&self, name: Option<String>) -> Result<(), ClientError> {
let room = match &self.inner {
SdkRoom::Joined(j) => j.clone(),
_ => {
return Err(anyhow!("Can't set a name in a room that isn't in joined state").into())
}
};
RUNTIME.block_on(async move {
room.set_name(name).await?;
self.inner.set_name(name).await?;
Ok(())
})
}
/// Sets a new topic in the room.
pub fn set_topic(&self, topic: String) -> Result<(), ClientError> {
let room = match &self.inner {
SdkRoom::Joined(j) => j.clone(),
_ => {
return Err(anyhow!("Can't set a topic in a room that isn't in joined state").into())
}
};
RUNTIME.block_on(async move {
room.set_room_topic(&topic).await?;
self.inner.set_room_topic(&topic).await?;
Ok(())
})
}
@@ -611,50 +568,27 @@ impl Room {
/// * `data` - The raw data that will be uploaded to the homeserver's
/// content repository
pub fn upload_avatar(&self, mime_type: String, data: Vec<u8>) -> Result<(), ClientError> {
let room = match &self.inner {
SdkRoom::Joined(j) => j.clone(),
_ => {
return Err(
anyhow!("Can't set a avatar in a room that isn't in joined state").into()
)
}
};
RUNTIME.block_on(async move {
let mime: Mime = mime_type.parse()?;
// TODO: We could add an FFI ImageInfo struct in the future
room.upload_avatar(&mime, data, None).await?;
self.inner.upload_avatar(&mime, data, None).await?;
Ok(())
})
}
/// Removes the current room avatar
pub fn remove_avatar(&self) -> Result<(), ClientError> {
let room = match &self.inner {
SdkRoom::Joined(j) => j.clone(),
_ => {
return Err(
anyhow!("Can't remove a avatar in a room that isn't in joined state").into()
)
}
};
RUNTIME.block_on(async move {
room.remove_avatar().await?;
self.inner.remove_avatar().await?;
Ok(())
})
}
pub fn invite_user_by_id(&self, user_id: String) -> Result<(), ClientError> {
let room = match &self.inner {
SdkRoom::Joined(joined_room) => joined_room.clone(),
_ => return Err(anyhow!("Can't invite user to room that isn't in joined state").into()),
};
RUNTIME.block_on(async move {
let user = <&UserId>::try_from(user_id.as_str())
.context("Could not create user from string")?;
room.invite_user_by_id(user).await?;
self.inner.invite_user_by_id(user).await?;
Ok(())
})
}
@@ -869,43 +803,23 @@ impl Room {
}
pub async fn can_user_redact(&self, user_id: String) -> Result<bool, ClientError> {
let room = match &self.inner {
SdkRoom::Joined(j) => j.clone(),
_ => return Err(anyhow!("Can't check permissions for non joined rooms").into()),
};
let user_id = UserId::parse(&user_id)?;
Ok(room.can_user_redact(&user_id).await?)
Ok(self.inner.can_user_redact(&user_id).await?)
}
pub async fn can_user_ban(&self, user_id: String) -> Result<bool, ClientError> {
let room = match &self.inner {
SdkRoom::Joined(j) => j.clone(),
_ => return Err(anyhow!("Can't check permissions for non joined rooms").into()),
};
let user_id = UserId::parse(&user_id)?;
Ok(room.can_user_ban(&user_id).await?)
Ok(self.inner.can_user_ban(&user_id).await?)
}
pub async fn can_user_invite(&self, user_id: String) -> Result<bool, ClientError> {
let room = match &self.inner {
SdkRoom::Joined(j) => j.clone(),
_ => return Err(anyhow!("Can't check permissions for non joined rooms").into()),
};
let user_id = UserId::parse(&user_id)?;
Ok(room.can_user_invite(&user_id).await?)
Ok(self.inner.can_user_invite(&user_id).await?)
}
pub async fn can_user_kick(&self, user_id: String) -> Result<bool, ClientError> {
let room = match &self.inner {
SdkRoom::Joined(j) => j.clone(),
_ => return Err(anyhow!("Can't check permissions for non joined rooms").into()),
};
let user_id = UserId::parse(&user_id)?;
Ok(room.can_user_kick(&user_id).await?)
Ok(self.inner.can_user_kick(&user_id).await?)
}
pub async fn can_user_send_state(
@@ -913,13 +827,8 @@ impl Room {
user_id: String,
state_event: StateEventType,
) -> Result<bool, ClientError> {
let room = match &self.inner {
SdkRoom::Joined(j) => j.clone(),
_ => return Err(anyhow!("Can't check permissions for non joined rooms").into()),
};
let user_id = UserId::parse(&user_id)?;
Ok(room.can_user_send_state(&user_id, state_event.into()).await?)
Ok(self.inner.can_user_send_state(&user_id, state_event.into()).await?)
}
pub async fn can_user_send_message(
@@ -927,26 +836,16 @@ impl Room {
user_id: String,
message: MessageLikeEventType,
) -> Result<bool, ClientError> {
let room = match &self.inner {
SdkRoom::Joined(j) => j.clone(),
_ => return Err(anyhow!("Can't check permissions for non joined rooms").into()),
};
let user_id = UserId::parse(&user_id)?;
Ok(room.can_user_send_message(&user_id, message.into()).await?)
Ok(self.inner.can_user_send_message(&user_id, message.into()).await?)
}
pub async fn can_user_trigger_room_notification(
&self,
user_id: String,
) -> Result<bool, ClientError> {
let room = match &self.inner {
SdkRoom::Joined(j) => j.clone(),
_ => return Err(anyhow!("Can't check permissions for non joined rooms").into()),
};
let user_id = UserId::parse(&user_id)?;
Ok(room.can_user_trigger_room_notification(&user_id).await?)
Ok(self.inner.can_user_trigger_room_notification(&user_id).await?)
}
pub fn own_user_id(&self) -> String {
@@ -14,8 +14,8 @@
use std::time::Duration;
use matrix_sdk::{room::Room, Client};
use matrix_sdk_base::StoreError;
use matrix_sdk::Client;
use matrix_sdk_base::{RoomState, StoreError};
use ruma::{events::AnySyncTimelineEvent, EventId, RoomId};
use thiserror::Error;
@@ -140,8 +140,8 @@ impl NotificationClient {
}
}
let sender = match &room {
Room::Invited(invited) => invited.invite_details().await?.inviter,
let sender = match room.state() {
RoomState::Invited => room.invite_details().await?.inviter,
_ => room.get_member(raw_event.sender()).await?,
};
@@ -46,7 +46,7 @@ struct RoomInner {
sliding_sync_room: SlidingSyncRoom,
/// The underlying client room.
room: matrix_sdk::room::Room,
room: matrix_sdk::room::Common,
/// The timeline of the room.
timeline: AsyncOnceCell<Arc<Timeline>>,
@@ -89,8 +89,8 @@ impl Room {
})
}
/// Get the underlying [`matrix_sdk::room::Room`].
pub fn inner_room(&self) -> &matrix_sdk::room::Room {
/// Get the underlying [`matrix_sdk::room::Common`].
pub fn inner_room(&self) -> &matrix_sdk::room::Common {
&self.inner.room
}
+4 -6
View File
@@ -6,7 +6,7 @@ use std::{
};
use eyeball::{SharedObservable, Subscriber};
use matrix_sdk::{attachment::AttachmentConfig, room::Room, TransmissionProgress};
use matrix_sdk::{attachment::AttachmentConfig, TransmissionProgress};
use mime::Mime;
use super::{Error, Timeline};
@@ -47,10 +47,6 @@ impl<'a> IntoFuture for SendAttachment<'a> {
fn into_future(self) -> Self::IntoFuture {
let Self { timeline, url, mime_type, config, send_progress } = self;
Box::pin(async move {
let Room::Joined(room) = Room::from(timeline.room().clone()) else {
return Err(Error::RoomNotJoined);
};
let body = Path::new(&url)
.file_name()
.ok_or(Error::InvalidAttachmentFileName)?
@@ -58,7 +54,9 @@ impl<'a> IntoFuture for SendAttachment<'a> {
.expect("path was created from UTF-8 string, hence filename part is UTF-8 too");
let data = fs::read(&url).map_err(|_| Error::InvalidAttachmentData)?;
room.send_attachment(body, &mime_type, data, config)
timeline
.room()
.send_attachment(body, &mime_type, data, config)
.with_send_progress_observable(send_progress)
.await
.map_err(|_| Error::FailedSendingAttachment)?;
+13 -27
View File
@@ -27,9 +27,10 @@ use matrix_sdk::{
attachment::AttachmentConfig,
event_handler::EventHandlerHandle,
executor::JoinHandle,
room::{self, MessagesOptions, Receipts, Room},
room::{self, MessagesOptions, Receipts},
Client, Result,
};
use matrix_sdk_base::RoomState;
use mime::Mime;
use pin_project_lite::pin_project;
use ruma::{
@@ -135,13 +136,6 @@ impl Timeline {
self.inner.room()
}
fn joined_room(&self) -> Result<room::Common, Error> {
match Room::from(self.room().clone()) {
Room::Joined(room) => Ok(room),
_ => Err(Error::RoomNotJoined),
}
}
/// Clear all timeline items, and reset pagination parameters.
#[cfg(feature = "experimental-sliding-sync")]
pub async fn clear(&self) {
@@ -408,13 +402,13 @@ impl Timeline {
/// Redact a reaction event from the homeserver
async fn redact_reaction(&self, event_id: &EventId) -> ReactionToggleResult {
let room = self.room();
if room.state() != RoomState::Joined {
return ReactionToggleResult::RedactFailure { event_id: event_id.to_owned() };
}
let txn_id = TransactionId::new();
let no_reason = RoomRedactionEventContent::default();
let room = self.joined_room();
let Ok(room) = room else {
return ReactionToggleResult::RedactFailure { event_id: event_id.to_owned() };
};
let response = room.redact(event_id, no_reason.reason.as_deref(), Some(txn_id)).await;
@@ -430,8 +424,10 @@ impl Timeline {
annotation: &Annotation,
txn_id: OwnedTransactionId,
) -> ReactionToggleResult {
let room = self.joined_room();
let Ok(room) = room else { return ReactionToggleResult::AddFailure { txn_id } };
let room = self.room();
if room.state() != RoomState::Joined {
return ReactionToggleResult::AddFailure { txn_id };
}
let event_content =
AnyMessageLikeEventContent::Reaction(ReactionEventContent::from(annotation.clone()));
@@ -605,12 +601,7 @@ impl Timeline {
return Ok(());
}
let Room::Joined(room) = Room::from(self.room().clone()) else {
// FIXME: Probably not exactly right
return Err(matrix_sdk::Error::InconsistentState);
};
room.send_single_receipt(receipt_type, thread, event_id).await
self.room().send_single_receipt(receipt_type, thread, event_id).await
}
/// Send the given receipts.
@@ -659,12 +650,7 @@ impl Timeline {
}
}
let Room::Joined(room) = Room::from(self.room().clone()) else {
// FIXME: Probably not exactly right
return Err(matrix_sdk::Error::InconsistentState);
};
room.send_multiple_receipts(receipts).await
self.room().send_multiple_receipts(receipts).await
}
}
+15 -17
View File
@@ -24,8 +24,9 @@ use std::{
use futures_util::future::Either;
use matrix_sdk::{
executor::{spawn, JoinError, JoinHandle},
room::{self, Room},
room,
};
use matrix_sdk_base::RoomState;
use ruma::{events::AnyMessageLikeEventContent, OwnedTransactionId};
use tokio::{select, sync::mpsc::Receiver};
use tracing::{debug, error, info, instrument, trace, warn};
@@ -103,22 +104,19 @@ async fn handle_message(
timeline_inner: &TimelineInner,
) {
if queue.is_empty() && send_task.is_idle() {
match Room::from(room) {
Room::Joined(room) => {
send_task.start(room, timeline_inner.clone(), msg);
}
_ => {
info!("Refusing to send message, room is not joined");
timeline_inner
.update_event_send_state(
&msg.txn_id,
EventSendState::SendingFailed {
// FIXME: Probably not exactly right
error: Arc::new(matrix_sdk::Error::InconsistentState),
},
)
.await;
}
if room.state() == RoomState::Joined {
send_task.start(room, timeline_inner.clone(), msg);
} else {
info!("Refusing to send message, room is not joined");
timeline_inner
.update_event_send_state(
&msg.txn_id,
EventSendState::SendingFailed {
// FIXME: Probably not exactly right
error: Arc::new(matrix_sdk::Error::InconsistentState),
},
)
.await;
}
} else {
queue.push_back(msg);
+19 -21
View File
@@ -104,10 +104,10 @@ type NotificationHandlerFut = Pin<Box<dyn Future<Output = ()>>>;
#[cfg(not(target_arch = "wasm32"))]
type NotificationHandlerFn =
Box<dyn Fn(Notification, room::Room, Client) -> NotificationHandlerFut + Send + Sync>;
Box<dyn Fn(Notification, room::Common, Client) -> NotificationHandlerFut + Send + Sync>;
#[cfg(target_arch = "wasm32")]
type NotificationHandlerFn =
Box<dyn Fn(Notification, room::Room, Client) -> NotificationHandlerFut>;
Box<dyn Fn(Notification, room::Common, Client) -> NotificationHandlerFut>;
/// Enum controlling if a loop running callbacks should continue or abort.
///
@@ -477,8 +477,8 @@ impl Client {
/// the event handler being skipped and an error being logged. The following
/// context argument types are only available for a subset of event types:
///
/// * [`Room`][room::Room] is only available for room-specific events, i.e.
/// not for events like global account data events or presence events.
/// * [`room::Common`] is only available for room-specific events, i.e. not
/// for events like global account data events or presence events.
///
/// You can provide custom context via
/// [`add_event_handler_context`](Client::add_event_handler_context) and
@@ -495,7 +495,7 @@ impl Client {
/// use matrix_sdk::{
/// deserialized_responses::EncryptionInfo,
/// event_handler::Ctx,
/// room::Room,
/// room::Common,
/// ruma::{
/// events::{
/// macros::EventContent,
@@ -518,12 +518,12 @@ impl Client {
/// # .unwrap();
/// #
/// client.add_event_handler(
/// |ev: SyncRoomMessageEvent, room: Room, client: Client| async move {
/// |ev: SyncRoomMessageEvent, room: Common, client: Client| async move {
/// // Common usage: Room event plus room and client.
/// },
/// );
/// client.add_event_handler(
/// |ev: SyncRoomMessageEvent, room: Room, encryption_info: Option<EncryptionInfo>| {
/// |ev: SyncRoomMessageEvent, room: Common, encryption_info: Option<EncryptionInfo>| {
/// async move {
/// // An `Option<EncryptionInfo>` parameter lets you distinguish between
/// // unencrypted events and events that were decrypted by the SDK.
@@ -531,7 +531,7 @@ impl Client {
/// },
/// );
/// client.add_event_handler(
/// |ev: SyncRoomMessageEvent, room: Room, push_actions: Vec<Action>| {
/// |ev: SyncRoomMessageEvent, room: Common, push_actions: Vec<Action>| {
/// async move {
/// // A `Vec<Action>` parameter allows you to know which push actions
/// // are applicable for an event. For example, an event with
@@ -570,7 +570,7 @@ impl Client {
/// expires_at: MilliSecondsSinceUnixEpoch,
/// }
///
/// client.add_event_handler(|ev: SyncTokenEvent, room: Room| async move {
/// client.add_event_handler(|ev: SyncTokenEvent, room: Common| async move {
/// todo!("Display the token");
/// });
///
@@ -699,7 +699,7 @@ impl Client {
///
/// ```
/// use matrix_sdk::{
/// event_handler::Ctx, room::Room,
/// event_handler::Ctx, room::Common,
/// ruma::events::room::message::SyncRoomMessageEvent,
/// };
/// # #[derive(Clone)]
@@ -719,7 +719,7 @@ impl Client {
///
/// client.add_event_handler_context(my_gui_handle.clone());
/// client.add_event_handler(
/// |ev: SyncRoomMessageEvent, room: Room, gui_handle: Ctx<SomeType>| {
/// |ev: SyncRoomMessageEvent, room: Common, gui_handle: Ctx<SomeType>| {
/// async move {
/// // gui_handle.send(DisplayMessage { message: ev });
/// }
@@ -738,10 +738,10 @@ impl Client {
///
/// Similar to [`Client::add_event_handler`], but only allows functions
/// or closures with exactly the three arguments [`Notification`],
/// [`room::Room`], [`Client`] for now.
/// [`room::Common`], [`Client`] for now.
pub async fn register_notification_handler<H, Fut>(&self, handler: H) -> &Self
where
H: Fn(Notification, room::Room, Client) -> Fut
H: Fn(Notification, room::Common, Client) -> Fut
+ SendOutsideWasm
+ SyncOutsideWasm
+ 'static,
@@ -778,20 +778,20 @@ impl Client {
/// Get all the rooms the client knows about.
///
/// This will return the list of joined, invited, and left rooms.
pub fn rooms(&self) -> Vec<room::Room> {
pub fn rooms(&self) -> Vec<room::Common> {
self.base_client()
.get_rooms()
.into_iter()
.map(|room| room::Common::new(self.clone(), room).into())
.map(|room| room::Common::new(self.clone(), room))
.collect()
}
/// Get all the rooms the client knows about, filtered by room state.
pub fn rooms_filtered(&self, filter: RoomStateFilter) -> Vec<room::Room> {
pub fn rooms_filtered(&self, filter: RoomStateFilter) -> Vec<room::Common> {
self.base_client()
.get_rooms_filtered(filter)
.into_iter()
.map(|room| room::Common::new(self.clone(), room).into())
.map(|room| room::Common::new(self.clone(), room))
.collect()
}
@@ -827,10 +827,8 @@ impl Client {
/// # Arguments
///
/// `room_id` - The unique id of the room that should be fetched.
pub fn get_room(&self, room_id: &RoomId) -> Option<room::Room> {
self.base_client()
.get_room(room_id)
.map(|room| room::Common::new(self.clone(), room).into())
pub fn get_room(&self, room_id: &RoomId) -> Option<room::Common> {
self.base_client().get_room(room_id).map(|room| room::Common::new(self.clone(), room))
}
/// Resolve a room alias to a room id and a list of servers which know
@@ -49,7 +49,7 @@ impl EventHandlerContext for EventHandlerHandle {
/// Trying to use it in the event handler for another event, for example a
/// global account data or presence event, will result in the event handler
/// being skipped and an error getting logged.
impl EventHandlerContext for room::Room {
impl EventHandlerContext for room::Common {
fn from_data(data: &EventHandlerData<'_>) -> Option<Self> {
data.room.clone()
}
+11 -11
View File
@@ -231,7 +231,7 @@ where
#[derive(Debug)]
pub struct EventHandlerData<'a> {
client: Client,
room: Option<room::Room>,
room: Option<room::Common>,
raw: &'a RawJsonValue,
encryption_info: Option<&'a EncryptionInfo>,
push_actions: &'a [Action],
@@ -328,7 +328,7 @@ impl Client {
pub(crate) async fn handle_sync_events<T>(
&self,
kind: HandlerKind,
room: Option<&room::Room>,
room: Option<&room::Common>,
events: &[Raw<T>],
) -> serde_json::Result<()> {
#[derive(Deserialize)]
@@ -347,7 +347,7 @@ impl Client {
pub(crate) async fn handle_sync_state_events(
&self,
room: Option<&room::Room>,
room: Option<&room::Common>,
state_events: &[Raw<AnySyncStateEvent>],
) -> serde_json::Result<()> {
#[derive(Deserialize)]
@@ -375,7 +375,7 @@ impl Client {
pub(crate) async fn handle_sync_timeline_events(
&self,
room: Option<&room::Room>,
room: Option<&room::Common>,
timeline_events: &[SyncTimelineEvent],
) -> serde_json::Result<()> {
#[derive(Deserialize)]
@@ -441,7 +441,7 @@ impl Client {
#[instrument(skip_all, fields(?event_kind, ?event_type, room_id))]
async fn call_event_handlers(
&self,
room: Option<&room::Room>,
room: Option<&room::Common>,
raw: &RawJsonValue,
event_kind: HandlerKind,
event_type: &str,
@@ -571,7 +571,7 @@ mod tests {
use crate::{
event_handler::Ctx,
room::Room,
room,
test_utils::{logged_in_client, no_retry_test_client},
Client,
};
@@ -587,7 +587,7 @@ mod tests {
client.add_event_handler({
let member_count = member_count.clone();
move |_ev: OriginalSyncRoomMemberEvent, _room: Room| {
move |_ev: OriginalSyncRoomMemberEvent, _room: room::Common| {
member_count.fetch_add(1, SeqCst);
future::ready(())
}
@@ -601,7 +601,7 @@ mod tests {
});
client.add_event_handler({
let power_levels_count = power_levels_count.clone();
move |_ev: OriginalSyncRoomPowerLevelsEvent, _client: Client, _room: Room| {
move |_ev: OriginalSyncRoomPowerLevelsEvent, _client: Client, _room: room::Common| {
power_levels_count.fetch_add(1, SeqCst);
future::ready(())
}
@@ -683,14 +683,14 @@ mod tests {
// Room event handlers for member events in both rooms
client.add_room_event_handler(room_id_a, {
let member_count = member_count.clone();
move |_ev: OriginalSyncRoomMemberEvent, _room: Room| {
move |_ev: OriginalSyncRoomMemberEvent, _room: room::Common| {
member_count.fetch_add(1, SeqCst);
future::ready(())
}
});
client.add_room_event_handler(room_id_b, {
let member_count = member_count.clone();
move |_ev: OriginalSyncRoomMemberEvent, _room: Room| {
move |_ev: OriginalSyncRoomMemberEvent, _room: room::Common| {
member_count.fetch_add(1, SeqCst);
future::ready(())
}
@@ -699,7 +699,7 @@ mod tests {
// Power levels event handlers for member events in room A
client.add_room_event_handler(room_id_a, {
let power_levels_count = power_levels_count.clone();
move |_ev: OriginalSyncRoomPowerLevelsEvent, _client: Client, _room: Room| {
move |_ev: OriginalSyncRoomPowerLevelsEvent, _client: Client, _room: room::Common| {
power_levels_count.fetch_add(1, SeqCst);
future::ready(())
}
-35
View File
@@ -1,7 +1,5 @@
//! High-level room API
use std::ops::Deref;
use crate::RoomState;
mod common;
@@ -15,36 +13,3 @@ pub use self::{
member::RoomMember,
messages::{Messages, MessagesOptions},
};
/// An enum that abstracts over the different states a room can be in.
#[derive(Debug, Clone)]
pub enum Room {
/// The room in the `join` state.
Joined(Common),
/// The room in the `left` state.
Left(Common),
/// The room in the `invited` state.
Invited(Common),
}
impl Deref for Room {
type Target = Common;
fn deref(&self) -> &Self::Target {
match self {
Self::Joined(room) => room,
Self::Left(room) => room,
Self::Invited(room) => room,
}
}
}
impl From<Common> for Room {
fn from(room: Common) -> Self {
match room.state() {
RoomState::Joined => Self::Joined(room),
RoomState::Left => Self::Left(room),
RoomState::Invited => Self::Invited(room),
}
}
}
+1 -1
View File
@@ -240,7 +240,7 @@ impl SlidingSyncRoom {
#[derive(Debug)]
struct SlidingSyncRoomInner {
/// The client, used to fetch [`Room`][crate::room::Room].
/// The client, used to fetch [`room::Common`][crate::room::Common].
client: Client,
/// The room ID.
+3 -3
View File
@@ -195,7 +195,7 @@ impl Client {
};
self.send_room_update(room_id, || RoomUpdate::Joined {
room: (*room).clone(),
room: room.clone(),
updates: room_info.clone(),
});
@@ -222,7 +222,7 @@ impl Client {
};
self.send_room_update(room_id, || RoomUpdate::Left {
room: (*room).clone(),
room: room.clone(),
updates: room_info.clone(),
});
@@ -241,7 +241,7 @@ impl Client {
};
self.send_room_update(room_id, || RoomUpdate::Invited {
room: (*room).clone(),
room: room.clone(),
updates: room_info.clone(),
});
+5 -3
View File
@@ -3,7 +3,7 @@ use std::env;
use matrix_sdk_appservice::{
matrix_sdk::{
event_handler::Ctx,
room::Room,
room,
ruma::{
events::room::member::{MembershipState, OriginalSyncRoomMemberEvent},
UserId,
@@ -16,7 +16,7 @@ use tracing::trace;
pub async fn handle_room_member(
appservice: AppService,
room: Room,
room: room::Common,
event: OriginalSyncRoomMemberEvent,
) -> Result<()> {
if !appservice.user_id_is_in_namespace(&event.state_key) {
@@ -68,7 +68,9 @@ pub async fn main() -> anyhow::Result<()> {
user.add_event_handler_context(appservice.clone());
user.add_event_handler(
move |event: OriginalSyncRoomMemberEvent, room: Room, Ctx(appservice): Ctx<AppService>| {
move |event: OriginalSyncRoomMemberEvent,
room: room::Common,
Ctx(appservice): Ctx<AppService>| {
handle_room_member(appservice, room, event)
},
);
+26 -24
View File
@@ -1,41 +1,43 @@
use std::{env, process::exit};
use matrix_sdk::{
config::SyncSettings, room::Room, ruma::events::room::member::StrippedRoomMemberEvent, Client,
config::SyncSettings, room, ruma::events::room::member::StrippedRoomMemberEvent, Client,
RoomState,
};
use tokio::time::{sleep, Duration};
async fn on_stripped_state_member(
room_member: StrippedRoomMemberEvent,
client: Client,
room: Room,
room: room::Common,
) {
if room_member.state_key != client.user_id().unwrap() {
return;
}
if let Room::Invited(room) = room {
tokio::spawn(async move {
println!("Autojoining room {}", room.room_id());
let mut delay = 2;
while let Err(err) = room.join().await {
// retry autojoin due to synapse sending invites, before the
// invited user can join for more information see
// https://github.com/matrix-org/synapse/issues/4345
eprintln!("Failed to join room {} ({err:?}), retrying in {delay}s", room.room_id());
sleep(Duration::from_secs(delay)).await;
delay *= 2;
if delay > 3600 {
eprintln!("Can't join room {} ({err:?})", room.room_id());
break;
}
}
println!("Successfully joined room {}", room.room_id());
});
if room.state() != RoomState::Joined {
return;
}
tokio::spawn(async move {
println!("Autojoining room {}", room.room_id());
let mut delay = 2;
while let Err(err) = room.join().await {
// retry autojoin due to synapse sending invites, before the
// invited user can join for more information see
// https://github.com/matrix-org/synapse/issues/4345
eprintln!("Failed to join room {} ({err:?}), retrying in {delay}s", room.room_id());
sleep(Duration::from_secs(delay)).await;
delay *= 2;
if delay > 3600 {
eprintln!("Can't join room {} ({err:?})", room.room_id());
break;
}
}
println!("Successfully joined room {}", room.room_id());
});
}
async fn login_and_sync(
+17 -16
View File
@@ -2,31 +2,32 @@ use std::{env, process::exit};
use matrix_sdk::{
config::SyncSettings,
room::Room,
room,
ruma::events::room::message::{
MessageType, OriginalSyncRoomMessageEvent, RoomMessageEventContent,
},
Client,
Client, RoomState,
};
async fn on_room_message(event: OriginalSyncRoomMessageEvent, room: Room) {
if let Room::Joined(room) = room {
let MessageType::Text(text_content) = event.content.msgtype else {
return;
};
async fn on_room_message(event: OriginalSyncRoomMessageEvent, room: room::Common) {
if room.state() != RoomState::Joined {
return;
}
let MessageType::Text(text_content) = event.content.msgtype else {
return;
};
if text_content.body.contains("!party") {
let content = RoomMessageEventContent::text_plain("🎉🎊🥳 let's PARTY!! 🥳🎊🎉");
if text_content.body.contains("!party") {
let content = RoomMessageEventContent::text_plain("🎉🎊🥳 let's PARTY!! 🥳🎊🎉");
println!("sending");
println!("sending");
// send our message to the room we found the "!party" command in
// the last parameter is an optional transaction id which we don't
// care about.
room.send(content, None).await.unwrap();
// send our message to the room we found the "!party" command in
// the last parameter is an optional transaction id which we don't
// care about.
room.send(content, None).await.unwrap();
println!("message sent");
}
println!("message sent");
}
}
+36 -34
View File
@@ -13,7 +13,7 @@ use std::{env, process::exit};
use matrix_sdk::{
config::SyncSettings,
room::Room,
room,
ruma::{
events::{
macros::EventContent,
@@ -24,7 +24,7 @@ use matrix_sdk::{
},
OwnedEventId,
},
Client,
Client, RoomState,
};
use serde::{Deserialize, Serialize};
use tokio::time::{sleep, Duration};
@@ -50,8 +50,10 @@ pub struct AckEventContent {
// use that for `on_ping_event`.
// we want to start the ping-ack-flow on "!ping" messages.
async fn on_regular_room_message(event: OriginalSyncRoomMessageEvent, room: Room) {
let Room::Joined(room) = room else { return };
async fn on_regular_room_message(event: OriginalSyncRoomMessageEvent, room: room::Common) {
if room.state() != RoomState::Joined {
return;
}
let MessageType::Text(text_content) = event.content.msgtype else { return };
if text_content.body.contains("!ping") {
@@ -64,17 +66,19 @@ async fn on_regular_room_message(event: OriginalSyncRoomMessageEvent, room: Room
}
// call this on any PingEvent we receive
async fn on_ping_event(event: SyncPingEvent, room: Room) {
if let Room::Joined(room) = room {
let event_id = event.event_id().to_owned();
// Send an ack with the event_id of the ping, as our 'protocol' demands
let content = AckEventContent { ping_id: event_id };
println!("sending ack");
room.send(content, None).await.unwrap();
println!("ack sent");
async fn on_ping_event(event: SyncPingEvent, room: room::Common) {
if room.state() != RoomState::Joined {
return;
}
let event_id = event.event_id().to_owned();
// Send an ack with the event_id of the ping, as our 'protocol' demands
let content = AckEventContent { ping_id: event_id };
println!("sending ack");
room.send(content, None).await.unwrap();
println!("ack sent");
}
// once logged in, this is called where we configure the handlers
@@ -120,36 +124,34 @@ async fn login_and_sync(
async fn on_stripped_state_member(
room_member: StrippedRoomMemberEvent,
client: Client,
room: Room,
room: room::Common,
) {
if room_member.state_key != client.user_id().unwrap() {
// the invite we've seen isn't for us, but for someone else. ignore
return;
}
// looks like the room is an invited room, let's attempt to join then
if let Room::Invited(room) = room {
tokio::spawn(async move {
println!("Autojoining room {}", room.room_id());
let mut delay = 2;
tokio::spawn(async move {
println!("Autojoining room {}", room.room_id());
let mut delay = 2;
while let Err(err) = room.join().await {
// retry autojoin due to synapse sending invites, before the
// invited user can join for more information see
// https://github.com/matrix-org/synapse/issues/4345
eprintln!("Failed to join room {} ({err:?}), retrying in {delay}s", room.room_id());
while let Err(err) = room.join().await {
// retry autojoin due to synapse sending invites, before the
// invited user can join for more information see
// https://github.com/matrix-org/synapse/issues/4345
eprintln!("Failed to join room {} ({err:?}), retrying in {delay}s", room.room_id());
sleep(Duration::from_secs(delay)).await;
delay *= 2;
sleep(Duration::from_secs(delay)).await;
delay *= 2;
if delay > 3600 {
eprintln!("Can't join room {} ({err:?})", room.room_id());
break;
}
if delay > 3600 {
eprintln!("Can't join room {} ({err:?})", room.room_id());
break;
}
println!("Successfully joined room {}", room.room_id());
});
}
}
println!("Successfully joined room {}", room.room_id());
});
}
#[tokio::main]
+27 -28
View File
@@ -14,12 +14,12 @@ use std::{env, process::exit};
use matrix_sdk::{
config::SyncSettings,
room::Room,
room,
ruma::events::room::{
member::StrippedRoomMemberEvent,
message::{MessageType, OriginalSyncRoomMessageEvent, RoomMessageEventContent},
},
Client,
Client, RoomState,
};
use tokio::time::{sleep, Duration};
@@ -108,40 +108,37 @@ async fn login_and_sync(
async fn on_stripped_state_member(
room_member: StrippedRoomMemberEvent,
client: Client,
room: Room,
room: room::Common,
) {
if room_member.state_key != client.user_id().unwrap() {
// the invite we've seen isn't for us, but for someone else. ignore
return;
}
// looks like the room is an invited room, let's attempt to join then
if let Room::Invited(room) = room {
// The event handlers are called before the next sync begins, but
// methods that change the state of a room (joining, leaving a room)
// wait for the sync to return the new room state so we need to spawn
// a new task for them.
tokio::spawn(async move {
println!("Autojoining room {}", room.room_id());
let mut delay = 2;
// The event handlers are called before the next sync begins, but
// methods that change the state of a room (joining, leaving a room)
// wait for the sync to return the new room state so we need to spawn
// a new task for them.
tokio::spawn(async move {
println!("Autojoining room {}", room.room_id());
let mut delay = 2;
while let Err(err) = room.join().await {
// retry autojoin due to synapse sending invites, before the
// invited user can join for more information see
// https://github.com/matrix-org/synapse/issues/4345
eprintln!("Failed to join room {} ({err:?}), retrying in {delay}s", room.room_id());
while let Err(err) = room.join().await {
// retry autojoin due to synapse sending invites, before the
// invited user can join for more information see
// https://github.com/matrix-org/synapse/issues/4345
eprintln!("Failed to join room {} ({err:?}), retrying in {delay}s", room.room_id());
sleep(Duration::from_secs(delay)).await;
delay *= 2;
sleep(Duration::from_secs(delay)).await;
delay *= 2;
if delay > 3600 {
eprintln!("Can't join room {} ({err:?})", room.room_id());
break;
}
if delay > 3600 {
eprintln!("Can't join room {} ({err:?})", room.room_id());
break;
}
println!("Successfully joined room {}", room.room_id());
});
}
}
println!("Successfully joined room {}", room.room_id());
});
}
// This fn is called whenever we see a new room message event. You notice that
@@ -149,10 +146,12 @@ async fn on_stripped_state_member(
// handler lies only in their input parameters. However, that is enough for the
// rust-sdk to figure out which one to call one and only do so, when
// the parameters are available.
async fn on_room_message(event: OriginalSyncRoomMessageEvent, room: Room) {
async fn on_room_message(event: OriginalSyncRoomMessageEvent, room: room::Common) {
// First, we need to unpack the message: We only want messages from rooms we are
// still in and that are regular text messages - ignoring everything else.
let Room::Joined(room) = room else { return };
if room.state() != RoomState::Joined {
return;
}
let MessageType::Text(text_content) = event.content.msgtype else { return };
// here comes the actual "logic": when the bot see's a `!party` in the message,
+6 -4
View File
@@ -4,14 +4,16 @@ use matrix_sdk::{
self,
attachment::AttachmentConfig,
config::SyncSettings,
room::Room,
room,
ruma::events::room::message::{MessageType, OriginalSyncRoomMessageEvent},
Client,
Client, RoomState,
};
use url::Url;
async fn on_room_message(event: OriginalSyncRoomMessageEvent, room: Room, image: Vec<u8>) {
let Room::Joined(room) = room else { return };
async fn on_room_message(event: OriginalSyncRoomMessageEvent, room: room::Common, image: Vec<u8>) {
if room.state() != RoomState::Joined {
return;
}
let MessageType::Text(text_content) = event.content.msgtype else { return };
if text_content.body.contains("!image") {
+6 -6
View File
@@ -8,12 +8,12 @@ use anyhow::anyhow;
use matrix_sdk::{
self,
config::SyncSettings,
room::Room,
room,
ruma::{
api::client::session::get_login_types::v3::{IdentityProvider, LoginType},
events::room::message::{MessageType, OriginalSyncRoomMessageEvent},
},
Client,
Client, RoomState,
};
use url::Url;
@@ -60,7 +60,7 @@ async fn login_and_sync(homeserver_url: String) -> anyhow::Result<()> {
choices.extend(sso.identity_providers.into_iter().map(LoginChoice::SsoIdp))
}
}
// This is used for SSO, so it's not a separate choice.
// This is used for SSO, so it's not a separate choice.
LoginType::Token(_) |
// This is only for application services, ignore it here.
LoginType::ApplicationService(_) => {},
@@ -208,11 +208,11 @@ async fn login_with_sso(client: &Client, idp: Option<&IdentityProvider>) -> anyh
}
/// Handle room messages by logging them.
async fn on_room_message(event: OriginalSyncRoomMessageEvent, room: Room) {
async fn on_room_message(event: OriginalSyncRoomMessageEvent, room: room::Common) {
// We only want to listen to joined rooms.
let Room::Joined(room) = room else {
if room.state() != RoomState::Joined {
return;
};
}
// We only want to log text messages.
let MessageType::Text(msgtype) = &event.content.msgtype else {
+6 -4
View File
@@ -5,12 +5,12 @@ use std::{
use matrix_sdk::{
config::SyncSettings,
room::Room,
room,
ruma::{
api::client::filter::FilterDefinition,
events::room::message::{MessageType, OriginalSyncRoomMessageEvent},
},
AuthSession, Client, Error, LoopCtrl,
AuthSession, Client, Error, LoopCtrl, RoomState,
};
use rand::{distributions::Alphanumeric, thread_rng, Rng};
use serde::{Deserialize, Serialize};
@@ -290,9 +290,11 @@ async fn persist_sync_token(session_file: &Path, sync_token: String) -> anyhow::
}
/// Handle room messages.
async fn on_room_message(event: OriginalSyncRoomMessageEvent, room: Room) {
async fn on_room_message(event: OriginalSyncRoomMessageEvent, room: room::Common) {
// We only want to log text messages in joined rooms.
let Room::Joined(room) = room else { return };
if room.state() != RoomState::Joined {
return;
}
let MessageType::Text(text_content) = &event.content.msgtype else { return };
let room_name = match room.display_name().await {
@@ -1,7 +1,7 @@
use anyhow::{bail, Result};
use anyhow::{ensure, Result};
use assign::assign;
use matrix_sdk::{
room::Room, ruma::api::client::room::create_room::v3::Request as CreateRoomRequest,
ruma::api::client::room::create_room::v3::Request as CreateRoomRequest, RoomState,
};
use crate::helpers::get_client_for_user;
@@ -25,12 +25,14 @@ async fn test_invitation_details() -> Result<()> {
sebastian.sync_once(Default::default()).await?;
let room = sebastian.get_room(&room_id).expect("Sebstian doesn't know about the room");
if let Room::Invited(iv) = room {
let details = iv.invite_details().await?;
let sender = details.inviter.expect("invite details doesn't have inviter");
assert_eq!(sender.user_id(), tamatoa.user_id().expect("tamatoa has a user_id"));
} else {
bail!("The room tamatoa invited sebastian in isn't an invite: {:?}", room);
}
ensure!(
room.state() == RoomState::Invited,
"The room tamatoa invited sebastian in isn't an invite: {room:?}"
);
let details = room.invite_details().await?;
let sender = details.inviter.expect("invite details doesn't have inviter");
assert_eq!(sender.user_id(), tamatoa.user_id().expect("tamatoa has a user_id"));
Ok(())
}
@@ -4,7 +4,7 @@ use anyhow::Result;
use assign::assign;
use matrix_sdk::{
event_handler::Ctx,
room::Room,
room,
ruma::{
api::client::room::create_room::v3::Request as CreateRoomRequest,
events::room::member::{MembershipState, StrippedRoomMemberEvent},
@@ -120,7 +120,7 @@ async fn test_repeated_join_leave() -> Result<()> {
async fn signal_on_invite(
event: StrippedRoomMemberEvent,
room: Room,
room: room::Common,
client: Client,
sender: Ctx<Arc<Notify>>,
) {