From 246d70e61e7394c44abef042a0006d07205b552c Mon Sep 17 00:00:00 2001 From: Daniel Salinas Date: Sat, 12 Oct 2024 13:45:10 -0400 Subject: [PATCH] Make the matrix-sdk-ui crate support wasm32-unknown-unknown This commit adjusts types and traits to support targeting wasm32. --- crates/matrix-sdk-base/src/client.rs | 3 - .../src/event_cache_store/traits.rs | 3 +- crates/matrix-sdk-base/src/read_receipts.rs | 9 ++ .../matrix-sdk-base/src/store/memory_store.rs | 3 +- crates/matrix-sdk-base/src/store/mod.rs | 9 +- .../src/store/observable_map.rs | 10 +++ crates/matrix-sdk-base/src/store/traits.rs | 9 +- crates/matrix-sdk-common/Cargo.toml | 5 +- crates/matrix-sdk-common/src/executor.rs | 90 +++++++++++++++++-- crates/matrix-sdk-common/src/lib.rs | 9 -- crates/matrix-sdk-crypto/src/machine/mod.rs | 2 +- .../src/store/memorystore.rs | 3 +- crates/matrix-sdk-crypto/src/store/traits.rs | 9 +- .../src/room_list_service/filters/mod.rs | 3 + crates/matrix-sdk-ui/src/sync_service.rs | 10 +-- .../src/timeline/event_item/local.rs | 2 +- .../src/timeline/pinned_events_loader.rs | 9 +- .../matrix-sdk-ui/src/timeline/tests/mod.rs | 24 ++--- crates/matrix-sdk-ui/src/timeline/traits.rs | 47 +++++++--- .../src/unable_to_decrypt_hook.rs | 3 +- crates/matrix-sdk/Cargo.toml | 2 +- crates/matrix-sdk/src/client/mod.rs | 14 +-- crates/matrix-sdk/src/event_handler/mod.rs | 12 +-- crates/matrix-sdk/src/room/futures.rs | 1 - crates/matrix-sdk/src/sliding_sync/error.rs | 2 +- crates/matrix-sdk/src/sliding_sync/mod.rs | 12 +-- crates/matrix-sdk/src/sliding_sync/utils.rs | 43 --------- 27 files changed, 194 insertions(+), 154 deletions(-) delete mode 100644 crates/matrix-sdk/src/sliding_sync/utils.rs diff --git a/crates/matrix-sdk-base/src/client.rs b/crates/matrix-sdk-base/src/client.rs index 35ec906b855..682dca6ce37 100644 --- a/crates/matrix-sdk-base/src/client.rs +++ b/crates/matrix-sdk-base/src/client.rs @@ -22,9 +22,7 @@ use std::{ }; use eyeball::{SharedObservable, Subscriber}; -#[cfg(not(target_arch = "wasm32"))] use eyeball_im::{Vector, VectorDiff}; -#[cfg(not(target_arch = "wasm32"))] use futures_util::Stream; #[cfg(feature = "e2e-encryption")] use matrix_sdk_crypto::{ @@ -228,7 +226,6 @@ impl BaseClient { /// Get a stream of all the rooms changes, in addition to the existing /// rooms. - #[cfg(not(target_arch = "wasm32"))] pub fn rooms_stream(&self) -> (Vector, impl Stream>>) { self.store.rooms_stream() } diff --git a/crates/matrix-sdk-base/src/event_cache_store/traits.rs b/crates/matrix-sdk-base/src/event_cache_store/traits.rs index 6c56166177b..f7cb15ec492 100644 --- a/crates/matrix-sdk-base/src/event_cache_store/traits.rs +++ b/crates/matrix-sdk-base/src/event_cache_store/traits.rs @@ -15,7 +15,6 @@ use std::{fmt, sync::Arc}; use async_trait::async_trait; -use matrix_sdk_common::AsyncTraitDeps; use ruma::MxcUri; use super::EventCacheStoreError; @@ -25,7 +24,7 @@ use crate::media::MediaRequest; /// for the event cache of the SDK. #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait)] -pub trait EventCacheStore: AsyncTraitDeps { +pub trait EventCacheStore: Send + Sync { /// The error type used by this event cache store. type Error: fmt::Debug + Into; diff --git a/crates/matrix-sdk-base/src/read_receipts.rs b/crates/matrix-sdk-base/src/read_receipts.rs index f582bdd5ade..7fd14721b63 100644 --- a/crates/matrix-sdk-base/src/read_receipts.rs +++ b/crates/matrix-sdk-base/src/read_receipts.rs @@ -266,12 +266,21 @@ impl RoomReadReceipts { } /// Provider for timeline events prior to the current sync. +#[cfg(not(target_arch = "wasm32"))] pub trait PreviousEventsProvider: Send + Sync { /// Returns the list of known timeline events, in sync order, for the given /// room. fn for_room(&self, room_id: &RoomId) -> Vector; } +/// Provider for timeline events prior to the current sync. +#[cfg(target_arch = "wasm32")] +pub trait PreviousEventsProvider { + /// Returns the list of known timeline events, in sync order, for the given + /// room. + fn for_room(&self, room_id: &RoomId) -> Vector; +} + impl PreviousEventsProvider for () { fn for_room(&self, _: &RoomId) -> Vector { Vector::new() diff --git a/crates/matrix-sdk-base/src/store/memory_store.rs b/crates/matrix-sdk-base/src/store/memory_store.rs index 995c7113870..babfc885473 100644 --- a/crates/matrix-sdk-base/src/store/memory_store.rs +++ b/crates/matrix-sdk-base/src/store/memory_store.rs @@ -137,8 +137,7 @@ impl MemoryStore { } } -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +#[async_trait] impl StateStore for MemoryStore { type Error = StoreError; diff --git a/crates/matrix-sdk-base/src/store/mod.rs b/crates/matrix-sdk-base/src/store/mod.rs index 9c774a769a0..dacfe87c989 100644 --- a/crates/matrix-sdk-base/src/store/mod.rs +++ b/crates/matrix-sdk-base/src/store/mod.rs @@ -29,9 +29,7 @@ use std::{ sync::{Arc, RwLock as StdRwLock}, }; -#[cfg(not(target_arch = "wasm32"))] use eyeball_im::{Vector, VectorDiff}; -#[cfg(not(target_arch = "wasm32"))] use futures_util::Stream; use once_cell::sync::OnceCell; @@ -60,9 +58,9 @@ use tokio::sync::{broadcast, Mutex, RwLock}; use tracing::warn; use crate::{ - event_cache_store::{DynEventCacheStore, IntoEventCacheStore}, - rooms::{normal::RoomInfoNotableUpdate, RoomInfo, RoomState}, - MinimalRoomMemberEvent, Room, RoomStateFilter, SessionMeta, + event_cache_store::{DynEventCacheStore, IntoEventCacheStore}, + rooms::{normal::RoomInfoNotableUpdate, RoomInfo, RoomState}, + MinimalRoomMemberEvent, Room, RoomStateFilter, SessionMeta }; pub(crate) mod ambiguity_map; @@ -263,7 +261,6 @@ impl Store { /// Get a stream of all the rooms changes, in addition to the existing /// rooms. - #[cfg(not(target_arch = "wasm32"))] pub fn rooms_stream(&self) -> (Vector, impl Stream>>) { self.rooms.read().unwrap().stream() } diff --git a/crates/matrix-sdk-base/src/store/observable_map.rs b/crates/matrix-sdk-base/src/store/observable_map.rs index e15124a9520..00d85c52580 100644 --- a/crates/matrix-sdk-base/src/store/observable_map.rs +++ b/crates/matrix-sdk-base/src/store/observable_map.rs @@ -136,6 +136,9 @@ mod impl_non_wasm32 { #[cfg(target_arch = "wasm32")] mod impl_wasm32 { use std::{borrow::Borrow, collections::BTreeMap, hash::Hash}; + use futures_util::stream; + use futures_util::{Stream, StreamExt}; + use eyeball_im::{Vector, VectorDiff}; /// An observable map for Wasm. It's a simple wrapper around `BTreeMap`. #[derive(Debug)] @@ -184,6 +187,13 @@ mod impl_wasm32 { pub(crate) fn iter(&self) -> impl Iterator { self.0.values() } + + /// Get a [`Stream`] of the values. + pub(crate) fn stream(&self) -> (Vector, impl Stream>>) { + let values: Vector = self.0.values().cloned().collect(); + let stream = stream::iter(vec![values.clone()]).map(|v| vec![VectorDiff::Reset{ values: v }]); + (values, stream) + } } } diff --git a/crates/matrix-sdk-base/src/store/traits.rs b/crates/matrix-sdk-base/src/store/traits.rs index d96e3f24cb0..cd7cceb2413 100644 --- a/crates/matrix-sdk-base/src/store/traits.rs +++ b/crates/matrix-sdk-base/src/store/traits.rs @@ -23,7 +23,6 @@ use std::{ use as_variant::as_variant; use async_trait::async_trait; use growable_bloom_filter::GrowableBloom; -use matrix_sdk_common::AsyncTraitDeps; use ruma::{ api::MatrixVersion, events::{ @@ -50,9 +49,8 @@ use crate::{ /// An abstract state store trait that can be used to implement different stores /// for the SDK. -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -pub trait StateStore: AsyncTraitDeps { +#[async_trait] +pub trait StateStore: fmt::Debug + Send + Sync { /// The error type used by this state store. type Error: fmt::Debug + Into + From; @@ -452,8 +450,7 @@ impl fmt::Debug for EraseStateStoreError { } } -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +#[async_trait] impl StateStore for EraseStateStoreError { type Error = StoreError; diff --git a/crates/matrix-sdk-common/Cargo.toml b/crates/matrix-sdk-common/Cargo.toml index 87d52a1f3fe..acce1456447 100644 --- a/crates/matrix-sdk-common/Cargo.toml +++ b/crates/matrix-sdk-common/Cargo.toml @@ -31,13 +31,16 @@ tokio = { workspace = true, features = ["rt", "time"] } uniffi = { workspace = true, optional = true } [target.'cfg(target_arch = "wasm32")'.dependencies] -futures-util = { workspace = true, features = ["channel"] } wasm-bindgen-futures = { version = "0.4.33", optional = true } gloo-timers = { version = "0.3.0", features = ["futures"] } +futures-util = { workspace = true, features = ["channel"] } web-sys = { version = "0.3.60", features = ["console"] } tracing-subscriber = { workspace = true, features = ["fmt", "ansi"] } wasm-bindgen = "0.2.84" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +futures-util = { workspace = true } + [dev-dependencies] assert_matches = { workspace = true } proptest = { version = "1.4.0", default-features = false, features = ["std"] } diff --git a/crates/matrix-sdk-common/src/executor.rs b/crates/matrix-sdk-common/src/executor.rs index b1cb1a7bf13..7f065fc72f5 100644 --- a/crates/matrix-sdk-common/src/executor.rs +++ b/crates/matrix-sdk-common/src/executor.rs @@ -14,24 +14,28 @@ //! Abstraction over an executor so we can spawn tasks under WASM the same way //! we do usually. - -#[cfg(target_arch = "wasm32")] use std::{ future::Future, pin::Pin, task::{Context, Poll}, }; +use futures_util::FutureExt; #[cfg(target_arch = "wasm32")] pub use futures_util::future::Aborted as JoinError; #[cfg(target_arch = "wasm32")] -use futures_util::{ - future::{AbortHandle, Abortable, RemoteHandle}, - FutureExt, -}; +use futures_util::future::{AbortHandle, Abortable, RemoteHandle}; #[cfg(not(target_arch = "wasm32"))] pub use tokio::task::{spawn, JoinError, JoinHandle}; + +/// A `Box::pin` future that is `Send` on non-wasm, and without `Send` on wasm. +#[cfg(target_arch = "wasm32")] +pub type BoxFuture<'a, T> = Pin + 'a>>; +#[cfg(not(target_arch = "wasm32"))] +pub type BoxFuture<'a, T> = Pin + Send + 'a>>; + + #[cfg(target_arch = "wasm32")] pub fn spawn(future: F) -> JoinHandle where @@ -50,6 +54,32 @@ where JoinHandle { remote_handle, abort_handle } } +pub trait BoxFutureExt<'a, T: 'a> { + fn box_future(self) -> BoxFuture<'a, T>; +} + +#[cfg(not(target_arch = "wasm32"))] +impl<'a, F, T> BoxFutureExt<'a, T> for F +where + F: Future + 'a + Send, + T: 'a, +{ + fn box_future(self) -> BoxFuture<'a, T> { + self.boxed() + } +} + +#[cfg(target_arch = "wasm32")] +impl<'a, F, T> BoxFutureExt<'a, T> for F +where + F: Future + 'a, + T: 'a, +{ + fn box_future(self) -> BoxFuture<'a, T> { + self.boxed_local() + } +} + #[cfg(target_arch = "wasm32")] #[derive(Debug)] pub struct JoinHandle { @@ -78,6 +108,54 @@ impl Future for JoinHandle { } } +#[derive(Debug)] +pub struct AbortOnDrop(JoinHandle); + +impl AbortOnDrop { + pub fn new(join_handle: JoinHandle) -> Self { + Self(join_handle) + } +} + +impl Drop for AbortOnDrop { + fn drop(&mut self) { + self.0.abort(); + } +} + +#[cfg(not(target_arch = "wasm32"))] +impl Future for AbortOnDrop { + type Output = Result; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + Pin::new(&mut self.0).poll(cx) + } +} + +#[cfg(target_arch = "wasm32")] +impl Future for AbortOnDrop { + type Output = Result; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + if self.0.abort_handle.is_aborted() { + // The future has been aborted. It is not possible to poll it again. + Poll::Ready(Err(JoinError)) + } else { + Pin::new(&mut self.0.remote_handle).poll(cx).map(Ok) + } + } +} + +/// Trait to create a `AbortOnDrop` from a `JoinHandle`. +pub trait JoinHandleExt { + fn abort_on_drop(self) -> AbortOnDrop; +} + +impl JoinHandleExt for JoinHandle { + fn abort_on_drop(self) -> AbortOnDrop { + AbortOnDrop::new(self) + } +} #[cfg(test)] mod tests { use assert_matches::assert_matches; diff --git a/crates/matrix-sdk-common/src/lib.rs b/crates/matrix-sdk-common/src/lib.rs index 451a86fa16c..851dc16b576 100644 --- a/crates/matrix-sdk-common/src/lib.rs +++ b/crates/matrix-sdk-common/src/lib.rs @@ -15,9 +15,6 @@ #![doc = include_str!("../README.md")] #![warn(missing_debug_implementations)] -use std::pin::Pin; - -use futures_core::Future; #[doc(no_inline)] pub use ruma; @@ -90,11 +87,5 @@ macro_rules! boxed_into_future { }; } -/// A `Box::pin` future that is `Send` on non-wasm, and without `Send` on wasm. -#[cfg(target_arch = "wasm32")] -pub type BoxFuture<'a, T> = Pin + 'a>>; -#[cfg(not(target_arch = "wasm32"))] -pub type BoxFuture<'a, T> = Pin + Send + 'a>>; - #[cfg(feature = "uniffi")] uniffi::setup_scaffolding!(); diff --git a/crates/matrix-sdk-crypto/src/machine/mod.rs b/crates/matrix-sdk-crypto/src/machine/mod.rs index 80b2c1d44d5..99baeece542 100644 --- a/crates/matrix-sdk-crypto/src/machine/mod.rs +++ b/crates/matrix-sdk-crypto/src/machine/mod.rs @@ -24,7 +24,7 @@ use matrix_sdk_common::{ AlgorithmInfo, DecryptedRoomEvent, DeviceLinkProblem, EncryptionInfo, UnableToDecryptInfo, UnsignedDecryptionResult, UnsignedEventLocation, VerificationLevel, VerificationState, }, - BoxFuture, + executor::BoxFuture, }; use ruma::{ api::client::{ diff --git a/crates/matrix-sdk-crypto/src/store/memorystore.rs b/crates/matrix-sdk-crypto/src/store/memorystore.rs index b773d819d94..c0c60456671 100644 --- a/crates/matrix-sdk-crypto/src/store/memorystore.rs +++ b/crates/matrix-sdk-crypto/src/store/memorystore.rs @@ -194,8 +194,7 @@ impl MemoryStore { type Result = std::result::Result; -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +#[async_trait] impl CryptoStore for MemoryStore { type Error = Infallible; diff --git a/crates/matrix-sdk-crypto/src/store/traits.rs b/crates/matrix-sdk-crypto/src/store/traits.rs index 3031e33ef8d..bc2b33e48fd 100644 --- a/crates/matrix-sdk-crypto/src/store/traits.rs +++ b/crates/matrix-sdk-crypto/src/store/traits.rs @@ -15,7 +15,6 @@ use std::{collections::HashMap, fmt, sync::Arc}; use async_trait::async_trait; -use matrix_sdk_common::AsyncTraitDeps; use ruma::{ events::secret::request::SecretName, DeviceId, OwnedDeviceId, RoomId, TransactionId, UserId, }; @@ -37,9 +36,8 @@ use crate::{ /// Represents a store that the `OlmMachine` uses to store E2EE data (such as /// cryptographic keys). -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -pub trait CryptoStore: AsyncTraitDeps { +#[async_trait] +pub trait CryptoStore: fmt::Debug + Send + Sync { /// The error type used by this crypto store. type Error: fmt::Debug + Into; @@ -369,8 +367,7 @@ impl fmt::Debug for EraseCryptoStoreError { } } -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +#[async_trait] impl CryptoStore for EraseCryptoStoreError { type Error = CryptoStoreError; diff --git a/crates/matrix-sdk-ui/src/room_list_service/filters/mod.rs b/crates/matrix-sdk-ui/src/room_list_service/filters/mod.rs index 2eb01063da0..1085400f4e9 100644 --- a/crates/matrix-sdk-ui/src/room_list_service/filters/mod.rs +++ b/crates/matrix-sdk-ui/src/room_list_service/filters/mod.rs @@ -102,7 +102,10 @@ pub trait Filter: Fn(&Room) -> bool {} impl Filter for F where F: Fn(&Room) -> bool {} /// Type alias for a boxed filter function. +#[cfg(not(target_arch = "wasm32"))] pub type BoxedFilterFn = Box; +#[cfg(target_arch = "wasm32")] +pub type BoxedFilterFn = Box; /// Normalize a string, i.e. decompose it into NFD (Normalization Form D, i.e. a /// canonical decomposition, see http://www.unicode.org/reports/tr15/) and diff --git a/crates/matrix-sdk-ui/src/sync_service.rs b/crates/matrix-sdk-ui/src/sync_service.rs index 23c8166cafe..f914df253cb 100644 --- a/crates/matrix-sdk-ui/src/sync_service.rs +++ b/crates/matrix-sdk-ui/src/sync_service.rs @@ -30,12 +30,10 @@ use futures_core::Future; use futures_util::{pin_mut, StreamExt as _}; use matrix_sdk::Client; use thiserror::Error; -use tokio::{ - sync::{ - mpsc::{Receiver, Sender}, - Mutex as AsyncMutex, OwnedMutexGuard, - }, - task::{spawn, JoinHandle}, +use matrix_sdk_base::executor::{spawn, JoinHandle}; +use tokio::sync::{ + mpsc::{Receiver, Sender}, + Mutex as AsyncMutex, OwnedMutexGuard, }; use tracing::{error, info, instrument, trace, warn, Instrument, Level}; diff --git a/crates/matrix-sdk-ui/src/timeline/event_item/local.rs b/crates/matrix-sdk-ui/src/timeline/event_item/local.rs index 2890b6eab8e..8846c2f4d89 100644 --- a/crates/matrix-sdk-ui/src/timeline/event_item/local.rs +++ b/crates/matrix-sdk-ui/src/timeline/event_item/local.rs @@ -28,7 +28,7 @@ pub(in crate::timeline) struct LocalEventTimelineItem { pub send_state: EventSendState, /// The transaction ID. pub transaction_id: OwnedTransactionId, - /// A handle to manipulate this event before it is sent, if possible. + // A handle to manipulate this event before it is sent, if possible. pub send_handle: Option, } diff --git a/crates/matrix-sdk-ui/src/timeline/pinned_events_loader.rs b/crates/matrix-sdk-ui/src/timeline/pinned_events_loader.rs index 450ccae0e94..7c7f4f90297 100644 --- a/crates/matrix-sdk-ui/src/timeline/pinned_events_loader.rs +++ b/crates/matrix-sdk-ui/src/timeline/pinned_events_loader.rs @@ -14,10 +14,9 @@ use std::{fmt::Formatter, sync::Arc}; -use futures_util::{stream, FutureExt as _, StreamExt}; +use futures_util::{stream, StreamExt}; use matrix_sdk::{ - config::RequestConfig, event_cache::paginator::PaginatorError, BoxFuture, Room, - SendOutsideWasm, SyncOutsideWasm, + config::RequestConfig, event_cache::paginator::PaginatorError, executor::{BoxFuture, BoxFutureExt}, Room, }; use matrix_sdk_base::deserialized_responses::SyncTimelineEvent; use ruma::{events::relation::RelationType, EventId, MilliSecondsSinceUnixEpoch, OwnedEventId}; @@ -119,7 +118,7 @@ impl PinnedEventsLoader { } } -pub trait PinnedEventsRoom: SendOutsideWasm + SyncOutsideWasm { +pub trait PinnedEventsRoom: Send + Sync { /// Load a single room event using the cache or network and any events /// related to it, if they are cached. /// @@ -165,7 +164,7 @@ impl PinnedEventsRoom for Room { .map(|e| (e.into(), Vec::new())) .map_err(|err| PaginatorError::SdkError(Box::new(err))) } - .boxed() + .box_future() } fn pinned_event_ids(&self) -> Vec { diff --git a/crates/matrix-sdk-ui/src/timeline/tests/mod.rs b/crates/matrix-sdk-ui/src/timeline/tests/mod.rs index 5c12916221f..fba8e68c6ee 100644 --- a/crates/matrix-sdk-ui/src/timeline/tests/mod.rs +++ b/crates/matrix-sdk-ui/src/timeline/tests/mod.rs @@ -27,12 +27,12 @@ use futures_util::FutureExt as _; use indexmap::IndexMap; use matrix_sdk::{ config::RequestConfig, - deserialized_responses::{SyncTimelineEvent, TimelineEvent}, - event_cache::paginator::{PaginableRoom, PaginatorError}, - room::{EventWithContextResponse, Messages, MessagesOptions}, - send_queue::RoomSendQueueUpdate, + deserialized_responses::{SyncTimelineEvent, TimelineEvent}, + event_cache::paginator::{PaginableRoom, PaginatorError}, + executor::{BoxFuture, BoxFutureExt}, + room::{EventWithContextResponse, Messages, MessagesOptions}, + send_queue::RoomSendQueueUpdate, test_utils::events::EventFactory, - BoxFuture, }; use matrix_sdk_base::{latest_event::LatestEvent, RoomInfo, RoomState}; use matrix_sdk_test::{EventBuilder, ALICE, BOB, DEFAULT_TEST_ROOM_ID}; @@ -369,7 +369,7 @@ impl RoomDataProvider for TestRoomDataProvider { } fn profile_from_user_id<'a>(&'a self, _user_id: &'a UserId) -> BoxFuture<'a, Option> { - ready(None).boxed() + ready(None).box_future() } fn profile_from_latest_event(&self, _latest_event: &LatestEvent) -> Option { @@ -389,7 +389,7 @@ impl RoomDataProvider for TestRoomDataProvider { .and_then(|user_map| user_map.get(user_id)) .cloned(), ) - .boxed() + .box_future() } fn load_event_receipts( @@ -401,7 +401,7 @@ impl RoomDataProvider for TestRoomDataProvider { } else { IndexMap::new() }) - .boxed() + .box_future() } fn push_rules_and_context(&self) -> BoxFuture<'_, Option<(Ruleset, PushConditionRoomCtx)>> { @@ -419,11 +419,11 @@ impl RoomDataProvider for TestRoomDataProvider { power_levels: Some(power_levels), }; - ready(Some((push_rules, push_context))).boxed() + ready(Some((push_rules, push_context))).box_future() } fn load_fully_read_marker(&self) -> BoxFuture<'_, Option> { - ready(self.fully_read_marker.clone()).boxed() + ready(self.fully_read_marker.clone()).box_future() } fn send(&self, content: AnyMessageLikeEventContent) -> BoxFuture<'_, Result<(), super::Error>> { @@ -431,7 +431,7 @@ impl RoomDataProvider for TestRoomDataProvider { self.sent_events.write().await.push(content); Ok(()) } - .boxed() + .box_future() } fn redact<'a>( @@ -444,7 +444,7 @@ impl RoomDataProvider for TestRoomDataProvider { self.redacted.write().await.push(event_id.to_owned()); Ok(()) } - .boxed() + .box_future() } fn room_info(&self) -> Subscriber { diff --git a/crates/matrix-sdk-ui/src/timeline/traits.rs b/crates/matrix-sdk-ui/src/timeline/traits.rs index 158488eb06f..47a2f676a7c 100644 --- a/crates/matrix-sdk-ui/src/timeline/traits.rs +++ b/crates/matrix-sdk-ui/src/timeline/traits.rs @@ -15,13 +15,14 @@ use std::future::Future; use eyeball::Subscriber; -use futures_util::FutureExt as _; use indexmap::IndexMap; #[cfg(test)] use matrix_sdk::crypto::{DecryptionSettings, TrustRequirement}; use matrix_sdk::{ - deserialized_responses::TimelineEvent, event_cache::paginator::PaginableRoom, BoxFuture, - Result, Room, + deserialized_responses::TimelineEvent, + event_cache::paginator::PaginableRoom, + executor::{BoxFuture, BoxFutureExt as _}, + AsyncTraitDeps, Result, Room }; use matrix_sdk_base::{latest_event::LatestEvent, RoomInfo}; use ruma::{ @@ -47,7 +48,18 @@ pub trait RoomExt { /// independent events. /// /// This is the same as using `room.timeline_builder().build()`. - fn timeline(&self) -> impl Future> + Send; + #[cfg(not(target_arch = "wasm32"))] + fn timeline(&self) -> impl Future> + Send; + + /// Get a [`Timeline`] for this room. + /// + /// This offers a higher-level API than event handlers, in treating things + /// like edits and reactions as updates of existing items rather than new + /// independent events. + /// + /// This is the same as using `room.timeline_builder().build()`. + #[cfg(target_arch = "wasm32")] + fn timeline(&self) -> impl Future>; /// Get a [`TimelineBuilder`] for this room. /// @@ -70,8 +82,7 @@ impl RoomExt for Room { } } -pub(super) trait RoomDataProvider: - Clone + Send + Sync + 'static + PaginableRoom + PinnedEventsRoom +pub(super) trait RoomDataProvider: AsyncTraitDeps + Clone + 'static + PaginableRoom + PinnedEventsRoom { fn own_user_id(&self) -> &UserId; fn room_version(&self) -> RoomVersionId; @@ -137,7 +148,7 @@ impl RoomDataProvider for Room { } } } - .boxed() + .box_future() } fn profile_from_latest_event(&self, latest_event: &LatestEvent) -> Option { @@ -172,7 +183,7 @@ impl RoomDataProvider for Room { } } } - .boxed() + .box_future() } fn load_event_receipts<'a>( @@ -205,7 +216,7 @@ impl RoomDataProvider for Room { unthreaded_receipts.extend(main_thread_receipts); unthreaded_receipts } - .boxed() + .box_future() } fn push_rules_and_context(&self) -> BoxFuture<'_, Option<(Ruleset, PushConditionRoomCtx)>> { @@ -228,7 +239,7 @@ impl RoomDataProvider for Room { } } } - .boxed() + .box_future() } fn load_fully_read_marker(&self) -> BoxFuture<'_, Option> { @@ -248,7 +259,7 @@ impl RoomDataProvider for Room { _ => None, } } - .boxed() + .box_future() } fn send(&self, content: AnyMessageLikeEventContent) -> BoxFuture<'_, Result<(), super::Error>> { @@ -256,7 +267,7 @@ impl RoomDataProvider for Room { let _ = self.send_queue().send(content).await?; Ok(()) } - .boxed() + .box_future() } fn redact<'a>( @@ -273,7 +284,7 @@ impl RoomDataProvider for Room { .map_err(super::Error::RedactError)?; Ok(()) } - .boxed() + .box_future() } fn room_info(&self) -> Subscriber { @@ -283,11 +294,19 @@ impl RoomDataProvider for Room { // Internal helper to make most of retry_event_decryption independent of a room // object, which is annoying to create for testing and not really needed -pub(super) trait Decryptor: Clone + Send + Sync + 'static { +pub(super) trait Decryptor: Clone + AsyncTraitDeps + 'static { + + #[cfg(not(target_arch = "wasm32"))] fn decrypt_event_impl( &self, raw: &Raw, ) -> impl Future> + Send; + + #[cfg(target_arch = "wasm32")] + fn decrypt_event_impl( + &self, + raw: &Raw, + ) -> impl Future>; } impl Decryptor for Room { diff --git a/crates/matrix-sdk-ui/src/unable_to_decrypt_hook.rs b/crates/matrix-sdk-ui/src/unable_to_decrypt_hook.rs index 14f72aee824..a0755c690e1 100644 --- a/crates/matrix-sdk-ui/src/unable_to_decrypt_hook.rs +++ b/crates/matrix-sdk-ui/src/unable_to_decrypt_hook.rs @@ -26,12 +26,11 @@ use std::{ use growable_bloom_filter::{GrowableBloom, GrowableBloomBuilder}; use matrix_sdk::{crypto::types::events::UtdCause, Client}; +use matrix_sdk::executor::{spawn, JoinHandle}; use matrix_sdk_base::{StateStoreDataKey, StateStoreDataValue, StoreError}; use ruma::{EventId, OwnedEventId}; use tokio::{ - spawn, sync::{Mutex as AsyncMutex, MutexGuard}, - task::JoinHandle, time::sleep, }; use tracing::error; diff --git a/crates/matrix-sdk/Cargo.toml b/crates/matrix-sdk/Cargo.toml index 2b2a5cd7062..415e8a45ef3 100644 --- a/crates/matrix-sdk/Cargo.toml +++ b/crates/matrix-sdk/Cargo.toml @@ -16,7 +16,7 @@ features = ["docsrs"] rustdoc-args = ["--cfg", "docsrs"] [features] -default = ["e2e-encryption", "automatic-room-key-forwarding", "sqlite", "native-tls"] +default = ["e2e-encryption", "automatic-room-key-forwarding", "sqlite", "native-tls", "js"] testing = ["matrix-sdk-sqlite?/testing", "matrix-sdk-indexeddb?/testing", "matrix-sdk-base/testing", "wiremock", "matrix-sdk-test", "assert_matches2"] e2e-encryption = [ diff --git a/crates/matrix-sdk/src/client/mod.rs b/crates/matrix-sdk/src/client/mod.rs index 92619b03089..d315d2a550e 100644 --- a/crates/matrix-sdk/src/client/mod.rs +++ b/crates/matrix-sdk/src/client/mod.rs @@ -23,12 +23,8 @@ use std::{ }; use eyeball::{SharedObservable, Subscriber}; -#[cfg(not(target_arch = "wasm32"))] use eyeball_im::VectorDiff; -use futures_core::Stream; -#[cfg(not(target_arch = "wasm32"))] -use futures_util::StreamExt; -#[cfg(not(target_arch = "wasm32"))] +use futures_util::{Stream, StreamExt}; use imbl::Vector; #[cfg(feature = "e2e-encryption")] use matrix_sdk_base::crypto::store::LockableCryptoStore; @@ -37,7 +33,7 @@ use matrix_sdk_base::{ store::{DynStateStore, ServerCapabilities}, sync::{Notification, RoomUpdates}, BaseClient, RoomInfoNotableUpdate, RoomState, RoomStateFilter, SendOutsideWasm, SessionMeta, - StateStoreDataKey, StateStoreDataValue, SyncOutsideWasm, + StateStoreDataKey, StateStoreDataValue, }; #[cfg(feature = "e2e-encryption")] use ruma::events::{room::encryption::RoomEncryptionEventContent, InitialStateEvent}; @@ -114,11 +110,8 @@ type NotificationHandlerFut = Pin + Send>>; #[cfg(target_arch = "wasm32")] type NotificationHandlerFut = Pin>>; -#[cfg(not(target_arch = "wasm32"))] type NotificationHandlerFn = Box NotificationHandlerFut + Send + Sync>; -#[cfg(target_arch = "wasm32")] -type NotificationHandlerFn = Box NotificationHandlerFut>; /// Enum controlling if a loop running callbacks should continue or abort. /// @@ -894,7 +887,7 @@ impl Client { /// [`Client`] for now. pub async fn register_notification_handler(&self, handler: H) -> &Self where - H: Fn(Notification, Room, Client) -> Fut + SendOutsideWasm + SyncOutsideWasm + 'static, + H: Fn(Notification, Room, Client) -> Fut + Send + Sync + 'static, Fut: Future + SendOutsideWasm + 'static, { self.inner.notification_handlers.write().await.push(Box::new( @@ -948,7 +941,6 @@ impl Client { } /// Get a stream of all the rooms, in addition to the existing rooms. - #[cfg(not(target_arch = "wasm32"))] pub fn rooms_stream(&self) -> (Vector, impl Stream>> + '_) { let (rooms, stream) = self.base_client().rooms_stream(); diff --git a/crates/matrix-sdk/src/event_handler/mod.rs b/crates/matrix-sdk/src/event_handler/mod.rs index c375619811d..1a0022aa6d2 100644 --- a/crates/matrix-sdk/src/event_handler/mod.rs +++ b/crates/matrix-sdk/src/event_handler/mod.rs @@ -39,8 +39,7 @@ use std::{ future::Future, pin::Pin, sync::{ - atomic::{AtomicU64, Ordering::SeqCst}, - RwLock, + atomic::{AtomicU64, Ordering::SeqCst}, RwLock }, }; @@ -48,7 +47,7 @@ use anymap2::any::CloneAnySendSync; use futures_util::stream::{FuturesUnordered, StreamExt}; use matrix_sdk_base::{ deserialized_responses::{EncryptionInfo, SyncTimelineEvent}, - SendOutsideWasm, SyncOutsideWasm, + SendOutsideWasm, }; use ruma::{events::AnySyncStateEvent, push::Action, serde::Raw, OwnedRoomId}; use serde::{de::DeserializeOwned, Deserialize}; @@ -69,10 +68,7 @@ type EventHandlerFut = Pin + Send>>; #[cfg(target_arch = "wasm32")] type EventHandlerFut = Pin>>; -#[cfg(not(target_arch = "wasm32"))] type EventHandlerFn = dyn Fn(EventHandlerData<'_>) -> EventHandlerFut + Send + Sync; -#[cfg(target_arch = "wasm32")] -type EventHandlerFn = dyn Fn(EventHandlerData<'_>) -> EventHandlerFut; type AnyMap = anymap2::Map; @@ -197,7 +193,7 @@ pub struct EventHandlerHandle { /// /// ¹ the only thing stopping such types from existing in stable Rust is that /// all manual implementations of the `Fn` traits require a Nightly feature -pub trait EventHandler: Clone + SendOutsideWasm + SyncOutsideWasm + 'static { +pub trait EventHandler: Clone + Send + Sync + 'static { /// The future returned by `handle_event`. #[doc(hidden)] type Future: EventHandlerFuture; @@ -512,7 +508,7 @@ macro_rules! impl_event_handler { impl EventHandler for Fun where Ev: SyncEvent, - Fun: FnOnce(Ev, $($ty),*) -> Fut + Clone + SendOutsideWasm + SyncOutsideWasm + 'static, + Fun: FnOnce(Ev, $($ty),*) -> Fut + Clone + Send + Sync + 'static, Fut: EventHandlerFuture, $($ty: EventHandlerContext),* { diff --git a/crates/matrix-sdk/src/room/futures.rs b/crates/matrix-sdk/src/room/futures.rs index ee8d278a281..5c2063914f4 100644 --- a/crates/matrix-sdk/src/room/futures.rs +++ b/crates/matrix-sdk/src/room/futures.rs @@ -275,7 +275,6 @@ impl<'a> SendAttachment<'a> { /// Replace the default `SharedObservable` used for tracking upload /// progress. - #[cfg(not(target_arch = "wasm32"))] pub fn with_send_progress_observable( mut self, send_progress: SharedObservable, diff --git a/crates/matrix-sdk/src/sliding_sync/error.rs b/crates/matrix-sdk/src/sliding_sync/error.rs index c72d5333e03..5b06a120672 100644 --- a/crates/matrix-sdk/src/sliding_sync/error.rs +++ b/crates/matrix-sdk/src/sliding_sync/error.rs @@ -1,7 +1,7 @@ //! Sliding Sync errors. use thiserror::Error; -use tokio::task::JoinError; +use matrix_sdk_common::executor::JoinError; /// Internal representation of errors in Sliding Sync. #[derive(Error, Debug)] diff --git a/crates/matrix-sdk/src/sliding_sync/mod.rs b/crates/matrix-sdk/src/sliding_sync/mod.rs index 9de9a21afb7..3793bfe1f9d 100644 --- a/crates/matrix-sdk/src/sliding_sync/mod.rs +++ b/crates/matrix-sdk/src/sliding_sync/mod.rs @@ -22,7 +22,6 @@ mod error; mod list; mod room; mod sticky_parameters; -mod utils; use std::{ collections::{btree_map::Entry, BTreeMap, HashSet}, @@ -36,20 +35,21 @@ use async_stream::stream; pub use client::{Version, VersionBuilder}; use futures_core::stream::Stream; pub use matrix_sdk_base::sliding_sync::http; -use matrix_sdk_common::timer; +use matrix_sdk_common::{executor::spawn, timer}; +#[cfg(feature = "e2e-encryption")] +use matrix_sdk_common::executor::JoinHandleExt as _; + use ruma::{ api::{client::error::ErrorKind, OutgoingRequest}, assign, OwnedEventId, OwnedRoomId, RoomId, }; use serde::{Deserialize, Serialize}; use tokio::{ - select, spawn, + select, sync::{broadcast::Sender, Mutex as AsyncMutex, OwnedMutexGuard, RwLock as AsyncRwLock}, }; use tracing::{debug, error, info, instrument, trace, warn, Instrument, Span}; -#[cfg(feature = "e2e-encryption")] -use self::utils::JoinHandleExt as _; pub use self::{builder::*, client::VersionBuilderError, error::*, list::*, room::*}; use self::{ cache::restore_sliding_sync_state, @@ -609,6 +609,7 @@ impl SlidingSync { // aborted as soon as possible. let client = self.inner.client.clone(); + #[cfg(feature = "e2e-encryption")] let e2ee_uploads = spawn(async move { if let Err(error) = client.send_outgoing_requests().await { error!(?error, "Error while sending outgoing E2EE requests"); @@ -625,6 +626,7 @@ impl SlidingSync { // `e2ee_uploads`. It did run concurrently, so it should not be blocking for too // long. Otherwise —if `request` has failed— `e2ee_uploads` has // been dropped, so aborted. + #[cfg(feature = "e2e-encryption")] e2ee_uploads.await.map_err(|error| Error::JoinError { task_description: "e2ee_uploads".to_owned(), error, diff --git a/crates/matrix-sdk/src/sliding_sync/utils.rs b/crates/matrix-sdk/src/sliding_sync/utils.rs deleted file mode 100644 index 0bc1e998d43..00000000000 --- a/crates/matrix-sdk/src/sliding_sync/utils.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! Moaaar features for Sliding Sync. - -use std::{ - future::Future, - pin::Pin, - task::{Context, Poll}, -}; - -use tokio::task::{JoinError, JoinHandle}; - -/// Private type to ensure a task is aborted on drop. -pub(crate) struct AbortOnDrop(JoinHandle); - -impl AbortOnDrop { - fn new(join_handle: JoinHandle) -> Self { - Self(join_handle) - } -} - -impl Drop for AbortOnDrop { - fn drop(&mut self) { - self.0.abort(); - } -} - -impl Future for AbortOnDrop { - type Output = Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - Pin::new(&mut self.0).poll(cx) - } -} - -/// Private trait to create a `AbortOnDrop` from a `JoinHandle`. -pub(crate) trait JoinHandleExt { - fn abort_on_drop(self) -> AbortOnDrop; -} - -impl JoinHandleExt for JoinHandle { - fn abort_on_drop(self) -> AbortOnDrop { - AbortOnDrop::new(self) - } -}