refactor(sdk): Move event handler fields from Client into a new struct

This commit is contained in:
Jonas Platte
2022-08-24 22:51:51 +02:00
committed by Jonas Platte
parent 973833c643
commit 9183f5d4ef
3 changed files with 69 additions and 54 deletions
-2
View File
@@ -427,8 +427,6 @@ impl ClientBuilder {
members_request_locks: Default::default(),
typing_notice_times: Default::default(),
event_handlers: Default::default(),
event_handler_data: Default::default(),
event_handler_counter: Default::default(),
notification_handlers: Default::default(),
appservice_mode: self.appservice_mode,
respect_login_well_known: self.respect_login_well_known,
+5 -38
View File
@@ -15,15 +15,13 @@
// limitations under the License.
use std::{
collections::{btree_map, BTreeMap},
fmt::{self, Debug},
future::Future,
io::Read,
pin::Pin,
sync::{atomic::AtomicU64, Arc, RwLock as StdRwLock, RwLockReadGuard as StdRwLockReadGuard},
sync::Arc,
};
use anymap2::any::CloneAnySendSync;
#[cfg(target_arch = "wasm32")]
use async_once_cell::OnceCell;
use dashmap::DashMap;
@@ -95,8 +93,7 @@ use crate::{
config::RequestConfig,
error::{HttpError, HttpResult},
event_handler::{
EventHandler, EventHandlerHandle, EventHandlerKey, EventHandlerResult, EventHandlerWrapper,
SyncEvent,
EventHandler, EventHandlerHandle, EventHandlerResult, EventHandlerStore, SyncEvent,
},
http_client::HttpClient,
room, Account, Error, RefreshTokenError, Result, RumaApiError,
@@ -117,8 +114,6 @@ const DEFAULT_UPLOAD_SPEED: u64 = 125_000;
/// 5 min minimal upload request timeout, used to clamp the request timeout.
const MIN_UPLOAD_REQUEST_TIMEOUT: Duration = Duration::from_secs(60 * 5);
type EventHandlerMap = BTreeMap<EventHandlerKey, Vec<EventHandlerWrapper>>;
#[cfg(not(target_arch = "wasm32"))]
type NotificationHandlerFut = Pin<Box<dyn Future<Output = ()> + Send>>;
#[cfg(target_arch = "wasm32")]
@@ -131,8 +126,6 @@ type NotificationHandlerFn =
type NotificationHandlerFn =
Box<dyn Fn(Notification, room::Room, Client) -> NotificationHandlerFut>;
type AnyMap = anymap2::Map<dyn CloneAnySendSync + Send + Sync>;
/// Enum controlling if a loop running callbacks should continue or abort.
///
/// This is mainly used in the [`sync_with_callback`] method, the return value
@@ -176,12 +169,7 @@ pub(crate) struct ClientInner {
pub(crate) members_request_locks: DashMap<OwnedRoomId, Arc<Mutex<()>>>,
pub(crate) typing_notice_times: DashMap<OwnedRoomId, Instant>,
/// Event handlers. See `add_event_handler`.
pub(crate) event_handlers: StdRwLock<EventHandlerMap>,
/// Custom event handler context. See `add_event_handler_context`.
pub(crate) event_handler_data: StdRwLock<AnyMap>,
/// When registering a event handler, the current value is used for the
/// handlers identification, then the counter is incremented.
pub(crate) event_handler_counter: AtomicU64,
pub(crate) event_handlers: EventHandlerStore,
/// Notification handlers. See `register_notification_handler`.
notification_handlers: RwLock<Vec<NotificationHandlerFn>>,
/// Whether the client should operate in application service style mode.
@@ -667,10 +655,6 @@ impl Client {
self
}
pub(crate) fn event_handlers(&self) -> StdRwLockReadGuard<'_, EventHandlerMap> {
self.inner.event_handlers.read().unwrap()
}
/// Remove the event handler associated with the handle.
///
/// Note that you **must not** call `remove_event_handler` from the
@@ -730,16 +714,7 @@ impl Client {
/// # });
/// ```
pub fn remove_event_handler(&self, handle: EventHandlerHandle) {
let mut event_handlers = self.inner.event_handlers.write().unwrap();
if let btree_map::Entry::Occupied(mut entry) = event_handlers.entry(handle.key) {
let v = entry.get_mut();
v.retain(|e| e.handler_id != handle.handler_id);
if v.is_empty() {
entry.remove();
}
}
self.inner.event_handlers.remove(handle);
}
/// Add an arbitrary value for use as event handler context.
@@ -787,7 +762,7 @@ impl Client {
where
T: Clone + Send + Sync + 'static,
{
self.inner.event_handler_data.write().unwrap().insert(ctx);
self.inner.event_handlers.add_context(ctx);
}
#[allow(missing_docs)]
@@ -800,14 +775,6 @@ impl Client {
self
}
pub(crate) fn event_handler_context<T>(&self) -> Option<T>
where
T: Clone + Send + Sync + 'static,
{
let map = self.inner.event_handler_data.read().unwrap();
map.get::<T>().cloned()
}
/// Register a handler for a notification.
///
/// Similar to [`Client::add_event_handler`], but only allows functions
+64 -14
View File
@@ -35,14 +35,19 @@
use std::any::TypeId;
use std::{
borrow::{Borrow, Cow},
collections::{btree_map, BTreeMap},
fmt,
future::Future,
iter,
ops::Deref,
pin::Pin,
sync::atomic::Ordering::SeqCst,
sync::{
atomic::{AtomicU64, Ordering::SeqCst},
RwLock, RwLockReadGuard,
},
};
use anymap2::any::CloneAnySendSync;
use matrix_sdk_base::{
deserialized_responses::{EncryptionInfo, SyncRoomEvent},
SendOutsideWasm, SyncOutsideWasm,
@@ -64,6 +69,56 @@ type EventHandlerFn = dyn Fn(EventHandlerData<'_>) -> EventHandlerFut + Send + S
#[cfg(target_arch = "wasm32")]
type EventHandlerFn = dyn Fn(EventHandlerData<'_>) -> EventHandlerFut;
type EventHandlerMap = BTreeMap<EventHandlerKey, Vec<EventHandlerWrapper>>;
type AnyMap = anymap2::Map<dyn CloneAnySendSync + Send + Sync>;
#[derive(Default)]
pub(crate) struct EventHandlerStore {
handlers: RwLock<EventHandlerMap>,
context: RwLock<AnyMap>,
counter: AtomicU64,
}
impl EventHandlerStore {
pub fn add_handler(
&self,
key: EventHandlerKey,
handler_id: u64,
handler_fn: Box<EventHandlerFn>,
) {
self.handlers
.write()
.unwrap()
.entry(key)
.or_default()
.push(EventHandlerWrapper { handler_id, handler_fn });
}
pub fn add_context<T>(&self, ctx: T)
where
T: Clone + Send + Sync + 'static,
{
self.context.write().unwrap().insert(ctx);
}
pub fn remove(&self, handle: EventHandlerHandle) {
let mut map = self.handlers.write().unwrap();
if let btree_map::Entry::Occupied(mut entry) = map.entry(handle.key) {
let v = entry.get_mut();
v.retain(|e| e.handler_id != handle.handler_id);
if v.is_empty() {
entry.remove();
}
}
}
fn read(&self) -> RwLockReadGuard<'_, EventHandlerMap> {
self.handlers.read().unwrap()
}
}
#[doc(hidden)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum EventKind {
@@ -275,7 +330,8 @@ pub struct Ctx<T>(pub T);
impl<T: Clone + Send + Sync + 'static> EventHandlerContext for Ctx<T> {
fn from_data(data: &EventHandlerData<'_>) -> Option<Self> {
data.client.event_handler_context::<T>().map(Ctx)
let map = data.client.inner.event_handlers.context.read().unwrap();
map.get::<T>().cloned().map(Ctx)
}
}
@@ -361,16 +417,10 @@ impl Client {
})
});
let handler_id = self.inner.event_handler_counter.fetch_add(1, SeqCst);
let handler_id = self.inner.event_handlers.counter.fetch_add(1, SeqCst);
let key = EventHandlerKey::new(Ev::KIND, Ev::TYPE, room_id);
self.inner
.event_handlers
.write()
.unwrap()
.entry(key.clone())
.or_default()
.push(EventHandlerWrapper { handler_fn, handler_id });
self.inner.event_handlers.add_handler(key.clone(), handler_id, handler_fn);
EventHandlerHandle { key, handler_id }
}
@@ -496,7 +546,7 @@ impl Client {
EventHandlerKeyInner { ev_kind, ev_type, room_id }
});
let handlers_lock = self.event_handlers();
let handlers_lock = self.inner.event_handlers.read();
iter::once(non_room_handler_key)
.chain(room_handler_key)
@@ -950,15 +1000,15 @@ mod tests {
let client = no_retry_test_client(None).await;
let handle = client.add_event_handler(|_ev: OriginalSyncRoomMemberEvent| async {});
assert_eq!(client.event_handlers().len(), 1);
assert_eq!(client.inner.event_handlers.read().len(), 1);
{
let _guard = client.event_handler_drop_guard(handle);
assert_eq!(client.event_handlers().len(), 1);
assert_eq!(client.inner.event_handlers.read().len(), 1);
// guard dropped here
}
assert_eq!(client.event_handlers().len(), 0);
assert_eq!(client.inner.event_handlers.read().len(), 0);
}
#[async_test]