diff --git a/examples/login.rs b/examples/login.rs index 088895e6..561795e6 100644 --- a/examples/login.rs +++ b/examples/login.rs @@ -28,7 +28,11 @@ async fn async_cb(room: Arc>, event: Arc>) { let member = room.members.get(&sender.to_string()).unwrap(); println!( "{}: {}", - member.user.display_name.as_ref().unwrap_or(&sender.to_string()), + member + .user + .display_name + .as_ref() + .unwrap_or(&sender.to_string()), msg_body ); } diff --git a/src/async_client.rs b/src/async_client.rs index 8fe5d916..90b8bdce 100644 --- a/src/async_client.rs +++ b/src/async_client.rs @@ -38,7 +38,6 @@ use ruma_identifiers::RoomId; use crate::api; use crate::base_client::Client as BaseClient; use crate::models::Room; -use crate::error::{Error, InnerError}; use crate::session::Session; use crate::VERSION; use crate::{Error, Result}; @@ -266,7 +265,7 @@ impl AsyncClient { pub fn base_client(&self) -> Arc> { Arc::clone(&self.base_client) } - + /// Calculate the room name from a `RoomId`, returning a string. pub async fn get_room_name(&self, room_id: &str) -> Option { self.base_client.read().await.calculate_room_name(room_id) @@ -424,16 +423,14 @@ impl AsyncClient { if let Some(e) = decrypted_event { *event = e; } - + for presence in &response.presence.events { let mut client = self.base_client.write().await; if let EventResult::Ok(e) = presence { - client.receive_presence_event(&room_id, e); + client.receive_presence_event(&room_id_string, e); } } - let event = Arc::new(event.clone()); - let callbacks = { let mut cb_futures = self.event_callbacks.lock().unwrap(); @@ -446,7 +443,7 @@ impl AsyncClient { let mut callbacks = Vec::new(); for cb in &mut cb_futures.iter_mut() { - callbacks.push(cb(matrix_room.clone(), event.clone())); + callbacks.push(cb(matrix_room.clone(), Arc::clone(&event))); } callbacks diff --git a/src/base_client.rs b/src/base_client.rs index 93b8b6b7..30a1d0aa 100644 --- a/src/base_client.rs +++ b/src/base_client.rs @@ -21,17 +21,17 @@ use std::result::Result as StdResult; use crate::api::r0 as api; use crate::error::Result; use crate::events::collections::all::{RoomEvent, StateEvent}; +use crate::events::presence::PresenceEvent; use crate::events::room::{ aliases::AliasesEvent, canonical_alias::CanonicalAliasEvent, member::{MemberEvent, MembershipState}, name::NameEvent, }; -use crate::events::presence::PresenceEvent; use crate::events::EventResult; use crate::identifiers::RoomAliasId; +use crate::models::Room; use crate::session::Session; -use crate::models::{Room}; use std::sync::{Arc, RwLock}; #[cfg(feature = "encryption")] diff --git a/src/event_emitter/mod.rs b/src/event_emitter/mod.rs index 7bce3fc1..93133a2d 100644 --- a/src/event_emitter/mod.rs +++ b/src/event_emitter/mod.rs @@ -13,32 +13,35 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::collections::HashMap; -use std::sync::{Arc, RwLock}; - -use crate::api::r0 as api; -use crate::events::collections::all::{Event, RoomEvent, StateEvent}; -use crate::events::room::{ - aliases::AliasesEvent, - canonical_alias::CanonicalAliasEvent, - member::{MemberEvent, MemberEventContent, MembershipState}, - name::NameEvent, -}; -use crate::events::EventResult; -use crate::identifiers::RoomAliasId; -use crate::session::Session; +use crate::events::collections::all::RoomEvent; use crate::models::Room; -use js_int::{Int, UInt}; -#[cfg(feature = "encryption")] -use tokio::sync::Mutex; - -#[cfg(feature = "encryption")] -use crate::crypto::{OlmMachine, OneTimeKeys}; -#[cfg(feature = "encryption")] -use ruma_client_api::r0::keys::{upload_keys::Response as KeysUploadResponse, DeviceKeys}; +// JUST AN IDEA +// +/// This is just a thought I had. Making users impl a trait instead of writing callbacks for events +/// could give the chance for really good documentation for each event? +/// It would look something like this +/// +/// ```rust,ignore +/// use matrix-sdk::{AsyncClient, EventEmitter}; +/// +/// struct MyAppClient; +/// +/// impl EventEmitter for MyAppClient { +/// fn on_room_member(&mut self, room: &Room, event: &RoomEvent) { ... } +/// } +/// async fn main() { +/// let cl = AsyncClient::with_emitter(MyAppClient); +/// } +/// ``` +/// +/// And in `AsyncClient::sync` there could be a switch case that calls the corresponding method on +/// the `Box pub trait EventEmitter { - fn on_room_name(&mut self, _: &Room) {} - fn on_room_member(&mut self, _: &Room) {} + fn on_room_name(&mut self, _: &Room, _: &RoomEvent) {} + /// Any event that alters the state of the room's members + fn on_room_member(&mut self, _: &Room, _: &RoomEvent) {} } + + diff --git a/src/lib.rs b/src/lib.rs index 8e3ffb0f..6014c21d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,9 +35,9 @@ pub use ruma_identifiers as identifiers; mod async_client; mod base_client; mod error; +mod event_emitter; mod models; mod session; -mod event_emitter; #[cfg(feature = "encryption")] mod crypto; diff --git a/src/models/mod.rs b/src/models/mod.rs index 4e2d3307..cbc7422e 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -1,51 +1,6 @@ -use crate::events::{ - call::{ - answer::AnswerEvent, candidates::CandidatesEvent, hangup::HangupEvent, invite::InviteEvent, - }, - direct::DirectEvent, - dummy::DummyEvent, - forwarded_room_key::ForwardedRoomKeyEvent, - fully_read::FullyReadEvent, - ignored_user_list::IgnoredUserListEvent, - key::verification::{ - accept::AcceptEvent, cancel::CancelEvent, key::KeyEvent, mac::MacEvent, - request::RequestEvent, start::StartEvent, - }, - presence::PresenceEvent, - push_rules::PushRulesEvent, - receipt::ReceiptEvent, - room::{ - aliases::AliasesEvent, - avatar::AvatarEvent, - canonical_alias::CanonicalAliasEvent, - create::CreateEvent, - encrypted::EncryptedEvent, - encryption::EncryptionEvent, - guest_access::GuestAccessEvent, - history_visibility::HistoryVisibilityEvent, - join_rules::JoinRulesEvent, - member::MemberEvent, - message::{feedback::FeedbackEvent, MessageEvent}, - name::NameEvent, - pinned_events::PinnedEventsEvent, - power_levels::PowerLevelsEvent, - redaction::RedactionEvent, - server_acl::ServerAclEvent, - third_party_invite::ThirdPartyInviteEvent, - tombstone::TombstoneEvent, - topic::TopicEvent, - }, - room_key::RoomKeyEvent, - room_key_request::RoomKeyRequestEvent, - sticker::StickerEvent, - tag::TagEvent, - typing::TypingEvent, - CustomEvent, CustomRoomEvent, CustomStateEvent, -}; - +mod room; mod room_member; mod room_state; -mod room; mod user; pub use room::{Room, RoomName}; @@ -53,145 +8,4 @@ pub use room_member::RoomMember; pub use user::User; pub type Token = String; -pub type RoomId = String; pub type UserId = String; - -pub enum EventWrapper<'ev> { - /// m.call.answer - CallAnswer(&'ev AnswerEvent), - - /// m.call.candidates - CallCandidates(&'ev CandidatesEvent), - - /// m.call.hangup - CallHangup(&'ev HangupEvent), - - /// m.call.invite - CallInvite(&'ev InviteEvent), - - /// m.direct - Direct(&'ev DirectEvent), - - /// m.dummy - Dummy(&'ev DummyEvent), - - /// m.forwarded_room_key - ForwardedRoomKey(&'ev ForwardedRoomKeyEvent), - - /// m.fully_read - FullyRead(&'ev FullyReadEvent), - - /// m.ignored_user_list - IgnoredUserList(&'ev IgnoredUserListEvent), - - /// m.key.verification.accept - KeyVerificationAccept(&'ev AcceptEvent), - - /// m.key.verification.cancel - KeyVerificationCancel(&'ev CancelEvent), - - /// m.key.verification.key - KeyVerificationKey(&'ev KeyEvent), - - /// m.key.verification.mac - KeyVerificationMac(&'ev MacEvent), - - /// m.key.verification.request - KeyVerificationRequest(&'ev RequestEvent), - - /// m.key.verification.start - KeyVerificationStart(&'ev StartEvent), - - /// m.presence - Presence(&'ev PresenceEvent), - - /// m.push_rules - PushRules(&'ev PushRulesEvent), - - /// m.receipt - Receipt(&'ev ReceiptEvent), - - /// m.room.aliases - RoomAliases(&'ev AliasesEvent), - - /// m.room.avatar - RoomAvatar(&'ev AvatarEvent), - - /// m.room.canonical_alias - RoomCanonicalAlias(&'ev CanonicalAliasEvent), - - /// m.room.create - RoomCreate(&'ev CreateEvent), - - /// m.room.encrypted - RoomEncrypted(&'ev EncryptedEvent), - - /// m.room.encryption - RoomEncryption(&'ev EncryptionEvent), - - /// m.room.guest_access - RoomGuestAccess(&'ev GuestAccessEvent), - - /// m.room.history_visibility - RoomHistoryVisibility(&'ev HistoryVisibilityEvent), - - /// m.room.join_rules - RoomJoinRules(&'ev JoinRulesEvent), - - /// m.room.member - RoomMember(&'ev MemberEvent), - - /// m.room.message - RoomMessage(&'ev MessageEvent), - - /// m.room.message.feedback - RoomMessageFeedback(&'ev FeedbackEvent), - - /// m.room.name - RoomName(&'ev NameEvent), - - /// m.room.pinned_events - RoomPinnedEvents(&'ev PinnedEventsEvent), - - /// m.room.power_levels - RoomPowerLevels(&'ev PowerLevelsEvent), - - /// m.room.redaction - RoomRedaction(&'ev RedactionEvent), - - /// m.room.server_acl - RoomServerAcl(&'ev ServerAclEvent), - - /// m.room.third_party_invite - RoomThirdPartyInvite(&'ev ThirdPartyInviteEvent), - - /// m.room.tombstone - RoomTombstone(&'ev TombstoneEvent), - - /// m.room.topic - RoomTopic(&'ev TopicEvent), - - /// m.room_key - RoomKey(&'ev RoomKeyEvent), - - /// m.room_key_request - RoomKeyRequest(&'ev RoomKeyRequestEvent), - - /// m.sticker - Sticker(&'ev StickerEvent), - - /// m.tag - Tag(&'ev TagEvent), - - /// m.typing - Typing(&'ev TypingEvent), - - /// Any basic event that is not part of the specification. - Custom(&'ev CustomEvent), - - /// Any room event that is not part of the specification. - CustomRoom(&'ev CustomRoomEvent), - - /// Any state event that is not part of the specification. - CustomState(&'ev CustomStateEvent), -} diff --git a/src/models/room.rs b/src/models/room.rs index deea05ad..e85c6a13 100644 --- a/src/models/room.rs +++ b/src/models/room.rs @@ -16,6 +16,7 @@ use std::collections::HashMap; use std::sync::{Arc, RwLock}; +use super::{RoomMember, User, UserId}; use crate::api::r0 as api; use crate::events::collections::all::{RoomEvent, StateEvent}; use crate::events::room::{ @@ -24,10 +25,12 @@ use crate::events::room::{ member::{MemberEvent, MembershipState}, name::NameEvent, }; -use crate::events::{presence::{PresenceEvent, PresenceEventContent}, EventResult}; +use crate::events::{ + presence::{PresenceEvent, PresenceEventContent}, + EventResult, +}; use crate::identifiers::RoomAliasId; use crate::session::Session; -use super::{RoomId, UserId, RoomMember, User}; #[cfg(feature = "encryption")] use tokio::sync::Mutex; @@ -52,7 +55,7 @@ pub struct RoomName { /// A Matrix rooom. pub struct Room { /// The unique id of the room. - pub room_id: RoomId, + pub room_id: String, /// The name of the room, clients use this to represent a room. pub room_name: RoomName, /// The mxid of our own user. @@ -175,11 +178,11 @@ impl Room { // } // fn handle_leave(&mut self, event: &MemberEvent) -> bool { - + // } /// Handle a room.member updating the room state if necessary. - /// + /// /// Returns true if the joined member list changed, false otherwise. pub fn handle_membership(&mut self, event: &MemberEvent) -> bool { match &event.content.membership { @@ -214,7 +217,7 @@ impl Room { } /// Handle a room.aliases event, updating the room state if necessary. - /// + /// /// Returns true if the room name changed, false otherwise. pub fn handle_room_aliases(&mut self, event: &AliasesEvent) -> bool { match event.content.aliases.as_slice() { @@ -225,7 +228,7 @@ impl Room { } /// Handle a room.canonical_alias event, updating the room state if necessary. - /// + /// /// Returns true if the room name changed, false otherwise. pub fn handle_canonical(&mut self, event: &CanonicalAliasEvent) -> bool { match &event.content.alias { @@ -235,7 +238,7 @@ impl Room { } /// Handle a room.name event, updating the room state if necessary. - /// + /// /// Returns true if the room name changed, false otherwise. pub fn handle_room_name(&mut self, event: &NameEvent) -> bool { match event.content.name() { @@ -291,21 +294,29 @@ impl Room { /// * `event` - The event of the room. pub fn receive_presence_event(&mut self, event: &PresenceEvent) -> bool { let PresenceEvent { - content: PresenceEventContent { - avatar_url, - currently_active, - displayname, - last_active_ago, - presence, - status_msg, - }, + content: + PresenceEventContent { + avatar_url, + currently_active, + displayname, + last_active_ago, + presence, + status_msg, + }, sender, } = event; - if let Some(user) = self.members.get_mut(&sender.to_string()).map(|m| &mut m.user) { - if user.display_name == *displayname && user.avatar_url == *avatar_url - && user.presence.as_ref() == Some(presence) && user.status_msg == *status_msg - && user.last_active_ago == *last_active_ago && user.currently_active == *currently_active + if let Some(user) = self + .members + .get_mut(&sender.to_string()) + .map(|m| &mut m.user) + { + if user.display_name == *displayname + && user.avatar_url == *avatar_url + && user.presence.as_ref() == Some(presence) + && user.status_msg == *status_msg + && user.last_active_ago == *last_active_ago + && user.currently_active == *currently_active { false } else { diff --git a/src/models/room_member.rs b/src/models/room_member.rs index c8f67ef8..33105ac0 100644 --- a/src/models/room_member.rs +++ b/src/models/room_member.rs @@ -16,6 +16,7 @@ use std::collections::HashMap; use std::sync::{Arc, RwLock}; +use super::{User, UserId}; use crate::api::r0 as api; use crate::events::collections::all::{Event, RoomEvent, StateEvent}; use crate::events::room::{ @@ -27,7 +28,6 @@ use crate::events::room::{ use crate::events::EventResult; use crate::identifiers::RoomAliasId; use crate::session::Session; -use super::{UserId, RoomId, User}; use js_int::{Int, UInt}; #[cfg(feature = "encryption")] @@ -44,7 +44,7 @@ pub struct RoomMember { /// The unique mxid of the user. pub user_id: UserId, /// The unique id of the room. - pub room_id: Option, + pub room_id: Option, /// If the member is typing. pub typing: Option, /// The user data for this room member. @@ -58,7 +58,7 @@ pub struct RoomMember { /// The human readable name of this room member. pub name: String, /// The events that created the state of this room member. - pub events: Vec + pub events: Vec, } impl RoomMember { @@ -73,26 +73,30 @@ impl RoomMember { power_level_norm: None, membership: event.content.membership, name: event.state_key.clone(), - events: vec![Event::RoomMember(event.clone())] + events: vec![Event::RoomMember(event.clone())], } } pub fn update(&mut self, event: &MemberEvent) { let MemberEvent { - content: MemberEventContent { - membership, - .. - }, + content: MemberEventContent { membership, .. }, room_id, state_key, .. } = event; let mut events = Vec::new(); - events.extend(self.events.drain(..).chain(Some(Event::RoomMember(event.clone())))); + events.extend( + self.events + .drain(..) + .chain(Some(Event::RoomMember(event.clone()))), + ); *self = Self { - room_id: room_id.as_ref().map(|id| id.to_string()).or(self.room_id.take()), + room_id: room_id + .as_ref() + .map(|id| id.to_string()) + .or(self.room_id.take()), user_id: state_key.clone(), typing: None, user: User::new(event), diff --git a/src/models/room_state.rs b/src/models/room_state.rs index e69de29b..2bbbb490 100644 --- a/src/models/room_state.rs +++ b/src/models/room_state.rs @@ -0,0 +1,15 @@ +// Copyright 2020 Damir Jelić +// Copyright 2020 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// 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. + diff --git a/src/models/user.rs b/src/models/user.rs index 060ec88c..f9840e32 100644 --- a/src/models/user.rs +++ b/src/models/user.rs @@ -16,19 +16,19 @@ use std::collections::HashMap; use std::sync::{Arc, RwLock}; +use super::UserId; use crate::api::r0 as api; use crate::events::collections::all::{Event, RoomEvent, StateEvent}; +use crate::events::presence::{PresenceEvent, PresenceState}; use crate::events::room::{ aliases::AliasesEvent, canonical_alias::CanonicalAliasEvent, member::{MemberEvent, MembershipState}, name::NameEvent, }; -use crate::events::presence::{PresenceEvent, PresenceState}; use crate::events::EventResult; use crate::identifiers::RoomAliasId; use crate::session::Session; -use super::{UserId, RoomId}; use js_int::UInt; #[cfg(feature = "encryption")] diff --git a/tests/async_client_tests.rs b/tests/async_client_tests.rs index 4b942e23..0c213d0c 100644 --- a/tests/async_client_tests.rs +++ b/tests/async_client_tests.rs @@ -90,38 +90,3 @@ async fn timeline() { println!("{:#?}", &client.base_client().read().await.joined_rooms); } - -#[test] -fn timeline() { - let mut rt = Runtime::new().unwrap(); - - let homeserver = Url::from_str(&mockito::server_url()).unwrap(); - - let session = Session { - access_token: "1234".to_owned(), - user_id: UserId::try_from("@example:example.com").unwrap(), - device_id: "DEVICEID".to_owned(), - }; - - let _m = mock( - "GET", - Matcher::Regex(r"^/_matrix/client/r0/sync\?.*$".to_string()), - ) - .with_status(200) - .with_body_from_file("tests/data/sync.json") - .create(); - - let mut client = AsyncClient::new(homeserver, Some(session)).unwrap(); - - let sync_settings = SyncSettings::new().timeout(3000).unwrap(); - - let _response = rt.block_on(client.sync(sync_settings)).unwrap(); - - assert_eq!(vec!["tutorial"], rt.block_on(client.get_room_names())); - assert_eq!( - Some("tutorial".into()), - rt.block_on(client.get_room_name("!SVkFJHzfwvuaIEawgC:localhost")) - ); - - rt.block_on(async { println!("{:#?}", &client.base_client().read().await.joined_rooms ) }); -}