diff --git a/matrix_sdk/examples/command_bot.rs b/matrix_sdk/examples/command_bot.rs index a238dac5..43df2674 100644 --- a/matrix_sdk/examples/command_bot.rs +++ b/matrix_sdk/examples/command_bot.rs @@ -1,12 +1,10 @@ -use std::sync::Arc; use std::{env, process::exit}; use matrix_sdk::{ self, events::room::message::{MessageEvent, MessageEventContent, TextMessageEventContent}, - AsyncClient, AsyncClientConfig, EventEmitter, JsonStore, Room, SyncSettings, + AsyncClient, AsyncClientConfig, EventEmitter, JsonStore, RoomState, SyncSettings, }; -use tokio::sync::RwLock; use url::Url; struct CommandBot { @@ -23,37 +21,39 @@ impl CommandBot { #[async_trait::async_trait] impl EventEmitter for CommandBot { - async fn on_room_message(&self, room: Arc>, event: &MessageEvent) { - let msg_body = if let MessageEvent { - content: MessageEventContent::Text(TextMessageEventContent { body: msg_body, .. }), - .. - } = event - { - msg_body.clone() - } else { - String::new() - }; + async fn on_room_message(&self, room: RoomState, event: &MessageEvent) { + if let RoomState::Joined(room) = room { + let msg_body = if let MessageEvent { + content: MessageEventContent::Text(TextMessageEventContent { body: msg_body, .. }), + .. + } = event + { + msg_body.clone() + } else { + String::new() + }; - if msg_body.contains("!party") { - let content = MessageEventContent::Text(TextMessageEventContent { - body: "🎉🎊🥳 let's PARTY!! 🥳🎊🎉".to_string(), - format: None, - formatted_body: None, - relates_to: None, - }); - // we clone here to hold the lock for as little time as possible. - let room_id = room.read().await.room_id.clone(); + if msg_body.contains("!party") { + let content = MessageEventContent::Text(TextMessageEventContent { + body: "🎉🎊🥳 let's PARTY!! 🥳🎊🎉".to_string(), + format: None, + formatted_body: None, + relates_to: None, + }); + // we clone here to hold the lock for as little time as possible. + let room_id = room.read().await.room_id.clone(); - println!("sending"); + println!("sending"); - self.client - // send our message to the room we found the "!party" command in - // the last parameter is an optional Uuid which we don't care about. - .room_send(&room_id, content, None) - .await - .unwrap(); + self.client + // send our message to the room we found the "!party" command in + // the last parameter is an optional Uuid which we don't care about. + .room_send(&room_id, content, None) + .await + .unwrap(); - println!("message sent"); + println!("message sent"); + } } } } diff --git a/matrix_sdk/examples/login.rs b/matrix_sdk/examples/login.rs index 150684c7..724a7da3 100644 --- a/matrix_sdk/examples/login.rs +++ b/matrix_sdk/examples/login.rs @@ -1,37 +1,37 @@ -use std::sync::Arc; use std::{env, process::exit}; use url::Url; use matrix_sdk::{ self, events::room::message::{MessageEvent, MessageEventContent, TextMessageEventContent}, - AsyncClient, AsyncClientConfig, EventEmitter, Room, SyncSettings, + AsyncClient, AsyncClientConfig, EventEmitter, RoomState, SyncSettings, }; -use tokio::sync::RwLock; struct EventCallback; #[async_trait::async_trait] impl EventEmitter for EventCallback { - async fn on_room_message(&self, room: Arc>, event: &MessageEvent) { - if let MessageEvent { - content: MessageEventContent::Text(TextMessageEventContent { body: msg_body, .. }), - sender, - .. - } = event - { - let name = { - // any reads should be held for the shortest time possible to - // avoid dead locks - let room = room.read().await; - let member = room.members.get(&sender).unwrap(); - member - .display_name - .as_ref() - .map(ToString::to_string) - .unwrap_or(sender.to_string()) - }; - println!("{}: {}", name, msg_body); + async fn on_room_message(&self, room: RoomState, event: &MessageEvent) { + if let RoomState::Joined(room) = room { + if let MessageEvent { + content: MessageEventContent::Text(TextMessageEventContent { body: msg_body, .. }), + sender, + .. + } = event + { + let name = { + // any reads should be held for the shortest time possible to + // avoid dead locks + let room = room.read().await; + let member = room.members.get(&sender).unwrap(); + member + .display_name + .as_ref() + .map(ToString::to_string) + .unwrap_or(sender.to_string()) + }; + println!("{}: {}", name, msg_body); + } } } } diff --git a/matrix_sdk/src/async_client.rs b/matrix_sdk/src/async_client.rs index fcad6177..dde9d8ba 100644 --- a/matrix_sdk/src/async_client.rs +++ b/matrix_sdk/src/async_client.rs @@ -50,7 +50,7 @@ use crate::models::Room; use crate::session::Session; use crate::state::StateStore; use crate::VERSION; -use crate::{Error, EventEmitter, Result}; +use crate::{Error, EventEmitter, Result, RoomStateType}; const DEFAULT_SYNC_TIMEOUT: Duration = Duration::from_secs(30); @@ -322,6 +322,9 @@ impl AsyncClient { /// /// This is a human readable room name. pub async fn get_room_name(&self, room_id: &RoomId) -> Option { + // TODO do we want to use the `RoomStateType` enum here or should we have + // 3 seperate `room_name` methods. The other option is to remove this and have + // the user get a `Room` and use `Room::calculate_name` method? self.base_client .read() .await @@ -336,13 +339,27 @@ impl AsyncClient { self.base_client.read().await.calculate_room_names().await } - /// Returns the rooms this client knows about. + /// Returns the joined rooms this client knows about. /// /// A `HashMap` of room id to `matrix::models::Room` - pub async fn get_rooms(&self) -> HashMap>> { + pub async fn get_joined_rooms(&self) -> HashMap>> { self.base_client.read().await.joined_rooms.clone() } + /// Returns the invited rooms this client knows about. + /// + /// A `HashMap` of room id to `matrix::models::Room` + pub async fn get_invited_rooms(&self) -> HashMap>> { + self.base_client.read().await.invited_rooms.clone() + } + + /// Returns the left rooms this client knows about. + /// + /// A `HashMap` of room id to `matrix::models::Room` + pub async fn get_left_rooms(&self) -> HashMap>> { + self.base_client.read().await.lefted_rooms.clone() + } + /// This allows `AsyncClient` to manually sync state with the provided `StateStore`. /// /// Returns true when a successful `StateStore` sync has completed. @@ -663,13 +680,12 @@ impl AsyncClient { Ok(response) } - #[inline] async fn iter_joined_rooms(&self, response: &mut sync_events::Response) -> Result { let mut updated = false; - for (room_id, room) in &mut response.rooms.join { + for (room_id, joined_room) in &mut response.rooms.join { let matrix_room = { let mut client = self.base_client.write().await; - for event in &room.state.events { + for event in &joined_room.state.events { if let Ok(e) = event.deserialize() { if client.receive_joined_state_event(&room_id, &e).await { updated = true; @@ -677,21 +693,26 @@ impl AsyncClient { } } - client.get_or_create_room(&room_id).clone() + client.get_or_create_joined_room(&room_id).clone() }; // RoomSummary contains information for calculating room name - matrix_room.write().await.set_room_summary(&room.summary); + matrix_room + .write() + .await + .set_room_summary(&joined_room.summary); // re looping is not ideal here - for event in &mut room.state.events { + for event in &mut joined_room.state.events { if let Ok(e) = event.deserialize() { let client = self.base_client.read().await; - client.emit_state_event(&room_id, &e).await; + client + .emit_state_event(&room_id, &e, RoomStateType::Joined) + .await; } } - for mut event in &mut room.timeline.events { + for mut event in &mut joined_room.timeline.events { let decrypted_event = { let mut client = self.base_client.write().await; let (decrypt_ev, timeline_update) = client @@ -709,12 +730,14 @@ impl AsyncClient { if let Ok(e) = event.deserialize() { let client = self.base_client.read().await; - client.emit_timeline_event(&room_id, &e).await; + client + .emit_timeline_event(&room_id, &e, RoomStateType::Joined) + .await; } } // look at AccountData to further cut down users by collecting ignored users - if let Some(account_data) = &room.account_data { + if let Some(account_data) = &joined_room.account_data { for account_data in &account_data.events { { if let Ok(e) = account_data.deserialize() { @@ -722,7 +745,9 @@ impl AsyncClient { if client.receive_account_data_event(&room_id, &e).await { updated = true; } - client.emit_account_data_event(room_id, &e).await; + client + .emit_account_data_event(room_id, &e, RoomStateType::Joined) + .await; } } } @@ -739,12 +764,14 @@ impl AsyncClient { updated = true; } - client.emit_presence_event(&room_id, &e).await; + client + .emit_presence_event(&room_id, &e, RoomStateType::Joined) + .await; } } } - for ephemeral in &mut room.ephemeral.events { + for ephemeral in &mut joined_room.ephemeral.events { { if let Ok(e) = ephemeral.deserialize() { let mut client = self.base_client.write().await; @@ -752,7 +779,9 @@ impl AsyncClient { updated = true; } - client.emit_ephemeral_event(&room_id, &e).await; + client + .emit_ephemeral_event(&room_id, &e, RoomStateType::Joined) + .await; } } } @@ -768,16 +797,36 @@ impl AsyncClient { Ok(updated) } - #[inline] async fn iter_left_rooms(&self, response: &mut sync_events::Response) -> Result { let mut updated = false; for (room_id, left_room) in &mut response.rooms.leave { + let matrix_room = { + let mut client = self.base_client.write().await; + for event in &left_room.state.events { + if let Ok(e) = event.deserialize() { + if client.receive_left_state_event(&room_id, &e).await { + updated = true; + } + } + } + + client.get_or_create_left_room(&room_id).clone() + }; + + for event in &mut left_room.state.events { + if let Ok(e) = event.deserialize() { + let client = self.base_client.read().await; + client + .emit_state_event(&room_id, &e, RoomStateType::Left) + .await; + } + } + for mut event in &mut left_room.timeline.events { let decrypted_event = { let mut client = self.base_client.write().await; - let (decrypt_ev, timeline_update) = client - .receive_joined_timeline_event(room_id, &mut event) + .receive_left_timeline_event(room_id, &mut event) .await; if timeline_update { updated = true; @@ -791,30 +840,23 @@ impl AsyncClient { if let Ok(e) = event.deserialize() { let client = self.base_client.read().await; - client.emit_timeline_event(&room_id, &e).await; - } - } - - // re looping is not ideal here - for event in &mut left_room.state.events { - if let Ok(e) = event.deserialize() { - let client = self.base_client.read().await; - client.emit_state_event(&room_id, &e).await; + client + .emit_timeline_event(&room_id, &e, RoomStateType::Left) + .await; } } if updated { if let Some(store) = self.base_client.read().await.state_store.as_ref() { - let mut client = self.base_client.write().await; - let room = client.get_or_create_room(&room_id).clone(); - store.store_room_state(room.read().await.deref()).await?; + store + .store_room_state(matrix_room.read().await.deref()) + .await?; } } } Ok(updated) } - #[inline] async fn iter_invited_rooms(&self, response: &sync_events::Response) -> Result { let mut updated = false; for (room_id, invited_room) in &response.rooms.invite { @@ -828,14 +870,15 @@ impl AsyncClient { } } - client.get_or_create_room(&room_id).clone() + client.get_or_create_left_room(&room_id).clone() }; - // re looping is not ideal here for event in &invited_room.invite_state.events { if let Ok(e) = event.deserialize() { let client = self.base_client.read().await; - client.emit_stripped_state_event(&room_id, &e).await; + client + .emit_stripped_state_event(&room_id, &e, RoomStateType::Invited) + .await; } } diff --git a/matrix_sdk/src/base_client.rs b/matrix_sdk/src/base_client.rs index db35c6b4..c6099580 100644 --- a/matrix_sdk/src/base_client.rs +++ b/matrix_sdk/src/base_client.rs @@ -58,6 +58,58 @@ use matrix_sdk_crypto::{OlmMachine, OneTimeKeys}; pub type Token = String; +/// Signals to the `BaseClient` which `RoomState` to send to `EventEmitter`. +pub enum RoomStateType { + /// Represents a joined room, the `joined_rooms` HashMap will be used. + Joined, + /// Represents a left room, the `left_rooms` HashMap will be used. + Left, + /// Represents an invited room, the `invited_rooms` HashMap will be used. + 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. +pub enum RoomState { + /// A room from the `join` section of a sync response. + Joined(Arc>), + /// A room from the `leave` section of a sync response. + Left(Arc>), + /// A room from the `invite` section of a sync response. + Invited(Arc>), +} + +macro_rules! emit_event { + ($this:ident, $id:ident, $event:ident, $state:ident, $($variant:path => $meth:ident,)*) => { + match &$event { + $($variant(ev) => { + if let Some(ee) = &$this.event_emitter { + match $state { + RoomStateType::Joined => { + if let Some(room) = $this.get_joined_room(&$id) { + ee.$meth(RoomState::Joined(Arc::clone(&room)), &ev).await; + } + } + RoomStateType::Invited => { + if let Some(room) = $this.get_invited_room(&$id) { + ee.$meth(RoomState::Invited(Arc::clone(&room)), &ev).await; + } + } + RoomStateType::Left => { + if let Some(room) = $this.get_left_room(&$id) { + ee.$meth(RoomState::Left(Arc::clone(&room)), &ev).await; + } + } + } + } + })* + _ => {} + } + } +} + /// A no IO Client implementation. /// /// This Client is a state machine that receives responses and events and @@ -70,6 +122,10 @@ pub struct Client { pub sync_token: Option, /// A map of the rooms our user is joined in. pub joined_rooms: HashMap>>, + /// A map of the rooms our user is invited to. + pub invited_rooms: HashMap>>, + /// A map of the rooms our user has left. + pub lefted_rooms: HashMap>>, /// A list of ignored users. pub ignored_users: Vec, /// The push ruleset for the logged in user. @@ -120,6 +176,8 @@ impl Client { session, sync_token: None, joined_rooms: HashMap::new(), + invited_rooms: HashMap::new(), + lefted_rooms: HashMap::new(), ignored_users: Vec::new(), push_ruleset: None, event_emitter: None, @@ -224,7 +282,7 @@ impl Client { res } - pub(crate) fn get_or_create_room(&mut self, room_id: &RoomId) -> &mut Arc> { + pub(crate) fn get_or_create_joined_room(&mut self, room_id: &RoomId) -> &mut Arc> { #[allow(clippy::or_fun_call)] self.joined_rooms .entry(room_id.clone()) @@ -238,10 +296,49 @@ impl Client { )))) } - pub(crate) fn get_room(&self, room_id: &RoomId) -> Option<&Arc>> { + pub(crate) fn get_joined_room(&self, room_id: &RoomId) -> Option<&Arc>> { self.joined_rooms.get(room_id) } + pub(crate) fn get_or_create_invited_room( + &mut self, + room_id: &RoomId, + ) -> &mut Arc> { + #[allow(clippy::or_fun_call)] + self.invited_rooms + .entry(room_id.clone()) + .or_insert(Arc::new(RwLock::new(Room::new( + room_id, + &self + .session + .as_ref() + .expect("Receiving events while not being logged in") + .user_id, + )))) + } + + pub(crate) fn get_invited_room(&self, room_id: &RoomId) -> Option<&Arc>> { + self.invited_rooms.get(room_id) + } + + pub(crate) fn get_or_create_left_room(&mut self, room_id: &RoomId) -> &mut Arc> { + #[allow(clippy::or_fun_call)] + self.lefted_rooms + .entry(room_id.clone()) + .or_insert(Arc::new(RwLock::new(Room::new( + room_id, + &self + .session + .as_ref() + .expect("Receiving events while not being logged in") + .user_id, + )))) + } + + pub(crate) fn get_left_room(&self, room_id: &RoomId) -> Option<&Arc>> { + self.lefted_rooms.get(room_id) + } + /// Handle a m.ignored_user_list event, updating the room state if necessary. /// /// Returns true if the room name changed, false otherwise. @@ -308,7 +405,7 @@ impl Client { } } - let mut room = self.get_or_create_room(&room_id).write().await; + let mut room = self.get_or_create_joined_room(&room_id).write().await; (decrypted_event, room.receive_timeline_event(&e)) } _ => (None, false), @@ -317,7 +414,7 @@ impl Client { /// Receive a state event for a joined room and update the client state. /// - /// Returns true if the membership list of the room changed, false + /// Returns true if the state of the room changed, false /// otherwise. /// /// # Arguments @@ -330,7 +427,7 @@ impl Client { room_id: &RoomId, event: &StateEvent, ) -> bool { - let mut room = self.get_or_create_room(room_id).write().await; + let mut room = self.get_or_create_joined_room(room_id).write().await; room.receive_state_event(event) } @@ -349,13 +446,70 @@ impl Client { room_id: &RoomId, event: &AnyStrippedStateEvent, ) -> bool { - let mut room = self.get_or_create_room(room_id).write().await; + let mut room = self.get_or_create_invited_room(room_id).write().await; room.receive_stripped_state_event(event) } + /// Receive a timeline event for a room the user has left and update the client state. + /// + /// Returns a tuple of the successfully decrypted event, or None on failure and + /// a bool, true when the `Room` state has been updated. + /// + /// # Arguments + /// + /// * `room_id` - The unique id of the room the event belongs to. + /// + /// * `event` - The event that should be handled by the client. + pub async fn receive_left_timeline_event( + &mut self, + room_id: &RoomId, + event: &mut EventJson, + ) -> (Option>, bool) { + match event.deserialize() { + #[allow(unused_mut)] + Ok(mut e) => { + #[cfg(feature = "encryption")] + let mut decrypted_event = None; + #[cfg(not(feature = "encryption"))] + let decrypted_event = None; + + #[cfg(feature = "encryption")] + { + if let RoomEvent::RoomEncrypted(ref mut e) = e { + e.room_id = Some(room_id.to_owned()); + let mut olm = self.olm.lock().await; + + if let Some(o) = &mut *olm { + decrypted_event = o.decrypt_room_event(&e).await.ok(); + } + } + } + + let mut room = self.get_or_create_left_room(&room_id).write().await; + (decrypted_event, room.receive_timeline_event(&e)) + } + _ => (None, false), + } + } + + /// Receive a state event for a room the user has left and update the client state. + /// + /// Returns true if the state of the room changed, false + /// otherwise. + /// + /// # Arguments + /// + /// * `room_id` - The unique id of the room the event belongs to. + /// + /// * `event` - The event that should be handled by the client. + pub async fn receive_left_state_event(&mut self, room_id: &RoomId, event: &StateEvent) -> bool { + let mut room = self.get_or_create_left_room(room_id).write().await; + room.receive_state_event(event) + } + /// Receive a presence event from a sync response and updates the client state. /// - /// Returns true if the membership list of the room changed, false + /// Returns true if the state of the room changed, false /// otherwise. /// /// # Arguments @@ -369,7 +523,7 @@ impl Client { event: &PresenceEvent, ) -> bool { // this should be the room that was just created in the `Client::sync` loop. - if let Some(room) = self.get_room(room_id) { + if let Some(room) = self.get_joined_room(room_id) { let mut room = room.write().await; room.receive_presence_event(event) } else { @@ -532,7 +686,7 @@ impl Client { &self, room_id: &RoomId, ) -> Result> { - let room = self.get_room(room_id).expect("No room found"); + let room = self.get_joined_room(room_id).expect("No room found"); let mut olm = self.olm.lock().await; match &mut *olm { @@ -649,288 +803,117 @@ impl Client { Ok(()) } - pub(crate) async fn emit_timeline_event(&self, room_id: &RoomId, event: &RoomEvent) { - match event { - RoomEvent::RoomMember(mem) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_room_member(Arc::clone(&room), &mem).await; - } - } - } - RoomEvent::RoomName(name) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_room_name(Arc::clone(&room), &name).await; - } - } - } - RoomEvent::RoomCanonicalAlias(canonical) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_room_canonical_alias(Arc::clone(&room), &canonical) - .await; - } - } - } - RoomEvent::RoomAliases(aliases) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_room_aliases(Arc::clone(&room), &aliases).await; - } - } - } - RoomEvent::RoomAvatar(avatar) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_room_avatar(Arc::clone(&room), &avatar).await; - } - } - } - RoomEvent::RoomMessage(msg) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_room_message(Arc::clone(&room), &msg).await; - } - } - } - RoomEvent::RoomMessageFeedback(msg_feedback) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_room_message_feedback(Arc::clone(&room), &msg_feedback) - .await; - } - } - } - RoomEvent::RoomRedaction(redaction) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_room_redaction(Arc::clone(&room), &redaction).await; - } - } - } - RoomEvent::RoomPowerLevels(power) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_room_power_levels(Arc::clone(&room), &power).await; - } - } - } - RoomEvent::RoomTombstone(tomb) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_room_tombstone(Arc::clone(&room), &tomb).await; - } - } - } - _ => {} - } + pub(crate) async fn emit_timeline_event( + &self, + room_id: &RoomId, + event: &RoomEvent, + room_state: RoomStateType, + ) { + emit_event!( + self, room_id, event, room_state, + RoomEvent::RoomMember => on_room_member, + RoomEvent::RoomName => on_room_name, + RoomEvent::RoomCanonicalAlias => on_room_canonical_alias, + RoomEvent::RoomAliases => on_room_aliases, + RoomEvent::RoomAvatar => on_room_avatar, + RoomEvent::RoomMessage => on_room_message, + RoomEvent::RoomMessageFeedback => on_room_message_feedback, + RoomEvent::RoomRedaction => on_room_redaction, + RoomEvent::RoomPowerLevels => on_room_power_levels, + RoomEvent::RoomTombstone => on_room_tombstone, + ); } pub(crate) async fn emit_stripped_state_event( &self, room_id: &RoomId, event: &AnyStrippedStateEvent, + room_state: RoomStateType, ) { - match event { - AnyStrippedStateEvent::RoomMember(member) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_stripped_state_member(Arc::clone(&room), &member) - .await; - } - } - } - AnyStrippedStateEvent::RoomName(name) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_stripped_state_name(Arc::clone(&room), &name).await; - } - } - } - AnyStrippedStateEvent::RoomCanonicalAlias(canonical) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_stripped_state_canonical_alias(Arc::clone(&room), &canonical) - .await; - } - } - } - AnyStrippedStateEvent::RoomAliases(aliases) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_stripped_state_aliases(Arc::clone(&room), &aliases) - .await; - } - } - } - AnyStrippedStateEvent::RoomAvatar(avatar) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_stripped_state_avatar(Arc::clone(&room), &avatar) - .await; - } - } - } - AnyStrippedStateEvent::RoomPowerLevels(power) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_stripped_state_power_levels(Arc::clone(&room), &power) - .await; - } - } - } - AnyStrippedStateEvent::RoomJoinRules(rules) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_stripped_state_join_rules(Arc::clone(&room), &rules) - .await; - } - } - } - _ => {} - } + emit_event!( + self, room_id, event, room_state, + AnyStrippedStateEvent::RoomMember => on_stripped_state_member, + AnyStrippedStateEvent::RoomName => on_stripped_state_name, + AnyStrippedStateEvent::RoomCanonicalAlias => on_stripped_state_canonical_alias, + AnyStrippedStateEvent::RoomAliases => on_stripped_state_aliases, + AnyStrippedStateEvent::RoomAvatar => on_stripped_state_avatar, + ); } - pub(crate) async fn emit_state_event(&self, room_id: &RoomId, event: &StateEvent) { - match event { - StateEvent::RoomMember(member) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_state_member(Arc::clone(&room), &member).await; - } - } - } - StateEvent::RoomName(name) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_state_name(Arc::clone(&room), &name).await; - } - } - } - StateEvent::RoomCanonicalAlias(canonical) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_state_canonical_alias(Arc::clone(&room), &canonical) - .await; - } - } - } - StateEvent::RoomAliases(aliases) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_state_aliases(Arc::clone(&room), &aliases).await; - } - } - } - StateEvent::RoomAvatar(avatar) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_state_avatar(Arc::clone(&room), &avatar).await; - } - } - } - StateEvent::RoomPowerLevels(power) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_state_power_levels(Arc::clone(&room), &power).await; - } - } - } - StateEvent::RoomJoinRules(rules) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_state_join_rules(Arc::clone(&room), &rules).await; - } - } - } - StateEvent::RoomTombstone(tomb) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_room_tombstone(Arc::clone(&room), &tomb).await; - } - } - } - _ => {} - } + pub(crate) async fn emit_state_event( + &self, + room_id: &RoomId, + event: &StateEvent, + room_state: RoomStateType, + ) { + emit_event!( + self, room_id, event, room_state, + StateEvent::RoomMember => on_state_member, + StateEvent::RoomName => on_state_name, + StateEvent::RoomCanonicalAlias => on_state_canonical_alias, + StateEvent::RoomAliases => on_state_aliases, + StateEvent::RoomAvatar => on_state_avatar, + StateEvent::RoomPowerLevels => on_state_power_levels, + StateEvent::RoomTombstone => on_room_tombstone, + ); } - pub(crate) async fn emit_account_data_event(&self, room_id: &RoomId, event: &NonRoomEvent) { - match event { - NonRoomEvent::Presence(presence) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_account_presence(Arc::clone(&room), &presence).await; - } - } - } - NonRoomEvent::IgnoredUserList(ignored) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_account_ignored_users(Arc::clone(&room), &ignored) - .await; - } - } - } - NonRoomEvent::PushRules(rules) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_account_push_rules(Arc::clone(&room), &rules).await; - } - } - } - NonRoomEvent::FullyRead(full_read) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_account_data_fully_read(Arc::clone(&room), &full_read) - .await; - } - } - } - _ => {} - } + pub(crate) async fn emit_account_data_event( + &self, + room_id: &RoomId, + event: &NonRoomEvent, + room_state: RoomStateType, + ) { + emit_event!( + self, room_id, event, room_state, + NonRoomEvent::Presence => on_account_presence, + NonRoomEvent::IgnoredUserList => on_account_ignored_users, + NonRoomEvent::PushRules => on_account_push_rules, + NonRoomEvent::FullyRead => on_account_data_fully_read, + ); } - pub(crate) async fn emit_ephemeral_event(&self, room_id: &RoomId, event: &NonRoomEvent) { - match event { - NonRoomEvent::Presence(presence) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_account_presence(Arc::clone(&room), &presence).await; - } - } - } - NonRoomEvent::IgnoredUserList(ignored) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_account_ignored_users(Arc::clone(&room), &ignored) - .await; - } - } - } - NonRoomEvent::PushRules(rules) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_account_push_rules(Arc::clone(&room), &rules).await; - } - } - } - NonRoomEvent::FullyRead(full_read) => { - if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_account_data_fully_read(Arc::clone(&room), &full_read) - .await; - } - } - } - _ => {} - } + pub(crate) async fn emit_ephemeral_event( + &self, + room_id: &RoomId, + event: &NonRoomEvent, + room_state: RoomStateType, + ) { + emit_event!( + self, room_id, event, room_state, + NonRoomEvent::Presence => on_account_presence, + NonRoomEvent::IgnoredUserList => on_account_ignored_users, + NonRoomEvent::PushRules => on_account_push_rules, + NonRoomEvent::FullyRead => on_account_data_fully_read, + ); } - pub(crate) async fn emit_presence_event(&self, room_id: &RoomId, event: &PresenceEvent) { + pub(crate) async fn emit_presence_event( + &self, + room_id: &RoomId, + event: &PresenceEvent, + room_state: RoomStateType, + ) { if let Some(ee) = &self.event_emitter { - if let Some(room) = self.get_room(&room_id) { - ee.on_presence_event(Arc::clone(&room), &event).await; + match room_state { + RoomStateType::Invited => { + if let Some(room) = self.get_invited_room(&room_id) { + ee.on_presence_event(RoomState::Invited(Arc::clone(&room)), &event) + .await; + } + } + RoomStateType::Joined => { + if let Some(room) = self.get_joined_room(&room_id) { + ee.on_presence_event(RoomState::Joined(Arc::clone(&room)), &event) + .await; + } + } + RoomStateType::Left => { + if let Some(room) = self.get_left_room(&room_id) { + ee.on_presence_event(RoomState::Left(Arc::clone(&room)), &event) + .await; + } + } } } } diff --git a/matrix_sdk/src/event_emitter/mod.rs b/matrix_sdk/src/event_emitter/mod.rs index de67be3c..0ddc77a1 100644 --- a/matrix_sdk/src/event_emitter/mod.rs +++ b/matrix_sdk/src/event_emitter/mod.rs @@ -12,7 +12,6 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -use std::sync::Arc; use crate::events::{ fully_read::FullyReadEvent, @@ -36,8 +35,7 @@ use crate::events::{ StrippedRoomMember, StrippedRoomName, StrippedRoomPowerLevels, }, }; -use crate::models::Room; -use tokio::sync::RwLock; +use crate::RoomState; /// This trait allows any type implementing `EventEmitter` to specify event callbacks for each event. /// The `AsyncClient` calls each method when the corresponding event is received. @@ -53,7 +51,7 @@ use tokio::sync::RwLock; /// events::{ /// room::message::{MessageEvent, MessageEventContent, TextMessageEventContent}, /// }, -/// AsyncClient, AsyncClientConfig, EventEmitter, Room, SyncSettings, +/// AsyncClient, AsyncClientConfig, EventEmitter, RoomState, SyncSettings, /// }; /// use tokio::sync::RwLock; /// @@ -61,23 +59,25 @@ use tokio::sync::RwLock; /// /// #[async_trait::async_trait] /// impl EventEmitter for EventCallback { -/// async fn on_room_message(&self, room: Arc>, event: &MessageEvent) { -/// if let MessageEvent { -/// content: MessageEventContent::Text(TextMessageEventContent { body: msg_body, .. }), -/// sender, -/// .. -/// } = event -/// { -/// let name = { -/// let room = room.read().await; -/// let member = room.members.get(&sender).unwrap(); -/// member -/// .display_name -/// .as_ref() -/// .map(ToString::to_string) -/// .unwrap_or(sender.to_string()) -/// }; -/// println!("{}: {}", name, msg_body); +/// async fn on_room_message(&self, room: RoomState, event: &MessageEvent) { +/// if let RoomState::Joined(room) = room { +/// if let MessageEvent { +/// content: MessageEventContent::Text(TextMessageEventContent { body: msg_body, .. }), +/// sender, +/// .. +/// } = event +/// { +/// let name = { +/// let room = room.read().await; +/// let member = room.members.get(&sender).unwrap(); +/// member +/// .display_name +/// .as_ref() +/// .map(ToString::to_string) +/// .unwrap_or(sender.to_string()) +/// }; +/// println!("{}: {}", name, msg_body); +/// } /// } /// } /// } @@ -86,81 +86,76 @@ use tokio::sync::RwLock; pub trait EventEmitter: Send + Sync { // ROOM EVENTS from `IncomingTimeline` /// Fires when `AsyncClient` receives a `RoomEvent::RoomMember` event. - async fn on_room_member(&self, _: Arc>, _: &MemberEvent) {} + async fn on_room_member(&self, _: RoomState, _: &MemberEvent) {} /// Fires when `AsyncClient` receives a `RoomEvent::RoomName` event. - async fn on_room_name(&self, _: Arc>, _: &NameEvent) {} + async fn on_room_name(&self, _: RoomState, _: &NameEvent) {} /// Fires when `AsyncClient` receives a `RoomEvent::RoomCanonicalAlias` event. - async fn on_room_canonical_alias(&self, _: Arc>, _: &CanonicalAliasEvent) {} + async fn on_room_canonical_alias(&self, _: RoomState, _: &CanonicalAliasEvent) {} /// Fires when `AsyncClient` receives a `RoomEvent::RoomAliases` event. - async fn on_room_aliases(&self, _: Arc>, _: &AliasesEvent) {} + async fn on_room_aliases(&self, _: RoomState, _: &AliasesEvent) {} /// Fires when `AsyncClient` receives a `RoomEvent::RoomAvatar` event. - async fn on_room_avatar(&self, _: Arc>, _: &AvatarEvent) {} + async fn on_room_avatar(&self, _: RoomState, _: &AvatarEvent) {} /// Fires when `AsyncClient` receives a `RoomEvent::RoomMessage` event. - async fn on_room_message(&self, _: Arc>, _: &MessageEvent) {} + async fn on_room_message(&self, _: RoomState, _: &MessageEvent) {} /// Fires when `AsyncClient` receives a `RoomEvent::RoomMessageFeedback` event. - async fn on_room_message_feedback(&self, _: Arc>, _: &FeedbackEvent) {} + async fn on_room_message_feedback(&self, _: RoomState, _: &FeedbackEvent) {} /// Fires when `AsyncClient` receives a `RoomEvent::RoomRedaction` event. - async fn on_room_redaction(&self, _: Arc>, _: &RedactionEvent) {} + async fn on_room_redaction(&self, _: RoomState, _: &RedactionEvent) {} /// Fires when `AsyncClient` receives a `RoomEvent::RoomPowerLevels` event. - async fn on_room_power_levels(&self, _: Arc>, _: &PowerLevelsEvent) {} + async fn on_room_power_levels(&self, _: RoomState, _: &PowerLevelsEvent) {} /// Fires when `AsyncClient` receives a `RoomEvent::Tombstone` event. - async fn on_room_tombstone(&self, _: Arc>, _: &TombstoneEvent) {} + async fn on_room_tombstone(&self, _: RoomState, _: &TombstoneEvent) {} // `RoomEvent`s from `IncomingState` /// Fires when `AsyncClient` receives a `StateEvent::RoomMember` event. - async fn on_state_member(&self, _: Arc>, _: &MemberEvent) {} + async fn on_state_member(&self, _: RoomState, _: &MemberEvent) {} /// Fires when `AsyncClient` receives a `StateEvent::RoomName` event. - async fn on_state_name(&self, _: Arc>, _: &NameEvent) {} + async fn on_state_name(&self, _: RoomState, _: &NameEvent) {} /// Fires when `AsyncClient` receives a `StateEvent::RoomCanonicalAlias` event. - async fn on_state_canonical_alias(&self, _: Arc>, _: &CanonicalAliasEvent) {} + async fn on_state_canonical_alias(&self, _: RoomState, _: &CanonicalAliasEvent) {} /// Fires when `AsyncClient` receives a `StateEvent::RoomAliases` event. - async fn on_state_aliases(&self, _: Arc>, _: &AliasesEvent) {} + async fn on_state_aliases(&self, _: RoomState, _: &AliasesEvent) {} /// Fires when `AsyncClient` receives a `StateEvent::RoomAvatar` event. - async fn on_state_avatar(&self, _: Arc>, _: &AvatarEvent) {} + async fn on_state_avatar(&self, _: RoomState, _: &AvatarEvent) {} /// Fires when `AsyncClient` receives a `StateEvent::RoomPowerLevels` event. - async fn on_state_power_levels(&self, _: Arc>, _: &PowerLevelsEvent) {} + async fn on_state_power_levels(&self, _: RoomState, _: &PowerLevelsEvent) {} /// Fires when `AsyncClient` receives a `StateEvent::RoomJoinRules` event. - async fn on_state_join_rules(&self, _: Arc>, _: &JoinRulesEvent) {} + async fn on_state_join_rules(&self, _: RoomState, _: &JoinRulesEvent) {} // `AnyStrippedStateEvent`s /// Fires when `AsyncClient` receives a `AnyStrippedStateEvent::StrippedRoomMember` event. - async fn on_stripped_state_member(&self, _: Arc>, _: &StrippedRoomMember) {} + async fn on_stripped_state_member(&self, _: RoomState, _: &StrippedRoomMember) {} /// Fires when `AsyncClient` receives a `AnyStrippedStateEvent::StrippedRoomName` event. - async fn on_stripped_state_name(&self, _: Arc>, _: &StrippedRoomName) {} + async fn on_stripped_state_name(&self, _: RoomState, _: &StrippedRoomName) {} /// Fires when `AsyncClient` receives a `AnyStrippedStateEvent::StrippedRoomCanonicalAlias` event. async fn on_stripped_state_canonical_alias( &self, - _: Arc>, + _: RoomState, _: &StrippedRoomCanonicalAlias, ) { } /// Fires when `AsyncClient` receives a `AnyStrippedStateEvent::StrippedRoomAliases` event. - async fn on_stripped_state_aliases(&self, _: Arc>, _: &StrippedRoomAliases) {} + async fn on_stripped_state_aliases(&self, _: RoomState, _: &StrippedRoomAliases) {} /// Fires when `AsyncClient` receives a `AnyStrippedStateEvent::StrippedRoomAvatar` event. - async fn on_stripped_state_avatar(&self, _: Arc>, _: &StrippedRoomAvatar) {} + async fn on_stripped_state_avatar(&self, _: RoomState, _: &StrippedRoomAvatar) {} /// Fires when `AsyncClient` receives a `AnyStrippedStateEvent::StrippedRoomPowerLevels` event. - async fn on_stripped_state_power_levels( - &self, - _: Arc>, - _: &StrippedRoomPowerLevels, - ) { - } + async fn on_stripped_state_power_levels(&self, _: RoomState, _: &StrippedRoomPowerLevels) {} /// Fires when `AsyncClient` receives a `AnyStrippedStateEvent::StrippedRoomJoinRules` event. - async fn on_stripped_state_join_rules(&self, _: Arc>, _: &StrippedRoomJoinRules) {} + async fn on_stripped_state_join_rules(&self, _: RoomState, _: &StrippedRoomJoinRules) {} // `NonRoomEvent` (this is a type alias from ruma_events) from `IncomingAccountData` /// Fires when `AsyncClient` receives a `NonRoomEvent::RoomMember` event. - async fn on_account_presence(&self, _: Arc>, _: &PresenceEvent) {} + async fn on_account_presence(&self, _: RoomState, _: &PresenceEvent) {} /// Fires when `AsyncClient` receives a `NonRoomEvent::RoomName` event. - async fn on_account_ignored_users(&self, _: Arc>, _: &IgnoredUserListEvent) {} + async fn on_account_ignored_users(&self, _: RoomState, _: &IgnoredUserListEvent) {} /// Fires when `AsyncClient` receives a `NonRoomEvent::RoomCanonicalAlias` event. - async fn on_account_push_rules(&self, _: Arc>, _: &PushRulesEvent) {} + async fn on_account_push_rules(&self, _: RoomState, _: &PushRulesEvent) {} /// Fires when `AsyncClient` receives a `NonRoomEvent::RoomAliases` event. - async fn on_account_data_fully_read(&self, _: Arc>, _: &FullyReadEvent) {} + async fn on_account_data_fully_read(&self, _: RoomState, _: &FullyReadEvent) {} // `PresenceEvent` is a struct so there is only the one method /// Fires when `AsyncClient` receives a `NonRoomEvent::RoomAliases` event. - async fn on_presence_event(&self, _: Arc>, _: &PresenceEvent) {} + async fn on_presence_event(&self, _: RoomState, _: &PresenceEvent) {} } #[cfg(test)] @@ -173,71 +168,71 @@ mod test { #[async_trait::async_trait] impl EventEmitter for EvEmitterTest { - async fn on_room_member(&self, _: Arc>, _: &MemberEvent) { + async fn on_room_member(&self, _: RoomState, _: &MemberEvent) { self.0.lock().await.push("member".to_string()) } - async fn on_room_name(&self, _: Arc>, _: &NameEvent) { + async fn on_room_name(&self, _: RoomState, _: &NameEvent) { self.0.lock().await.push("name".to_string()) } - async fn on_room_canonical_alias(&self, _: Arc>, _: &CanonicalAliasEvent) { + async fn on_room_canonical_alias(&self, _: RoomState, _: &CanonicalAliasEvent) { self.0.lock().await.push("canonical".to_string()) } - async fn on_room_aliases(&self, _: Arc>, _: &AliasesEvent) { + async fn on_room_aliases(&self, _: RoomState, _: &AliasesEvent) { self.0.lock().await.push("aliases".to_string()) } - async fn on_room_avatar(&self, _: Arc>, _: &AvatarEvent) { + async fn on_room_avatar(&self, _: RoomState, _: &AvatarEvent) { self.0.lock().await.push("avatar".to_string()) } - async fn on_room_message(&self, _: Arc>, _: &MessageEvent) { + async fn on_room_message(&self, _: RoomState, _: &MessageEvent) { self.0.lock().await.push("message".to_string()) } - async fn on_room_message_feedback(&self, _: Arc>, _: &FeedbackEvent) { + async fn on_room_message_feedback(&self, _: RoomState, _: &FeedbackEvent) { self.0.lock().await.push("feedback".to_string()) } - async fn on_room_redaction(&self, _: Arc>, _: &RedactionEvent) { + async fn on_room_redaction(&self, _: RoomState, _: &RedactionEvent) { self.0.lock().await.push("redaction".to_string()) } - async fn on_room_power_levels(&self, _: Arc>, _: &PowerLevelsEvent) { + async fn on_room_power_levels(&self, _: RoomState, _: &PowerLevelsEvent) { self.0.lock().await.push("power".to_string()) } - async fn on_room_tombstone(&self, _: Arc>, _: &TombstoneEvent) { + async fn on_room_tombstone(&self, _: RoomState, _: &TombstoneEvent) { self.0.lock().await.push("tombstone".to_string()) } - async fn on_state_member(&self, _: Arc>, _: &MemberEvent) { + async fn on_state_member(&self, _: RoomState, _: &MemberEvent) { self.0.lock().await.push("state member".to_string()) } - async fn on_state_name(&self, _: Arc>, _: &NameEvent) { + async fn on_state_name(&self, _: RoomState, _: &NameEvent) { self.0.lock().await.push("state name".to_string()) } - async fn on_state_canonical_alias(&self, _: Arc>, _: &CanonicalAliasEvent) { + async fn on_state_canonical_alias(&self, _: RoomState, _: &CanonicalAliasEvent) { self.0.lock().await.push("state canonical".to_string()) } - async fn on_state_aliases(&self, _: Arc>, _: &AliasesEvent) { + async fn on_state_aliases(&self, _: RoomState, _: &AliasesEvent) { self.0.lock().await.push("state aliases".to_string()) } - async fn on_state_avatar(&self, _: Arc>, _: &AvatarEvent) { + async fn on_state_avatar(&self, _: RoomState, _: &AvatarEvent) { self.0.lock().await.push("state avatar".to_string()) } - async fn on_state_power_levels(&self, _: Arc>, _: &PowerLevelsEvent) { + async fn on_state_power_levels(&self, _: RoomState, _: &PowerLevelsEvent) { self.0.lock().await.push("state power".to_string()) } - async fn on_state_join_rules(&self, _: Arc>, _: &JoinRulesEvent) { + async fn on_state_join_rules(&self, _: RoomState, _: &JoinRulesEvent) { self.0.lock().await.push("state rules".to_string()) } - async fn on_stripped_state_member(&self, _: Arc>, _: &StrippedRoomMember) { + async fn on_stripped_state_member(&self, _: RoomState, _: &StrippedRoomMember) { self.0 .lock() .await .push("stripped state member".to_string()) } - async fn on_stripped_state_name(&self, _: Arc>, _: &StrippedRoomName) { + async fn on_stripped_state_name(&self, _: RoomState, _: &StrippedRoomName) { self.0.lock().await.push("stripped state name".to_string()) } async fn on_stripped_state_canonical_alias( &self, - _: Arc>, + _: RoomState, _: &StrippedRoomCanonicalAlias, ) { self.0 @@ -245,46 +240,38 @@ mod test { .await .push("stripped state canonical".to_string()) } - async fn on_stripped_state_aliases(&self, _: Arc>, _: &StrippedRoomAliases) { + async fn on_stripped_state_aliases(&self, _: RoomState, _: &StrippedRoomAliases) { self.0 .lock() .await .push("stripped state aliases".to_string()) } - async fn on_stripped_state_avatar(&self, _: Arc>, _: &StrippedRoomAvatar) { + async fn on_stripped_state_avatar(&self, _: RoomState, _: &StrippedRoomAvatar) { self.0 .lock() .await .push("stripped state avatar".to_string()) } - async fn on_stripped_state_power_levels( - &self, - _: Arc>, - _: &StrippedRoomPowerLevels, - ) { + async fn on_stripped_state_power_levels(&self, _: RoomState, _: &StrippedRoomPowerLevels) { self.0.lock().await.push("stripped state power".to_string()) } - async fn on_stripped_state_join_rules( - &self, - _: Arc>, - _: &StrippedRoomJoinRules, - ) { + async fn on_stripped_state_join_rules(&self, _: RoomState, _: &StrippedRoomJoinRules) { self.0.lock().await.push("stripped state rules".to_string()) } - async fn on_account_presence(&self, _: Arc>, _: &PresenceEvent) { + async fn on_account_presence(&self, _: RoomState, _: &PresenceEvent) { self.0.lock().await.push("account presence".to_string()) } - async fn on_account_ignored_users(&self, _: Arc>, _: &IgnoredUserListEvent) { + async fn on_account_ignored_users(&self, _: RoomState, _: &IgnoredUserListEvent) { self.0.lock().await.push("account ignore".to_string()) } - async fn on_account_push_rules(&self, _: Arc>, _: &PushRulesEvent) { + async fn on_account_push_rules(&self, _: RoomState, _: &PushRulesEvent) { self.0.lock().await.push("".to_string()) } - async fn on_account_data_fully_read(&self, _: Arc>, _: &FullyReadEvent) { + async fn on_account_data_fully_read(&self, _: RoomState, _: &FullyReadEvent) { self.0.lock().await.push("account read".to_string()) } - async fn on_presence_event(&self, _: Arc>, _: &PresenceEvent) { + async fn on_presence_event(&self, _: RoomState, _: &PresenceEvent) { self.0.lock().await.push("presence event".to_string()) } } @@ -330,7 +317,6 @@ mod test { assert_eq!( v.as_slice(), [ - "state rules", "state member", "state aliases", "state power", @@ -340,7 +326,7 @@ mod test { "message", "account read", "account ignore", - "presence event", + "presence event" ], ) } @@ -410,14 +396,13 @@ mod test { assert_eq!( v.as_slice(), [ - "message", - "state rules", "state member", "state aliases", "state power", "state canonical", "state member", - "state member" + "state member", + "message" ], ) } diff --git a/matrix_sdk/src/lib.rs b/matrix_sdk/src/lib.rs index 8999e450..ac07fb34 100644 --- a/matrix_sdk/src/lib.rs +++ b/matrix_sdk/src/lib.rs @@ -43,7 +43,7 @@ mod state; pub mod test_builder; pub use async_client::{AsyncClient, AsyncClientConfig, SyncSettings}; -pub use base_client::Client; +pub use base_client::{Client, RoomState, RoomStateType}; pub use event_emitter::EventEmitter; #[cfg(feature = "encryption")] pub use matrix_sdk_crypto::{Device, TrustState};