diff --git a/matrix_sdk/src/client.rs b/matrix_sdk/src/client.rs index 5518af18..852655d7 100644 --- a/matrix_sdk/src/client.rs +++ b/matrix_sdk/src/client.rs @@ -41,7 +41,7 @@ use tracing::{debug, warn}; use tracing::{error, info, instrument}; use matrix_sdk_base::{ - responses::SyncResponse, BaseClient, BaseClientConfig, Room, Session, Store, + responses::SyncResponse, BaseClient, BaseClientConfig, JoinedRoom, Room, Session, Store, }; #[cfg(feature = "encryption")] @@ -575,8 +575,8 @@ impl Client { /// # Arguments /// /// `room_id` - The unique id of the room that should be fetched. - pub fn get_joined_room(&self, room_id: &RoomId) -> Option { - self.base_client.get_room(room_id) + pub fn get_joined_room(&self, room_id: &RoomId) -> Option { + self.base_client.get_joined_room(room_id) } ///// Get an invited room with the given room id. @@ -1150,7 +1150,7 @@ impl Client { let _guard = mutex.lock().await; { - let room = self.base_client.get_room(room_id).unwrap(); + let room = self.get_joined_room(room_id).unwrap(); let members = room.joined_user_ids().await; // TODO don't collect here. let members_iter: Vec = members.collect().await; @@ -1252,17 +1252,17 @@ impl Client { /// Returns true if a room with the given id was found and the room is /// encrypted, false if the room wasn't found or isn't encrypted. async fn is_room_encrypted(&self, room_id: &RoomId) -> bool { - match self.base_client.get_room(room_id) { - Some(r) => r.is_encrypted(), - None => false, - } + self.base_client + .get_room(room_id) + .map(|r| r.is_encrypted()) + .unwrap_or(false) } async fn are_members_synced(&self, room_id: &RoomId) -> bool { - match self.base_client.get_room(room_id) { - Some(r) => r.are_members_synced(), - None => true, - } + self.base_client + .get_room(room_id) + .map(|r| r.are_members_synced()) + .unwrap_or(true) } /// Send an attachment to a room. diff --git a/matrix_sdk/src/lib.rs b/matrix_sdk/src/lib.rs index 3146bd8c..073c71e9 100644 --- a/matrix_sdk/src/lib.rs +++ b/matrix_sdk/src/lib.rs @@ -66,7 +66,10 @@ compile_error!("only one of 'native-tls' or 'rustls-tls' features can be enabled #[cfg(feature = "encryption")] #[cfg_attr(feature = "docs", doc(cfg(encryption)))] pub use matrix_sdk_base::crypto::LocalTrust; -pub use matrix_sdk_base::{Error as BaseError, Room, RoomInfo, RoomMember, Session}; +pub use matrix_sdk_base::{ + Error as BaseError, EventEmitter, InvitedRoom, JoinedRoom, LeftRoom, RoomInfo, RoomMember, + Session, +}; pub use matrix_sdk_common::*; pub use reqwest; diff --git a/matrix_sdk_base/src/client.rs b/matrix_sdk_base/src/client.rs index 3fe13aef..5a720399 100644 --- a/matrix_sdk_base/src/client.rs +++ b/matrix_sdk_base/src/client.rs @@ -59,12 +59,14 @@ use zeroize::Zeroizing; use crate::{ error::Result, responses::{ - AccountData, Ephemeral, InviteState, InvitedRoom, JoinedRoom, LeftRoom, MemberEvent, - Presence, Rooms, State, StrippedMemberEvent, SyncResponse, Timeline, + AccountData, Ephemeral, InviteState, InvitedRoom as InvitedRoomResponse, + JoinedRoom as JoinedRoomResponse, LeftRoom as LeftRoomResponse, MemberEvent, Presence, + Rooms, State, StrippedMemberEvent, SyncResponse, Timeline, }, rooms::{Room, RoomInfo, RoomType, StrippedRoom, StrippedRoomInfo}, session::Session, store::{StateChanges, Store}, + EventEmitter, InvitedRoom, JoinedRoom, LeftRoom, RoomState, }; pub type Token = String; @@ -163,21 +165,6 @@ pub enum RoomStateType { Invited, } -/// An enum that represents the state of the given `Room`. -/// -/// If the event came from the `join`, `invite` or `leave` rooms map from the server -/// the variant that holds the corresponding room is used. `RoomState` is generic -/// so it can be used to represent a `Room` or an `Arc>` -#[derive(Debug)] -pub enum RoomState { - /// A room from the `join` section of a sync response. - Joined(R), - /// A room from the `leave` section of a sync response. - Left(R), - /// A room from the `invite` section of a sync response. - Invited(R), -} - /// A no IO Client implementation. /// /// This Client is a state machine that receives responses and events and @@ -199,6 +186,9 @@ pub struct BaseClient { cryptostore: Arc>>>, store_path: Arc>, store_passphrase: Arc>, + /// Any implementor of EventEmitter will act as the callbacks for various + /// events. + event_emitter: Arc>>>, } #[cfg(not(tarpaulin_include))] @@ -303,21 +293,21 @@ impl BaseClient { }; Ok(BaseClient { - session: Arc::new(RwLock::new(None)), - sync_token: Arc::new(RwLock::new(None)), + session: RwLock::new(None).into(), + sync_token: RwLock::new(None).into(), store, - rooms: Arc::new(DashMap::new()), - stripped_rooms: Arc::new(DashMap::new()), + rooms: DashMap::new().into(), + stripped_rooms: DashMap::new().into(), #[cfg(feature = "encryption")] - olm: Arc::new(Mutex::new(None)), + olm: Mutex::new(None).into(), #[cfg(feature = "encryption")] - cryptostore: Arc::new(Mutex::new(config.crypto_store)), - store_path: Arc::new(config.store_path), - store_passphrase: Arc::new( - config - .passphrase - .unwrap_or_else(|| Zeroizing::new("DEFAULT_PASSPHRASE".to_owned())), - ), + cryptostore: Mutex::new(config.crypto_store).into(), + store_path: config.store_path.into(), + store_passphrase: config + .passphrase + .unwrap_or_else(|| Zeroizing::new("DEFAULT_PASSPHRASE".to_owned())) + .into(), + event_emitter: RwLock::new(None).into(), }) } @@ -425,6 +415,13 @@ impl BaseClient { self.sync_token.read().await.clone() } + /// Add `EventEmitter` to `Client`. + /// + /// The methods of `EventEmitter` are called when the respective `RoomEvents` occur. + pub async fn add_event_emitter(&self, emitter: Box) { + *self.event_emitter.write().await = Some(emitter); + } + async fn get_or_create_stripped_room(&self, room_id: &RoomId) -> StrippedRoom { let session = self.session.read().await; let user_id = &session @@ -738,7 +735,13 @@ impl BaseClient { rooms.join.insert( room_id, - JoinedRoom::new(timeline, state, account_data, ephemeral, notification_count), + JoinedRoomResponse::new( + timeline, + state, + account_data, + ephemeral, + notification_count, + ), ); changes.add_room(room_info); @@ -769,9 +772,10 @@ impl BaseClient { .handle_room_account_data(&room_id, &new_info.account_data.events, &mut changes) .await; - rooms - .leave - .insert(room_id, LeftRoom::new(timeline, state, account_data)); + rooms.leave.insert( + room_id, + LeftRoomResponse::new(timeline, state, account_data), + ); } for (room_id, new_info) in response.rooms.invite { @@ -791,7 +795,7 @@ impl BaseClient { changes.stripped_members.insert(room_id.clone(), members); changes.stripped_state.insert(room_id.clone(), state_events); - let room = InvitedRoom { + let room = InvitedRoomResponse { invite_state: state, }; @@ -851,7 +855,7 @@ impl BaseClient { async fn apply_changes(&self, changes: &StateChanges) { // TODO emit room changes here for (room_id, room_info) in &changes.room_infos { - if let Some(room) = self.get_room(&room_id) { + if let Some(room) = self.get_bare_room(&room_id) { room.update_summary(room_info.clone()) } } @@ -862,7 +866,7 @@ impl BaseClient { room_id: &RoomId, response: &api::membership::get_member_events::Response, ) -> Result<()> { - if let Some(room) = self.get_room(room_id) { + if let Some(room) = self.get_bare_room(room_id) { let mut room_info = room.clone_info(); room_info.mark_members_synced(); @@ -1027,12 +1031,28 @@ impl BaseClient { } } - pub fn get_room(&self, room_id: &RoomId) -> Option { + fn get_bare_room(&self, room_id: &RoomId) -> Option { #[allow(clippy::map_clone)] self.rooms.get(room_id).map(|r| r.clone()) } - pub fn get_stripped_room(&self, room_id: &RoomId) -> Option { + pub fn get_joined_room(&self, room_id: &RoomId) -> Option { + self.get_room(room_id).map(|r| r.joined()).flatten() + } + + pub fn get_room(&self, room_id: &RoomId) -> Option { + self.get_bare_room(room_id) + .map(|r| match r.room_type() { + RoomType::Joined => Some(RoomState::Joined(JoinedRoom { inner: r })), + RoomType::Left => Some(RoomState::Left(LeftRoom { inner: r })), + RoomType::Invited => self + .get_stripped_room(room_id) + .map(|r| RoomState::Invited(InvitedRoom { inner: r })), + }) + .flatten() + } + + fn get_stripped_room(&self, room_id: &RoomId) -> Option { #[allow(clippy::map_clone)] self.stripped_rooms.get(room_id).map(|r| r.clone()) } diff --git a/matrix_sdk_base/src/event_emitter/mod.rs b/matrix_sdk_base/src/event_emitter/mod.rs index 7a334f4d..41637042 100644 --- a/matrix_sdk_base/src/event_emitter/mod.rs +++ b/matrix_sdk_base/src/event_emitter/mod.rs @@ -40,13 +40,11 @@ use crate::{ typing::TypingEventContent, BasicEvent, StrippedStateEvent, SyncEphemeralRoomEvent, SyncMessageEvent, SyncStateEvent, }, - Room, RoomState, + rooms::RoomState, + Room, }; use matrix_sdk_common_macros::async_trait; -/// Type alias for `RoomState` enum when passed to `EventEmitter` methods. -pub type SyncRoom = RoomState>>; - /// This represents the various "unrecognized" events. #[derive(Clone, Copy, Debug)] pub enum CustomEvent<'c> { @@ -76,7 +74,7 @@ pub enum CustomEvent<'c> { /// # room::message::{MessageEventContent, TextMessageEventContent}, /// # SyncMessageEvent /// # }, -/// # EventEmitter, SyncRoom +/// # EventEmitter, RoomState /// # }; /// # use matrix_sdk_common::locks::RwLock; /// # use matrix_sdk_common_macros::async_trait; @@ -85,8 +83,8 @@ pub enum CustomEvent<'c> { /// /// #[async_trait] /// impl EventEmitter for EventCallback { -/// async fn on_room_message(&self, room: SyncRoom, event: &SyncMessageEvent) { -/// if let SyncRoom::Joined(room) = room { +/// async fn on_room_message(&self, room: RoomState, event: &SyncMessageEvent) { +/// if let RoomState::Joined(room) = room { /// if let SyncMessageEvent { /// content: MessageEventContent::Text(TextMessageEventContent { body: msg_body, .. }), /// sender, @@ -112,135 +110,140 @@ pub enum CustomEvent<'c> { pub trait EventEmitter: Send + Sync { // ROOM EVENTS from `IncomingTimeline` /// Fires when `Client` receives a `RoomEvent::RoomMember` event. - async fn on_room_member(&self, _: SyncRoom, _: &SyncStateEvent) {} + async fn on_room_member(&self, _: RoomState, _: &SyncStateEvent) {} /// Fires when `Client` receives a `RoomEvent::RoomName` event. - async fn on_room_name(&self, _: SyncRoom, _: &SyncStateEvent) {} + async fn on_room_name(&self, _: RoomState, _: &SyncStateEvent) {} /// Fires when `Client` receives a `RoomEvent::RoomCanonicalAlias` event. async fn on_room_canonical_alias( &self, - _: SyncRoom, + _: RoomState, _: &SyncStateEvent, ) { } /// Fires when `Client` receives a `RoomEvent::RoomAliases` event. - async fn on_room_aliases(&self, _: SyncRoom, _: &SyncStateEvent) {} + async fn on_room_aliases(&self, _: RoomState, _: &SyncStateEvent) {} /// Fires when `Client` receives a `RoomEvent::RoomAvatar` event. - async fn on_room_avatar(&self, _: SyncRoom, _: &SyncStateEvent) {} + async fn on_room_avatar(&self, _: RoomState, _: &SyncStateEvent) {} /// Fires when `Client` receives a `RoomEvent::RoomMessage` event. - async fn on_room_message(&self, _: SyncRoom, _: &SyncMessageEvent) {} + async fn on_room_message(&self, _: RoomState, _: &SyncMessageEvent) {} /// Fires when `Client` receives a `RoomEvent::RoomMessageFeedback` event. async fn on_room_message_feedback( &self, - _: SyncRoom, + _: RoomState, _: &SyncMessageEvent, ) { } /// Fires when `Client` receives a `RoomEvent::RoomRedaction` event. - async fn on_room_redaction(&self, _: SyncRoom, _: &SyncRedactionEvent) {} + async fn on_room_redaction(&self, _: RoomState, _: &SyncRedactionEvent) {} /// Fires when `Client` receives a `RoomEvent::RoomPowerLevels` event. - async fn on_room_power_levels(&self, _: SyncRoom, _: &SyncStateEvent) { + async fn on_room_power_levels( + &self, + _: RoomState, + _: &SyncStateEvent, + ) { } /// Fires when `Client` receives a `RoomEvent::Tombstone` event. - async fn on_room_join_rules(&self, _: SyncRoom, _: &SyncStateEvent) {} + async fn on_room_join_rules(&self, _: RoomState, _: &SyncStateEvent) {} /// Fires when `Client` receives a `RoomEvent::Tombstone` event. - async fn on_room_tombstone(&self, _: SyncRoom, _: &SyncStateEvent) {} + async fn on_room_tombstone(&self, _: RoomState, _: &SyncStateEvent) {} // `RoomEvent`s from `IncomingState` /// Fires when `Client` receives a `StateEvent::RoomMember` event. - async fn on_state_member(&self, _: SyncRoom, _: &SyncStateEvent) {} + async fn on_state_member(&self, _: RoomState, _: &SyncStateEvent) {} /// Fires when `Client` receives a `StateEvent::RoomName` event. - async fn on_state_name(&self, _: SyncRoom, _: &SyncStateEvent) {} + async fn on_state_name(&self, _: RoomState, _: &SyncStateEvent) {} /// Fires when `Client` receives a `StateEvent::RoomCanonicalAlias` event. async fn on_state_canonical_alias( &self, - _: SyncRoom, + _: RoomState, _: &SyncStateEvent, ) { } /// Fires when `Client` receives a `StateEvent::RoomAliases` event. - async fn on_state_aliases(&self, _: SyncRoom, _: &SyncStateEvent) {} + async fn on_state_aliases(&self, _: RoomState, _: &SyncStateEvent) {} /// Fires when `Client` receives a `StateEvent::RoomAvatar` event. - async fn on_state_avatar(&self, _: SyncRoom, _: &SyncStateEvent) {} + async fn on_state_avatar(&self, _: RoomState, _: &SyncStateEvent) {} /// Fires when `Client` receives a `StateEvent::RoomPowerLevels` event. async fn on_state_power_levels( &self, - _: SyncRoom, + _: RoomState, _: &SyncStateEvent, ) { } /// Fires when `Client` receives a `StateEvent::RoomJoinRules` event. - async fn on_state_join_rules(&self, _: SyncRoom, _: &SyncStateEvent) {} + async fn on_state_join_rules(&self, _: RoomState, _: &SyncStateEvent) {} // `AnyStrippedStateEvent`s /// Fires when `Client` receives a `AnyStrippedStateEvent::StrippedRoomMember` event. async fn on_stripped_state_member( &self, - _: SyncRoom, + _: RoomState, _: &StrippedStateEvent, _: Option, ) { } /// Fires when `Client` receives a `AnyStrippedStateEvent::StrippedRoomName` event. - async fn on_stripped_state_name(&self, _: SyncRoom, _: &StrippedStateEvent) {} + async fn on_stripped_state_name(&self, _: RoomState, _: &StrippedStateEvent) { + } /// Fires when `Client` receives a `AnyStrippedStateEvent::StrippedRoomCanonicalAlias` event. async fn on_stripped_state_canonical_alias( &self, - _: SyncRoom, + _: RoomState, _: &StrippedStateEvent, ) { } /// Fires when `Client` receives a `AnyStrippedStateEvent::StrippedRoomAliases` event. async fn on_stripped_state_aliases( &self, - _: SyncRoom, + _: RoomState, _: &StrippedStateEvent, ) { } /// Fires when `Client` receives a `AnyStrippedStateEvent::StrippedRoomAvatar` event. async fn on_stripped_state_avatar( &self, - _: SyncRoom, + _: RoomState, _: &StrippedStateEvent, ) { } /// Fires when `Client` receives a `AnyStrippedStateEvent::StrippedRoomPowerLevels` event. async fn on_stripped_state_power_levels( &self, - _: SyncRoom, + _: RoomState, _: &StrippedStateEvent, ) { } /// Fires when `Client` receives a `AnyStrippedStateEvent::StrippedRoomJoinRules` event. async fn on_stripped_state_join_rules( &self, - _: SyncRoom, + _: RoomState, _: &StrippedStateEvent, ) { } // `NonRoomEvent` (this is a type alias from ruma_events) /// Fires when `Client` receives a `NonRoomEvent::RoomPresence` event. - async fn on_non_room_presence(&self, _: SyncRoom, _: &PresenceEvent) {} + async fn on_non_room_presence(&self, _: RoomState, _: &PresenceEvent) {} /// Fires when `Client` receives a `NonRoomEvent::RoomName` event. async fn on_non_room_ignored_users( &self, - _: SyncRoom, + _: RoomState, _: &BasicEvent, ) { } /// Fires when `Client` receives a `NonRoomEvent::RoomCanonicalAlias` event. - async fn on_non_room_push_rules(&self, _: SyncRoom, _: &BasicEvent) {} + async fn on_non_room_push_rules(&self, _: RoomState, _: &BasicEvent) {} /// Fires when `Client` receives a `NonRoomEvent::RoomAliases` event. async fn on_non_room_fully_read( &self, - _: SyncRoom, + _: RoomState, _: &SyncEphemeralRoomEvent, ) { } /// Fires when `Client` receives a `NonRoomEvent::Typing` event. async fn on_non_room_typing( &self, - _: SyncRoom, + _: RoomState, _: &SyncEphemeralRoomEvent, ) { } @@ -249,27 +252,27 @@ pub trait EventEmitter: Send + Sync { /// This is always a read receipt. async fn on_non_room_receipt( &self, - _: SyncRoom, + _: RoomState, _: &SyncEphemeralRoomEvent, ) { } // `PresenceEvent` is a struct so there is only the one method /// Fires when `Client` receives a `NonRoomEvent::RoomAliases` event. - async fn on_presence_event(&self, _: SyncRoom, _: &PresenceEvent) {} + async fn on_presence_event(&self, _: RoomState, _: &PresenceEvent) {} /// Fires when `Client` receives a `Event::Custom` event or if deserialization fails /// because the event was unknown to ruma. /// /// The only guarantee this method can give about the event is that it is valid JSON. - async fn on_unrecognized_event(&self, _: SyncRoom, _: &RawJsonValue) {} + async fn on_unrecognized_event(&self, _: RoomState, _: &RawJsonValue) {} /// Fires when `Client` receives a `Event::Custom` event or if deserialization fails /// because the event was unknown to ruma. /// /// The only guarantee this method can give about the event is that it is in the /// shape of a valid matrix event. - async fn on_custom_event(&self, _: SyncRoom, _: &CustomEvent<'_>) {} + async fn on_custom_event(&self, _: RoomState, _: &CustomEvent<'_>) {} } #[cfg(test)] @@ -288,78 +291,78 @@ mod test { #[async_trait] impl EventEmitter for EvEmitterTest { - async fn on_room_member(&self, _: SyncRoom, _: &SyncStateEvent) { + async fn on_room_member(&self, _: RoomState, _: &SyncStateEvent) { self.0.lock().await.push("member".to_string()) } - async fn on_room_name(&self, _: SyncRoom, _: &SyncStateEvent) { + async fn on_room_name(&self, _: RoomState, _: &SyncStateEvent) { self.0.lock().await.push("name".to_string()) } async fn on_room_canonical_alias( &self, - _: SyncRoom, + _: RoomState, _: &SyncStateEvent, ) { self.0.lock().await.push("canonical".to_string()) } - async fn on_room_aliases(&self, _: SyncRoom, _: &SyncStateEvent) { + async fn on_room_aliases(&self, _: RoomState, _: &SyncStateEvent) { self.0.lock().await.push("aliases".to_string()) } - async fn on_room_avatar(&self, _: SyncRoom, _: &SyncStateEvent) { + async fn on_room_avatar(&self, _: RoomState, _: &SyncStateEvent) { self.0.lock().await.push("avatar".to_string()) } - async fn on_room_message(&self, _: SyncRoom, _: &SyncMessageEvent) { + async fn on_room_message(&self, _: RoomState, _: &SyncMessageEvent) { self.0.lock().await.push("message".to_string()) } async fn on_room_message_feedback( &self, - _: SyncRoom, + _: RoomState, _: &SyncMessageEvent, ) { self.0.lock().await.push("feedback".to_string()) } - async fn on_room_redaction(&self, _: SyncRoom, _: &SyncRedactionEvent) { + async fn on_room_redaction(&self, _: RoomState, _: &SyncRedactionEvent) { self.0.lock().await.push("redaction".to_string()) } async fn on_room_power_levels( &self, - _: SyncRoom, + _: RoomState, _: &SyncStateEvent, ) { self.0.lock().await.push("power".to_string()) } - async fn on_room_tombstone(&self, _: SyncRoom, _: &SyncStateEvent) { + async fn on_room_tombstone(&self, _: RoomState, _: &SyncStateEvent) { self.0.lock().await.push("tombstone".to_string()) } - async fn on_state_member(&self, _: SyncRoom, _: &SyncStateEvent) { + async fn on_state_member(&self, _: RoomState, _: &SyncStateEvent) { self.0.lock().await.push("state member".to_string()) } - async fn on_state_name(&self, _: SyncRoom, _: &SyncStateEvent) { + async fn on_state_name(&self, _: RoomState, _: &SyncStateEvent) { self.0.lock().await.push("state name".to_string()) } async fn on_state_canonical_alias( &self, - _: SyncRoom, + _: RoomState, _: &SyncStateEvent, ) { self.0.lock().await.push("state canonical".to_string()) } - async fn on_state_aliases(&self, _: SyncRoom, _: &SyncStateEvent) { + async fn on_state_aliases(&self, _: RoomState, _: &SyncStateEvent) { self.0.lock().await.push("state aliases".to_string()) } - async fn on_state_avatar(&self, _: SyncRoom, _: &SyncStateEvent) { + async fn on_state_avatar(&self, _: RoomState, _: &SyncStateEvent) { self.0.lock().await.push("state avatar".to_string()) } async fn on_state_power_levels( &self, - _: SyncRoom, + _: RoomState, _: &SyncStateEvent, ) { self.0.lock().await.push("state power".to_string()) } async fn on_state_join_rules( &self, - _: SyncRoom, + _: RoomState, _: &SyncStateEvent, ) { self.0.lock().await.push("state rules".to_string()) @@ -369,7 +372,7 @@ mod test { /// Fires when `Client` receives a `AnyStrippedStateEvent::StrippedRoomMember` event. async fn on_stripped_state_member( &self, - _: SyncRoom, + _: RoomState, _: &StrippedStateEvent, _: Option, ) { @@ -381,7 +384,7 @@ mod test { /// Fires when `Client` receives a `AnyStrippedStateEvent::StrippedRoomName` event. async fn on_stripped_state_name( &self, - _: SyncRoom, + _: RoomState, _: &StrippedStateEvent, ) { self.0.lock().await.push("stripped state name".to_string()) @@ -389,7 +392,7 @@ mod test { /// Fires when `Client` receives a `AnyStrippedStateEvent::StrippedRoomCanonicalAlias` event. async fn on_stripped_state_canonical_alias( &self, - _: SyncRoom, + _: RoomState, _: &StrippedStateEvent, ) { self.0 @@ -400,7 +403,7 @@ mod test { /// Fires when `Client` receives a `AnyStrippedStateEvent::StrippedRoomAliases` event. async fn on_stripped_state_aliases( &self, - _: SyncRoom, + _: RoomState, _: &StrippedStateEvent, ) { self.0 @@ -411,7 +414,7 @@ mod test { /// Fires when `Client` receives a `AnyStrippedStateEvent::StrippedRoomAvatar` event. async fn on_stripped_state_avatar( &self, - _: SyncRoom, + _: RoomState, _: &StrippedStateEvent, ) { self.0 @@ -422,7 +425,7 @@ mod test { /// Fires when `Client` receives a `AnyStrippedStateEvent::StrippedRoomPowerLevels` event. async fn on_stripped_state_power_levels( &self, - _: SyncRoom, + _: RoomState, _: &StrippedStateEvent, ) { self.0.lock().await.push("stripped state power".to_string()) @@ -430,53 +433,57 @@ mod test { /// Fires when `Client` receives a `AnyStrippedStateEvent::StrippedRoomJoinRules` event. async fn on_stripped_state_join_rules( &self, - _: SyncRoom, + _: RoomState, _: &StrippedStateEvent, ) { self.0.lock().await.push("stripped state rules".to_string()) } - async fn on_non_room_presence(&self, _: SyncRoom, _: &PresenceEvent) { + async fn on_non_room_presence(&self, _: RoomState, _: &PresenceEvent) { self.0.lock().await.push("presence".to_string()) } async fn on_non_room_ignored_users( &self, - _: SyncRoom, + _: RoomState, _: &BasicEvent, ) { self.0.lock().await.push("account ignore".to_string()) } - async fn on_non_room_push_rules(&self, _: SyncRoom, _: &BasicEvent) { + async fn on_non_room_push_rules( + &self, + _: RoomState, + _: &BasicEvent, + ) { self.0.lock().await.push("account push rules".to_string()) } async fn on_non_room_fully_read( &self, - _: SyncRoom, + _: RoomState, _: &SyncEphemeralRoomEvent, ) { self.0.lock().await.push("account read".to_string()) } async fn on_non_room_typing( &self, - _: SyncRoom, + _: RoomState, _: &SyncEphemeralRoomEvent, ) { self.0.lock().await.push("typing event".to_string()) } async fn on_non_room_receipt( &self, - _: SyncRoom, + _: RoomState, _: &SyncEphemeralRoomEvent, ) { self.0.lock().await.push("receipt event".to_string()) } - async fn on_presence_event(&self, _: SyncRoom, _: &PresenceEvent) { + async fn on_presence_event(&self, _: RoomState, _: &PresenceEvent) { self.0.lock().await.push("presence event".to_string()) } - async fn on_unrecognized_event(&self, _: SyncRoom, _: &RawJsonValue) { + async fn on_unrecognized_event(&self, _: RoomState, _: &RawJsonValue) { self.0.lock().await.push("unrecognized event".to_string()) } - async fn on_custom_event(&self, _: SyncRoom, _: &CustomEvent<'_>) { + async fn on_custom_event(&self, _: RoomState, _: &CustomEvent<'_>) { self.0.lock().await.push("custom event".to_string()) } } @@ -503,8 +510,8 @@ mod test { let client = get_client().await; client.add_event_emitter(emitter).await; - let mut response = sync_response(SyncResponseFile::Default); - client.receive_sync_response(&mut response).await.unwrap(); + let response = sync_response(SyncResponseFile::Default); + client.receive_sync_response(response).await.unwrap(); let v = test_vec.lock().await; assert_eq!( @@ -535,8 +542,8 @@ mod test { let client = get_client().await; client.add_event_emitter(emitter).await; - let mut response = sync_response(SyncResponseFile::Invite); - client.receive_sync_response(&mut response).await.unwrap(); + let response = sync_response(SyncResponseFile::Invite); + client.receive_sync_response(response).await.unwrap(); let v = test_vec.lock().await; assert_eq!( @@ -554,8 +561,8 @@ mod test { let client = get_client().await; client.add_event_emitter(emitter).await; - let mut response = sync_response(SyncResponseFile::Leave); - client.receive_sync_response(&mut response).await.unwrap(); + let response = sync_response(SyncResponseFile::Leave); + client.receive_sync_response(response).await.unwrap(); let v = test_vec.lock().await; assert_eq!( @@ -582,8 +589,8 @@ mod test { let client = get_client().await; client.add_event_emitter(emitter).await; - let mut response = sync_response(SyncResponseFile::All); - client.receive_sync_response(&mut response).await.unwrap(); + let response = sync_response(SyncResponseFile::All); + client.receive_sync_response(response).await.unwrap(); let v = test_vec.lock().await; assert_eq!( diff --git a/matrix_sdk_base/src/lib.rs b/matrix_sdk_base/src/lib.rs index 1f5965ed..c1201da1 100644 --- a/matrix_sdk_base/src/lib.rs +++ b/matrix_sdk_base/src/lib.rs @@ -44,15 +44,17 @@ pub use matrix_sdk_common::*; mod client; mod error; +mod event_emitter; pub mod responses; mod rooms; mod session; mod store; -pub use rooms::{Room, RoomInfo, RoomMember}; +pub use event_emitter::EventEmitter; +pub use rooms::{InvitedRoom, JoinedRoom, LeftRoom, Room, RoomInfo, RoomMember, RoomState}; pub use store::Store; -pub use client::{BaseClient, BaseClientConfig, RoomState, RoomStateType}; +pub use client::{BaseClient, BaseClientConfig, RoomStateType}; #[cfg(feature = "encryption")] #[cfg_attr(feature = "docs", doc(cfg(encryption)))] diff --git a/matrix_sdk_base/src/rooms/mod.rs b/matrix_sdk_base/src/rooms/mod.rs index 337346d6..2ce618e5 100644 --- a/matrix_sdk_base/src/rooms/mod.rs +++ b/matrix_sdk_base/src/rooms/mod.rs @@ -8,7 +8,7 @@ pub use stripped::{StrippedRoom, StrippedRoomInfo}; pub use members::RoomMember; use serde::{Deserialize, Serialize}; -use std::cmp::max; +use std::{cmp::max, ops::Deref}; use matrix_sdk_common::{ events::{ @@ -18,6 +18,86 @@ use matrix_sdk_common::{ identifiers::RoomAliasId, }; +/// An enum that represents the state of the given `Room`. +/// +/// If the event came from the `join`, `invite` or `leave` rooms map from the server +/// the variant that holds the corresponding room is used. `RoomState` is generic +/// so it can be used to represent a `Room` or an `Arc>` +#[derive(Debug, Clone)] +pub enum RoomState { + /// A room from the `join` section of a sync response. + Joined(JoinedRoom), + /// A room from the `leave` section of a sync response. + Left(LeftRoom), + /// A room from the `invite` section of a sync response. + Invited(InvitedRoom), +} + +impl RoomState { + pub fn joined(self) -> Option { + if let RoomState::Joined(r) = self { + Some(r) + } else { + None + } + } + + pub fn is_encrypted(&self) -> bool { + match self { + RoomState::Joined(r) => r.inner.is_encrypted(), + RoomState::Left(r) => r.inner.is_encrypted(), + RoomState::Invited(r) => r.inner.is_encrypted(), + } + } + + pub fn are_members_synced(&self) -> bool { + if let RoomState::Joined(r) = self { + r.inner.are_members_synced() + } else { + true + } + } +} + +#[derive(Debug, Clone)] +pub struct JoinedRoom { + pub(crate) inner: Room, +} + +impl Deref for JoinedRoom { + type Target = Room; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +#[derive(Debug, Clone)] +pub struct LeftRoom { + pub(crate) inner: Room, +} + +impl Deref for LeftRoom { + type Target = Room; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +#[derive(Debug, Clone)] +pub struct InvitedRoom { + pub(crate) inner: StrippedRoom, +} + +impl Deref for InvitedRoom { + type Target = StrippedRoom; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + #[derive(Clone, Debug, Serialize, Deserialize)] pub struct BaseRoomInfo { pub name: Option, diff --git a/matrix_sdk_base/src/rooms/normal.rs b/matrix_sdk_base/src/rooms/normal.rs index 42971926..7ee21458 100644 --- a/matrix_sdk_base/src/rooms/normal.rs +++ b/matrix_sdk_base/src/rooms/normal.rs @@ -83,6 +83,10 @@ impl Room { self.inner.lock().unwrap().members_synced } + pub fn room_type(&self) -> RoomType { + self.inner.lock().unwrap().room_type + } + pub async fn get_active_members(&self) -> impl Stream + '_ { let joined = self.store.get_joined_user_ids(self.room_id()).await; let invited = self.store.get_invited_user_ids(self.room_id()).await;