diff --git a/examples/command_bot.rs b/examples/command_bot.rs index c3004280..56925416 100644 --- a/examples/command_bot.rs +++ b/examples/command_bot.rs @@ -1,4 +1,6 @@ +use std::sync::Arc; use std::{env, process::exit}; + use url::Url; use matrix_sdk::{ @@ -6,7 +8,7 @@ use matrix_sdk::{ events::room::message::{MessageEvent, MessageEventContent, TextMessageEventContent}, AsyncClient, AsyncClientConfig, EventEmitter, Room, SyncSettings, }; -use tokio::sync::Mutex; +use tokio::sync::{Mutex, RwLock}; struct CommandBot { client: Mutex, @@ -22,7 +24,7 @@ impl CommandBot { #[async_trait::async_trait] impl EventEmitter for CommandBot { - async fn on_room_message(&self, room: &Room, event: &MessageEvent) { + async fn on_room_message(&self, room: Arc>, event: &MessageEvent) { let msg_body = if let MessageEvent { content: MessageEventContent::Text(TextMessageEventContent { body: msg_body, .. }), .. @@ -40,7 +42,7 @@ impl EventEmitter for CommandBot { formatted_body: None, relates_to: None, }); - let room_id = &room.room_id; + let room_id = { room.read().await.room_id.clone() }; println!("sending"); @@ -62,9 +64,10 @@ async fn login_and_sync( username: String, password: String, ) -> Result<(), matrix_sdk::Error> { - let client_config = AsyncClientConfig::new(); - // .proxy("http://localhost:8080")? - // .disable_ssl_verification(); + let client_config = AsyncClientConfig::new() + .proxy("http://localhost:8080")? + .disable_ssl_verification(); + let homeserver_url = Url::parse(&homeserver_url)?; let mut client = AsyncClient::new_with_config(homeserver_url, None, client_config).unwrap(); diff --git a/examples/login.rs b/examples/login.rs index 34f943a2..703fd2e0 100644 --- a/examples/login.rs +++ b/examples/login.rs @@ -1,4 +1,3 @@ -use std::ops::Deref; use std::sync::Arc; use std::{env, process::exit}; use url::Url; @@ -8,25 +7,30 @@ use matrix_sdk::{ events::room::message::{MessageEvent, MessageEventContent, TextMessageEventContent}, AsyncClient, AsyncClientConfig, EventEmitter, Room, SyncSettings, }; -use tokio::sync::Mutex; +use tokio::sync::RwLock; struct EventCallback; #[async_trait::async_trait] impl EventEmitter for EventCallback { - async fn on_room_message(&self, room: &Room, event: &MessageEvent) { + async fn on_room_message(&self, room: Arc>, event: &MessageEvent) { if let MessageEvent { content: MessageEventContent::Text(TextMessageEventContent { body: msg_body, .. }), sender, .. } = event { - let member = room.members.get(&sender).unwrap(); - println!( - "{}: {}", - member.display_name.as_ref().unwrap_or(&sender.to_string()), - msg_body - ); + let name = { + // any reads or + 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/src/base_client.rs b/src/base_client.rs index 5c8a5bf3..686f8c15 100644 --- a/src/base_client.rs +++ b/src/base_client.rs @@ -17,7 +17,6 @@ use std::collections::HashMap; #[cfg(feature = "encryption")] use std::collections::HashSet; use std::fmt; -use std::ops::Deref; use std::sync::Arc; #[cfg(feature = "encryption")] @@ -578,21 +577,21 @@ impl Client { RoomEvent::RoomMember(mem) => { if let Some(ee) = &self.event_emitter { if let Some(room) = self.get_room(&room_id) { - ee.on_room_member(room.read().await.deref(), &mem).await; + 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(room.read().await.deref(), &name).await; + 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(room.read().await.deref(), &canonical) + ee.on_room_canonical_alias(Arc::clone(&room), &canonical) .await; } } @@ -600,29 +599,28 @@ impl Client { RoomEvent::RoomAliases(aliases) => { if let Some(ee) = &self.event_emitter { if let Some(room) = self.get_room(&room_id) { - ee.on_room_aliases(room.read().await.deref(), &aliases) - .await; + 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(room.read().await.deref(), &avatar).await; + 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(room.read().await.deref(), &msg).await; + 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(room.read().await.deref(), &msg_feedback) + ee.on_room_message_feedback(Arc::clone(&room), &msg_feedback) .await; } } @@ -630,16 +628,14 @@ impl Client { RoomEvent::RoomRedaction(redaction) => { if let Some(ee) = &self.event_emitter { if let Some(room) = self.get_room(&room_id) { - ee.on_room_redaction(room.read().await.deref(), &redaction) - .await; + 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(room.read().await.deref(), &power) - .await; + ee.on_room_power_levels(Arc::clone(&room), &power).await; } } } @@ -652,21 +648,21 @@ impl Client { StateEvent::RoomMember(member) => { if let Some(ee) = &self.event_emitter { if let Some(room) = self.get_room(&room_id) { - ee.on_state_member(room.read().await.deref(), &member).await; + 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(room.read().await.deref(), &name).await; + 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(room.read().await.deref(), &canonical) + ee.on_state_canonical_alias(Arc::clone(&room), &canonical) .await; } } @@ -674,31 +670,28 @@ impl Client { StateEvent::RoomAliases(aliases) => { if let Some(ee) = &self.event_emitter { if let Some(room) = self.get_room(&room_id) { - ee.on_state_aliases(room.read().await.deref(), &aliases) - .await; + 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(room.read().await.deref(), &avatar).await; + 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(room.read().await.deref(), &power) - .await; + 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(room.read().await.deref(), &rules) - .await; + ee.on_state_join_rules(Arc::clone(&room), &rules).await; } } } @@ -711,15 +704,14 @@ impl Client { NonRoomEvent::Presence(presence) => { if let Some(ee) = &self.event_emitter { if let Some(room) = self.get_room(&room_id) { - ee.on_account_presence(room.read().await.deref(), &presence) - .await; + 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(room.read().await.deref(), &ignored) + ee.on_account_ignored_users(Arc::clone(&room), &ignored) .await; } } @@ -727,15 +719,14 @@ impl Client { NonRoomEvent::PushRules(rules) => { if let Some(ee) = &self.event_emitter { if let Some(room) = self.get_room(&room_id) { - ee.on_account_push_rules(room.read().await.deref(), &rules) - .await; + 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(room.read().await.deref(), &full_read) + ee.on_account_data_fully_read(Arc::clone(&room), &full_read) .await; } } @@ -749,15 +740,14 @@ impl Client { NonRoomEvent::Presence(presence) => { if let Some(ee) = &self.event_emitter { if let Some(room) = self.get_room(&room_id) { - ee.on_account_presence(room.read().await.deref(), &presence) - .await; + 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(room.read().await.deref(), &ignored) + ee.on_account_ignored_users(Arc::clone(&room), &ignored) .await; } } @@ -765,15 +755,14 @@ impl Client { NonRoomEvent::PushRules(rules) => { if let Some(ee) = &self.event_emitter { if let Some(room) = self.get_room(&room_id) { - ee.on_account_push_rules(room.read().await.deref(), &rules) - .await; + 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(room.read().await.deref(), &full_read) + ee.on_account_data_fully_read(Arc::clone(&room), &full_read) .await; } } @@ -785,8 +774,7 @@ impl Client { pub(crate) async fn emit_presence_event(&self, room_id: &RoomId, event: &PresenceEvent) { if let Some(ee) = &self.event_emitter { if let Some(room) = self.get_room(&room_id) { - ee.on_presence_event(room.read().await.deref(), &event) - .await; + ee.on_presence_event(Arc::clone(&room), &event).await; } } } diff --git a/src/event_emitter/mod.rs b/src/event_emitter/mod.rs index 6ee62d18..f3afd392 100644 --- a/src/event_emitter/mod.rs +++ b/src/event_emitter/mod.rs @@ -12,6 +12,7 @@ // 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, @@ -31,6 +32,7 @@ use crate::events::{ }, }; use crate::models::Room; +use tokio::sync::RwLock; /// 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. @@ -78,53 +80,53 @@ use crate::models::Room; pub trait EventEmitter: Send + Sync { // ROOM EVENTS from `IncomingTimeline` /// Fires when `AsyncClient` receives a `RoomEvent::RoomMember` event. - async fn on_room_member(&self, _: &Room, _: &MemberEvent) {} + async fn on_room_member(&self, _: Arc>, _: &MemberEvent) {} /// Fires when `AsyncClient` receives a `RoomEvent::RoomName` event. - async fn on_room_name(&self, _: &Room, _: &NameEvent) {} + async fn on_room_name(&self, _: Arc>, _: &NameEvent) {} /// Fires when `AsyncClient` receives a `RoomEvent::RoomCanonicalAlias` event. - async fn on_room_canonical_alias(&self, _: &Room, _: &CanonicalAliasEvent) {} + async fn on_room_canonical_alias(&self, _: Arc>, _: &CanonicalAliasEvent) {} /// Fires when `AsyncClient` receives a `RoomEvent::RoomAliases` event. - async fn on_room_aliases(&self, _: &Room, _: &AliasesEvent) {} + async fn on_room_aliases(&self, _: Arc>, _: &AliasesEvent) {} /// Fires when `AsyncClient` receives a `RoomEvent::RoomAvatar` event. - async fn on_room_avatar(&self, _: &Room, _: &AvatarEvent) {} + async fn on_room_avatar(&self, _: Arc>, _: &AvatarEvent) {} /// Fires when `AsyncClient` receives a `RoomEvent::RoomMessage` event. - async fn on_room_message(&self, _: &Room, _: &MessageEvent) {} + async fn on_room_message(&self, _: Arc>, _: &MessageEvent) {} /// Fires when `AsyncClient` receives a `RoomEvent::RoomMessageFeedback` event. - async fn on_room_message_feedback(&self, _: &Room, _: &FeedbackEvent) {} + async fn on_room_message_feedback(&self, _: Arc>, _: &FeedbackEvent) {} /// Fires when `AsyncClient` receives a `RoomEvent::RoomRedaction` event. - async fn on_room_redaction(&self, _: &Room, _: &RedactionEvent) {} + async fn on_room_redaction(&self, _: Arc>, _: &RedactionEvent) {} /// Fires when `AsyncClient` receives a `RoomEvent::RoomPowerLevels` event. - async fn on_room_power_levels(&self, _: &Room, _: &PowerLevelsEvent) {} + async fn on_room_power_levels(&self, _: Arc>, _: &PowerLevelsEvent) {} // `RoomEvent`s from `IncomingState` /// Fires when `AsyncClient` receives a `StateEvent::RoomMember` event. - async fn on_state_member(&self, _: &Room, _: &MemberEvent) {} + async fn on_state_member(&self, _: Arc>, _: &MemberEvent) {} /// Fires when `AsyncClient` receives a `StateEvent::RoomName` event. - async fn on_state_name(&self, _: &Room, _: &NameEvent) {} + async fn on_state_name(&self, _: Arc>, _: &NameEvent) {} /// Fires when `AsyncClient` receives a `StateEvent::RoomCanonicalAlias` event. - async fn on_state_canonical_alias(&self, _: &Room, _: &CanonicalAliasEvent) {} + async fn on_state_canonical_alias(&self, _: Arc>, _: &CanonicalAliasEvent) {} /// Fires when `AsyncClient` receives a `StateEvent::RoomAliases` event. - async fn on_state_aliases(&self, _: &Room, _: &AliasesEvent) {} + async fn on_state_aliases(&self, _: Arc>, _: &AliasesEvent) {} /// Fires when `AsyncClient` receives a `StateEvent::RoomAvatar` event. - async fn on_state_avatar(&self, _: &Room, _: &AvatarEvent) {} + async fn on_state_avatar(&self, _: Arc>, _: &AvatarEvent) {} /// Fires when `AsyncClient` receives a `StateEvent::RoomPowerLevels` event. - async fn on_state_power_levels(&self, _: &Room, _: &PowerLevelsEvent) {} + async fn on_state_power_levels(&self, _: Arc>, _: &PowerLevelsEvent) {} /// Fires when `AsyncClient` receives a `StateEvent::RoomJoinRules` event. - async fn on_state_join_rules(&self, _: &Room, _: &JoinRulesEvent) {} + async fn on_state_join_rules(&self, _: Arc>, _: &JoinRulesEvent) {} // `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, _: &Room, _: &PresenceEvent) {} + async fn on_account_presence(&self, _: Arc>, _: &PresenceEvent) {} /// Fires when `AsyncClient` receives a `NonRoomEvent::RoomName` event. - async fn on_account_ignored_users(&self, _: &Room, _: &IgnoredUserListEvent) {} + async fn on_account_ignored_users(&self, _: Arc>, _: &IgnoredUserListEvent) {} /// Fires when `AsyncClient` receives a `NonRoomEvent::RoomCanonicalAlias` event. - async fn on_account_push_rules(&self, _: &Room, _: &PushRulesEvent) {} + async fn on_account_push_rules(&self, _: Arc>, _: &PushRulesEvent) {} /// Fires when `AsyncClient` receives a `NonRoomEvent::RoomAliases` event. - async fn on_account_data_fully_read(&self, _: &Room, _: &FullyReadEvent) {} + async fn on_account_data_fully_read(&self, _: Arc>, _: &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, _: &Room, _: &PresenceEvent) {} + async fn on_presence_event(&self, _: Arc>, _: &PresenceEvent) {} } #[cfg(test)] @@ -137,69 +139,69 @@ mod test { #[async_trait::async_trait] impl EventEmitter for EvEmitterTest { - async fn on_room_member(&self, _: &Room, _: &MemberEvent) { + async fn on_room_member(&self, _: Arc>, _: &MemberEvent) { self.0.lock().await.push("member".to_string()) } - async fn on_room_name(&self, _: &Room, _: &NameEvent) { + async fn on_room_name(&self, _: Arc>, _: &NameEvent) { self.0.lock().await.push("name".to_string()) } - async fn on_room_canonical_alias(&self, _: &Room, _: &CanonicalAliasEvent) { + async fn on_room_canonical_alias(&self, _: Arc>, _: &CanonicalAliasEvent) { self.0.lock().await.push("canonical".to_string()) } - async fn on_room_aliases(&self, _: &Room, _: &AliasesEvent) { + async fn on_room_aliases(&self, _: Arc>, _: &AliasesEvent) { self.0.lock().await.push("aliases".to_string()) } - async fn on_room_avatar(&self, _: &Room, _: &AvatarEvent) { + async fn on_room_avatar(&self, _: Arc>, _: &AvatarEvent) { self.0.lock().await.push("avatar".to_string()) } - async fn on_room_message(&self, _: &Room, _: &MessageEvent) { + async fn on_room_message(&self, _: Arc>, _: &MessageEvent) { self.0.lock().await.push("message".to_string()) } - async fn on_room_message_feedback(&self, _: &Room, _: &FeedbackEvent) { + async fn on_room_message_feedback(&self, _: Arc>, _: &FeedbackEvent) { self.0.lock().await.push("feedback".to_string()) } - async fn on_room_redaction(&self, _: &Room, _: &RedactionEvent) { + async fn on_room_redaction(&self, _: Arc>, _: &RedactionEvent) { self.0.lock().await.push("redaction".to_string()) } - async fn on_room_power_levels(&self, _: &Room, _: &PowerLevelsEvent) { + async fn on_room_power_levels(&self, _: Arc>, _: &PowerLevelsEvent) { self.0.lock().await.push("power".to_string()) } - async fn on_state_member(&self, _: &Room, _: &MemberEvent) { + async fn on_state_member(&self, _: Arc>, _: &MemberEvent) { self.0.lock().await.push("state member".to_string()) } - async fn on_state_name(&self, _: &Room, _: &NameEvent) { + async fn on_state_name(&self, _: Arc>, _: &NameEvent) { self.0.lock().await.push("state name".to_string()) } - async fn on_state_canonical_alias(&self, _: &Room, _: &CanonicalAliasEvent) { + async fn on_state_canonical_alias(&self, _: Arc>, _: &CanonicalAliasEvent) { self.0.lock().await.push("state canonical".to_string()) } - async fn on_state_aliases(&self, _: &Room, _: &AliasesEvent) { + async fn on_state_aliases(&self, _: Arc>, _: &AliasesEvent) { self.0.lock().await.push("state aliases".to_string()) } - async fn on_state_avatar(&self, _: &Room, _: &AvatarEvent) { + async fn on_state_avatar(&self, _: Arc>, _: &AvatarEvent) { self.0.lock().await.push("state avatar".to_string()) } - async fn on_state_power_levels(&self, _: &Room, _: &PowerLevelsEvent) { + async fn on_state_power_levels(&self, _: Arc>, _: &PowerLevelsEvent) { self.0.lock().await.push("state power".to_string()) } - async fn on_state_join_rules(&self, _: &Room, _: &JoinRulesEvent) { + async fn on_state_join_rules(&self, _: Arc>, _: &JoinRulesEvent) { self.0.lock().await.push("state rules".to_string()) } - async fn on_account_presence(&self, _: &Room, _: &PresenceEvent) { + async fn on_account_presence(&self, _: Arc>, _: &PresenceEvent) { self.0.lock().await.push("account presence".to_string()) } - async fn on_account_ignored_users(&self, _: &Room, _: &IgnoredUserListEvent) { + async fn on_account_ignored_users(&self, _: Arc>, _: &IgnoredUserListEvent) { self.0.lock().await.push("account ignore".to_string()) } - async fn on_account_push_rules(&self, _: &Room, _: &PushRulesEvent) { + async fn on_account_push_rules(&self, _: Arc>, _: &PushRulesEvent) { self.0.lock().await.push("".to_string()) } - async fn on_account_data_fully_read(&self, _: &Room, _: &FullyReadEvent) { + async fn on_account_data_fully_read(&self, _: Arc>, _: &FullyReadEvent) { self.0.lock().await.push("account read".to_string()) } - async fn on_presence_event(&self, _: &Room, _: &PresenceEvent) { + async fn on_presence_event(&self, _: Arc>, _: &PresenceEvent) { self.0.lock().await.push("presence event".to_string()) } }