refactor(sdk): Move event handler fields from Client into a new struct
This commit is contained in:
committed by
Jonas Platte
parent
973833c643
commit
9183f5d4ef
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user