move matrix_sdk_base::EventHandler to matrix_sdk

master
Julian Sparber 2021-03-17 11:53:18 +01:00
parent e9dff24ba7
commit 382ec01bc3
9 changed files with 82 additions and 86 deletions

View File

@ -4,7 +4,8 @@ use tokio::time::{sleep, Duration};
use matrix_sdk::{ use matrix_sdk::{
self, async_trait, self, async_trait,
events::{room::member::MemberEventContent, StrippedStateEvent}, events::{room::member::MemberEventContent, StrippedStateEvent},
room, BaseRoom, Client, ClientConfig, EventHandler, SyncSettings, room::Room,
Client, ClientConfig, EventHandler, SyncSettings,
}; };
use url::Url; use url::Url;
@ -22,7 +23,7 @@ impl AutoJoinBot {
impl EventHandler for AutoJoinBot { impl EventHandler for AutoJoinBot {
async fn on_stripped_state_member( async fn on_stripped_state_member(
&self, &self,
room: BaseRoom, room: Room,
room_member: &StrippedStateEvent<MemberEventContent>, room_member: &StrippedStateEvent<MemberEventContent>,
_: Option<MemberEventContent>, _: Option<MemberEventContent>,
) { ) {
@ -30,7 +31,7 @@ impl EventHandler for AutoJoinBot {
return; return;
} }
if let Some(room) = room::Invited::new(self.client.clone(), room) { if let Room::Invited(room) = room {
println!("Autojoining room {}", room.room_id()); println!("Autojoining room {}", room.room_id());
let mut delay = 2; let mut delay = 2;

View File

@ -6,27 +6,23 @@ use matrix_sdk::{
room::message::{MessageEventContent, MessageType, TextMessageEventContent}, room::message::{MessageEventContent, MessageType, TextMessageEventContent},
AnyMessageEventContent, SyncMessageEvent, AnyMessageEventContent, SyncMessageEvent,
}, },
room::Joined, room::Room,
BaseRoom, Client, ClientConfig, EventHandler, SyncSettings, Client, ClientConfig, EventHandler, SyncSettings,
}; };
use url::Url; use url::Url;
struct CommandBot { struct CommandBot;
/// This clone of the `Client` will send requests to the server,
/// while the other keeps us in sync with the server using `sync`.
client: Client,
}
impl CommandBot { impl CommandBot {
pub fn new(client: Client) -> Self { pub fn new() -> Self {
Self { client } Self {}
} }
} }
#[async_trait] #[async_trait]
impl EventHandler for CommandBot { impl EventHandler for CommandBot {
async fn on_room_message(&self, room: BaseRoom, event: &SyncMessageEvent<MessageEventContent>) { async fn on_room_message(&self, room: Room, event: &SyncMessageEvent<MessageEventContent>) {
if let Some(room) = Joined::new(self.client.clone(), room) { if let Room::Joined(room) = room {
let msg_body = if let SyncMessageEvent { let msg_body = if let SyncMessageEvent {
content: content:
MessageEventContent { MessageEventContent {
@ -85,9 +81,7 @@ async fn login_and_sync(
client.sync_once(SyncSettings::default()).await.unwrap(); client.sync_once(SyncSettings::default()).await.unwrap();
// add our CommandBot to be notified of incoming messages, we do this after the initial // add our CommandBot to be notified of incoming messages, we do this after the initial
// sync to avoid responding to messages before the bot was running. // sync to avoid responding to messages before the bot was running.
client client.set_event_handler(Box::new(CommandBot::new())).await;
.set_event_handler(Box::new(CommandBot::new(client.clone())))
.await;
// since we called `sync_once` before we entered our sync loop we must pass // since we called `sync_once` before we entered our sync loop we must pass
// that sync token to `sync` // that sync token to `sync`

View File

@ -14,27 +14,26 @@ use matrix_sdk::{
room::message::{MessageEventContent, MessageType, TextMessageEventContent}, room::message::{MessageEventContent, MessageType, TextMessageEventContent},
SyncMessageEvent, SyncMessageEvent,
}, },
room::Joined, room::Room,
BaseRoom, Client, EventHandler, SyncSettings, Client, EventHandler, SyncSettings,
}; };
use url::Url; use url::Url;
struct ImageBot { struct ImageBot {
client: Client,
image: Arc<Mutex<File>>, image: Arc<Mutex<File>>,
} }
impl ImageBot { impl ImageBot {
pub fn new(client: Client, image: File) -> Self { pub fn new(image: File) -> Self {
let image = Arc::new(Mutex::new(image)); let image = Arc::new(Mutex::new(image));
Self { client, image } Self { image }
} }
} }
#[async_trait] #[async_trait]
impl EventHandler for ImageBot { impl EventHandler for ImageBot {
async fn on_room_message(&self, room: BaseRoom, event: &SyncMessageEvent<MessageEventContent>) { async fn on_room_message(&self, room: Room, event: &SyncMessageEvent<MessageEventContent>) {
if let Some(room) = Joined::new(self.client.clone(), room) { if let Room::Joined(room) = room {
let msg_body = if let SyncMessageEvent { let msg_body = if let SyncMessageEvent {
content: content:
MessageEventContent { MessageEventContent {
@ -80,7 +79,7 @@ async fn login_and_sync(
client.sync_once(SyncSettings::default()).await.unwrap(); client.sync_once(SyncSettings::default()).await.unwrap();
client client
.set_event_handler(Box::new(ImageBot::new(client.clone(), image))) .set_event_handler(Box::new(ImageBot::new(image)))
.await; .await;
let settings = SyncSettings::default().token(client.sync_token().await.unwrap()); let settings = SyncSettings::default().token(client.sync_token().await.unwrap());

View File

@ -7,15 +7,16 @@ use matrix_sdk::{
room::message::{MessageEventContent, MessageType, TextMessageEventContent}, room::message::{MessageEventContent, MessageType, TextMessageEventContent},
SyncMessageEvent, SyncMessageEvent,
}, },
BaseRoom, Client, EventHandler, RoomType, SyncSettings, room::Room,
Client, EventHandler, SyncSettings,
}; };
struct EventCallback; struct EventCallback;
#[async_trait] #[async_trait]
impl EventHandler for EventCallback { impl EventHandler for EventCallback {
async fn on_room_message(&self, room: BaseRoom, event: &SyncMessageEvent<MessageEventContent>) { async fn on_room_message(&self, room: Room, event: &SyncMessageEvent<MessageEventContent>) {
if room.room_type() == RoomType::Joined { if let Room::Joined(room) = room {
if let SyncMessageEvent { if let SyncMessageEvent {
content: content:
MessageEventContent { MessageEventContent {

View File

@ -40,8 +40,7 @@ use tracing::{debug, warn};
use tracing::{error, info, instrument}; use tracing::{error, info, instrument};
use matrix_sdk_base::{ use matrix_sdk_base::{
deserialized_responses::SyncResponse, BaseClient, BaseClientConfig, EventHandler, Session, deserialized_responses::SyncResponse, BaseClient, BaseClientConfig, Session, Store,
Store,
}; };
#[cfg(feature = "encryption")] #[cfg(feature = "encryption")]
@ -82,6 +81,7 @@ use matrix_sdk_common::{
assign, assign,
identifiers::{DeviceIdBox, EventId, RoomId, RoomIdOrAliasId, ServerName, UserId}, identifiers::{DeviceIdBox, EventId, RoomId, RoomIdOrAliasId, ServerName, UserId},
instant::{Duration, Instant}, instant::{Duration, Instant},
locks::RwLock,
presence::PresenceState, presence::PresenceState,
uuid::Uuid, uuid::Uuid,
FromHttpResponseError, UInt, FromHttpResponseError, UInt,
@ -106,9 +106,11 @@ use crate::{
#[cfg(feature = "encryption")] #[cfg(feature = "encryption")]
use crate::{ use crate::{
device::{Device, UserDevices}, device::{Device, UserDevices},
event_handler::Handler,
identifiers::DeviceId, identifiers::DeviceId,
sas::Sas, sas::Sas,
verification_request::VerificationRequest, verification_request::VerificationRequest,
EventHandler,
}; };
const DEFAULT_SYNC_TIMEOUT: Duration = Duration::from_secs(30); const DEFAULT_SYNC_TIMEOUT: Duration = Duration::from_secs(30);
@ -139,6 +141,9 @@ pub struct Client {
key_claim_lock: Arc<Mutex<()>>, key_claim_lock: Arc<Mutex<()>>,
pub(crate) members_request_locks: Arc<DashMap<RoomId, Arc<Mutex<()>>>>, pub(crate) members_request_locks: Arc<DashMap<RoomId, Arc<Mutex<()>>>>,
pub(crate) typing_notice_times: Arc<DashMap<RoomId, Instant>>, pub(crate) typing_notice_times: Arc<DashMap<RoomId, Instant>>,
/// Any implementor of EventHandler will act as the callbacks for various
/// events.
event_handler: Arc<RwLock<Option<Handler>>>,
} }
#[cfg(not(tarpaulin_include))] #[cfg(not(tarpaulin_include))]
@ -396,6 +401,7 @@ impl Client {
key_claim_lock: Arc::new(Mutex::new(())), key_claim_lock: Arc::new(Mutex::new(())),
members_request_locks: Arc::new(DashMap::new()), members_request_locks: Arc::new(DashMap::new()),
typing_notice_times: Arc::new(DashMap::new()), typing_notice_times: Arc::new(DashMap::new()),
event_handler: Arc::new(RwLock::new(None)),
}) })
} }
@ -541,7 +547,11 @@ impl Client {
/// ///
/// The methods of `EventHandler` are called when the respective `RoomEvents` occur. /// The methods of `EventHandler` are called when the respective `RoomEvents` occur.
pub async fn set_event_handler(&self, handler: Box<dyn EventHandler>) { pub async fn set_event_handler(&self, handler: Box<dyn EventHandler>) {
self.base_client.set_event_handler(handler).await; let handler = Handler {
inner: handler,
client: self.clone(),
};
*self.event_handler.write().await = Some(handler);
} }
/// Get all the rooms the client knows about. /// Get all the rooms the client knows about.
@ -1180,8 +1190,13 @@ impl Client {
+ SYNC_REQUEST_TIMEOUT; + SYNC_REQUEST_TIMEOUT;
let response = self.send(request, Some(timeout)).await?; let response = self.send(request, Some(timeout)).await?;
let sync_response = self.base_client.receive_sync_response(response).await?;
Ok(self.base_client.receive_sync_response(response).await?) if let Some(handler) = self.event_handler.read().await.as_ref() {
handler.handle_sync(&sync_response).await;
}
Ok(sync_response)
} }
/// Repeatedly call sync to synchronize the client state with the server. /// Repeatedly call sync to synchronize the client state with the server.

View File

@ -47,14 +47,14 @@ use crate::{
AnySyncStateEvent, BasicEvent, StrippedStateEvent, SyncEphemeralRoomEvent, AnySyncStateEvent, BasicEvent, StrippedStateEvent, SyncEphemeralRoomEvent,
SyncMessageEvent, SyncStateEvent, SyncMessageEvent, SyncStateEvent,
}, },
rooms::Room, room::Room,
Store, Client,
}; };
use matrix_sdk_common::async_trait; use matrix_sdk_common::async_trait;
pub(crate) struct Handler { pub(crate) struct Handler {
pub(crate) inner: Box<dyn EventHandler>, pub(crate) inner: Box<dyn EventHandler>,
pub(crate) store: Store, pub(crate) client: Client,
} }
impl Deref for Handler { impl Deref for Handler {
@ -67,7 +67,7 @@ impl Deref for Handler {
impl Handler { impl Handler {
fn get_room(&self, room_id: &RoomId) -> Option<Room> { fn get_room(&self, room_id: &RoomId) -> Option<Room> {
self.store.get_room(room_id) self.client.get_room(room_id)
} }
pub(crate) async fn handle_sync(&self, response: &SyncResponse) { pub(crate) async fn handle_sync(&self, response: &SyncResponse) {
@ -270,22 +270,23 @@ pub enum CustomEvent<'c> {
/// # use std::ops::Deref; /// # use std::ops::Deref;
/// # use std::sync::Arc; /// # use std::sync::Arc;
/// # use std::{env, process::exit}; /// # use std::{env, process::exit};
/// # use matrix_sdk_base::{ /// # use matrix_sdk::{
/// # self, /// # async_trait,
/// # EventHandler,
/// # events::{ /// # events::{
/// # room::message::{MessageEventContent, MessageType, TextMessageEventContent}, /// # room::message::{MessageEventContent, MessageType, TextMessageEventContent},
/// # SyncMessageEvent /// # SyncMessageEvent
/// # }, /// # },
/// # EventHandler, Room, RoomType, /// # locks::RwLock,
/// # room::Room,
/// # }; /// # };
/// # use matrix_sdk_common::{async_trait, locks::RwLock};
/// ///
/// struct EventCallback; /// struct EventCallback;
/// ///
/// #[async_trait] /// #[async_trait]
/// impl EventHandler for EventCallback { /// impl EventHandler for EventCallback {
/// async fn on_room_message(&self, room: Room, event: &SyncMessageEvent<MessageEventContent>) { /// async fn on_room_message(&self, room: Room, event: &SyncMessageEvent<MessageEventContent>) {
/// if room.room_type() == RoomType::Joined { /// if let Room::Joined(room) = room {
/// if let SyncMessageEvent { /// if let SyncMessageEvent {
/// content: /// content:
/// MessageEventContent { /// MessageEventContent {
@ -458,8 +459,9 @@ pub trait EventHandler: Send + Sync {
mod test { mod test {
use super::*; use super::*;
use matrix_sdk_common::{async_trait, locks::Mutex}; use matrix_sdk_common::{async_trait, locks::Mutex};
use matrix_sdk_test::{async_test, sync_response, SyncResponseFile}; use matrix_sdk_test::{async_test, test_json};
use std::sync::Arc; use mockito::{mock, Matcher};
use std::{sync::Arc, time::Duration};
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
pub use wasm_bindgen_test::*; pub use wasm_bindgen_test::*;
@ -667,19 +669,34 @@ mod test {
} }
} }
use crate::{identifiers::user_id, BaseClient, Session}; use crate::{identifiers::user_id, Client, Session, SyncSettings};
async fn get_client() -> BaseClient { async fn get_client() -> Client {
let session = Session { let session = Session {
access_token: "1234".to_owned(), access_token: "1234".to_owned(),
user_id: user_id!("@example:example.com"), user_id: user_id!("@example:example.com"),
device_id: "DEVICEID".into(), device_id: "DEVICEID".into(),
}; };
let client = BaseClient::new().unwrap(); let homeserver = url::Url::parse(&mockito::server_url()).unwrap();
let client = Client::new(homeserver).unwrap();
client.restore_login(session).await.unwrap(); client.restore_login(session).await.unwrap();
client client
} }
async fn mock_sync(client: Client, response: String) {
let _m = mock(
"GET",
Matcher::Regex(r"^/_matrix/client/r0/sync\?.*$".to_string()),
)
.with_status(200)
.match_header("authorization", "Bearer 1234")
.with_body(response)
.create();
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
let _response = client.sync_once(sync_settings).await.unwrap();
}
#[async_test] #[async_test]
async fn event_handler_joined() { async fn event_handler_joined() {
let vec = Arc::new(Mutex::new(Vec::new())); let vec = Arc::new(Mutex::new(Vec::new()));
@ -688,9 +705,7 @@ mod test {
let client = get_client().await; let client = get_client().await;
client.set_event_handler(handler).await; client.set_event_handler(handler).await;
mock_sync(client, test_json::SYNC.to_string()).await;
let response = sync_response(SyncResponseFile::Default);
client.receive_sync_response(response).await.unwrap();
let v = test_vec.lock().await; let v = test_vec.lock().await;
assert_eq!( assert_eq!(
@ -720,9 +735,7 @@ mod test {
let client = get_client().await; let client = get_client().await;
client.set_event_handler(handler).await; client.set_event_handler(handler).await;
mock_sync(client, test_json::INVITE_SYNC.to_string()).await;
let response = sync_response(SyncResponseFile::Invite);
client.receive_sync_response(response).await.unwrap();
let v = test_vec.lock().await; let v = test_vec.lock().await;
assert_eq!( assert_eq!(
@ -743,9 +756,7 @@ mod test {
let client = get_client().await; let client = get_client().await;
client.set_event_handler(handler).await; client.set_event_handler(handler).await;
mock_sync(client, test_json::LEAVE_SYNC.to_string()).await;
let response = sync_response(SyncResponseFile::Leave);
client.receive_sync_response(response).await.unwrap();
let v = test_vec.lock().await; let v = test_vec.lock().await;
assert_eq!( assert_eq!(
@ -773,9 +784,7 @@ mod test {
let client = get_client().await; let client = get_client().await;
client.set_event_handler(handler).await; client.set_event_handler(handler).await;
mock_sync(client, test_json::MORE_SYNC.to_string()).await;
let response = sync_response(SyncResponseFile::All);
client.receive_sync_response(response).await.unwrap();
let v = test_vec.lock().await; let v = test_vec.lock().await;
assert_eq!( assert_eq!(
@ -798,9 +807,7 @@ mod test {
let client = get_client().await; let client = get_client().await;
client.set_event_handler(handler).await; client.set_event_handler(handler).await;
mock_sync(client, test_json::VOIP_SYNC.to_string()).await;
let response = sync_response(SyncResponseFile::Voip);
client.receive_sync_response(response).await.unwrap();
let v = test_vec.lock().await; let v = test_vec.lock().await;
assert_eq!( assert_eq!(

View File

@ -68,8 +68,8 @@ compile_error!("only one of 'native-tls' or 'rustls-tls' features can be enabled
#[cfg_attr(feature = "docs", doc(cfg(encryption)))] #[cfg_attr(feature = "docs", doc(cfg(encryption)))]
pub use matrix_sdk_base::crypto::{EncryptionInfo, LocalTrust}; pub use matrix_sdk_base::crypto::{EncryptionInfo, LocalTrust};
pub use matrix_sdk_base::{ pub use matrix_sdk_base::{
CustomEvent, Error as BaseError, EventHandler, Room as BaseRoom, RoomInfo, RoomMember, Error as BaseError, Room as BaseRoom, RoomInfo, RoomMember, RoomType, Session, StateChanges,
RoomType, Session, StateChanges, StoreError, StoreError,
}; };
pub use matrix_sdk_common::*; pub use matrix_sdk_common::*;
@ -77,6 +77,7 @@ pub use reqwest;
mod client; mod client;
mod error; mod error;
mod event_handler;
mod http_client; mod http_client;
/// High-level room API /// High-level room API
pub mod room; pub mod room;
@ -93,6 +94,7 @@ pub use client::{Client, ClientConfig, LoopCtrl, SyncSettings};
#[cfg_attr(feature = "docs", doc(cfg(encryption)))] #[cfg_attr(feature = "docs", doc(cfg(encryption)))]
pub use device::Device; pub use device::Device;
pub use error::{Error, HttpError, Result}; pub use error::{Error, HttpError, Result};
pub use event_handler::{CustomEvent, EventHandler};
pub use http_client::HttpSend; pub use http_client::HttpSend;
#[cfg(feature = "encryption")] #[cfg(feature = "encryption")]
#[cfg_attr(feature = "docs", doc(cfg(encryption)))] #[cfg_attr(feature = "docs", doc(cfg(encryption)))]

View File

@ -62,11 +62,9 @@ use zeroize::Zeroizing;
use crate::{ use crate::{
error::Result, error::Result,
event_handler::Handler,
rooms::{Room, RoomInfo, RoomType}, rooms::{Room, RoomInfo, RoomType},
session::Session, session::Session,
store::{ambiguity_map::AmbiguityCache, Result as StoreResult, StateChanges, Store}, store::{ambiguity_map::AmbiguityCache, Result as StoreResult, StateChanges, Store},
EventHandler,
}; };
pub type Token = String; pub type Token = String;
@ -172,9 +170,6 @@ pub struct BaseClient {
cryptostore: Arc<Mutex<Option<Box<dyn CryptoStore>>>>, cryptostore: Arc<Mutex<Option<Box<dyn CryptoStore>>>>,
store_path: Arc<Option<PathBuf>>, store_path: Arc<Option<PathBuf>>,
store_passphrase: Arc<Option<Zeroizing<String>>>, store_passphrase: Arc<Option<Zeroizing<String>>>,
/// Any implementor of EventHandler will act as the callbacks for various
/// events.
event_handler: Arc<RwLock<Option<Handler>>>,
} }
#[cfg(not(tarpaulin_include))] #[cfg(not(tarpaulin_include))]
@ -320,7 +315,6 @@ impl BaseClient {
cryptostore: Mutex::new(crypto_store).into(), cryptostore: Mutex::new(crypto_store).into(),
store_path: config.store_path.into(), store_path: config.store_path.into(),
store_passphrase: config.passphrase.into(), store_passphrase: config.passphrase.into(),
event_handler: RwLock::new(None).into(),
}) })
} }
@ -419,17 +413,6 @@ impl BaseClient {
self.sync_token.read().await.clone() self.sync_token.read().await.clone()
} }
/// Add `EventHandler` to `Client`.
///
/// The methods of `EventHandler` are called when the respective `RoomEvents` occur.
pub async fn set_event_handler(&self, handler: Box<dyn EventHandler>) {
let handler = Handler {
inner: handler,
store: self.store.clone(),
};
*self.event_handler.write().await = Some(handler);
}
async fn handle_timeline( async fn handle_timeline(
&self, &self,
room_id: &RoomId, room_id: &RoomId,
@ -934,10 +917,6 @@ impl BaseClient {
}, },
}; };
if let Some(handler) = self.event_handler.read().await.as_ref() {
handler.handle_sync(&response).await;
}
Ok(response) Ok(response)
} }

View File

@ -46,12 +46,10 @@ pub use matrix_sdk_common::*;
mod client; mod client;
mod error; mod error;
mod event_handler;
mod rooms; mod rooms;
mod session; mod session;
mod store; mod store;
pub use event_handler::{CustomEvent, EventHandler};
pub use rooms::{Room, RoomInfo, RoomMember, RoomType}; pub use rooms::{Room, RoomInfo, RoomMember, RoomType};
pub use store::{StateChanges, StateStore, Store, StoreError}; pub use store::{StateChanges, StateStore, Store, StoreError};