diff --git a/crates/matrix-sdk-indexeddb/CHANGELOG.md b/crates/matrix-sdk-indexeddb/CHANGELOG.md index 3c749c8e466..c89b7bb7793 100644 --- a/crates/matrix-sdk-indexeddb/CHANGELOG.md +++ b/crates/matrix-sdk-indexeddb/CHANGELOG.md @@ -6,6 +6,14 @@ All notable changes to this project will be documented in this file. ## [Unreleased] - ReleaseDate +### Features + +- Expose implementations of `EventCacheStore` and `MediaStore` and add a + composite type for initializing all stores with a single function - i.e., + `IndexeddbStores::open`. Additionally, allow feature flags for each of the + stores to be used independent of and in combination with the others. + ([#5946](https://github.com/matrix-org/matrix-rust-sdk/pull/5946)) + ### Bug Fixes - Ensure that encrypted tests are run with a `StoreCipher`. This happened to reveal tests which fail in an diff --git a/crates/matrix-sdk-indexeddb/Cargo.toml b/crates/matrix-sdk-indexeddb/Cargo.toml index 0cf5a0f8918..8cdfd88ecc4 100644 --- a/crates/matrix-sdk-indexeddb/Cargo.toml +++ b/crates/matrix-sdk-indexeddb/Cargo.toml @@ -14,11 +14,14 @@ default-target = "wasm32-unknown-unknown" rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"] [features] -default = ["e2e-encryption", "state-store", "event-cache-store"] -event-cache-store = ["dep:matrix-sdk-base", "media-store"] -media-store = ["dep:matrix-sdk-base"] -state-store = ["dep:matrix-sdk-base", "growable-bloom-filter"] -e2e-encryption = ["dep:matrix-sdk-base", "dep:matrix-sdk-crypto"] +default = ["e2e-encryption", "state-store", "event-cache-store", "media-store"] +event-cache-store = ["dep:matrix-sdk-base", "media-store", "indexed-type-serializer"] +media-store = ["dep:matrix-sdk-base", "indexed-type-serializer"] +state-store = ["dep:matrix-sdk-base", "growable-bloom-filter", "safe-encode-traits"] +e2e-encryption = ["dep:matrix-sdk-base", "dep:matrix-sdk-crypto", "safe-encode-serializer"] +safe-encode-traits = [] +safe-encode-serializer = ["dep:matrix-sdk-crypto", "safe-encode-traits"] +indexed-type-serializer = ["safe-encode-serializer"] testing = ["matrix-sdk-crypto?/testing"] experimental-encrypted-state-events = [ "matrix-sdk-crypto?/experimental-encrypted-state-events" diff --git a/crates/matrix-sdk-indexeddb/src/event_cache_store/builder.rs b/crates/matrix-sdk-indexeddb/src/event_cache_store/builder.rs index 3e989c350fc..6d8bcd862f6 100644 --- a/crates/matrix-sdk-indexeddb/src/event_cache_store/builder.rs +++ b/crates/matrix-sdk-indexeddb/src/event_cache_store/builder.rs @@ -26,7 +26,7 @@ use crate::{ error::IndexeddbEventCacheStoreError, migrations::open_and_upgrade_db, IndexeddbEventCacheStore, }, - serializer::{IndexedTypeSerializer, SafeEncodeSerializer}, + serializer::{indexed_type::IndexedTypeSerializer, safe_encode::types::SafeEncodeSerializer}, }; /// A type for conveniently building an [`IndexeddbEventCacheStore`] @@ -56,6 +56,16 @@ impl IndexeddbEventCacheStoreBuilder { self } + /// Create a new [`IndexeddbEventCacheStoreBuilder`] where the database name + /// is constructed by joining the given prefix with + /// [`Self::DEFAULT_DATABASE_NAME`] and separated by `::`. + pub fn with_prefix(prefix: &str) -> Self { + Self { + database_name: format!("{}::{}", prefix, Self::DEFAULT_DATABASE_NAME), + store_cipher: None, + } + } + /// Sets the store cipher to use when encrypting data before it is persisted /// to the IndexedDB database. By default, no store cipher is used - /// i.e., data is not encrypted before it is persisted. diff --git a/crates/matrix-sdk-indexeddb/src/event_cache_store/mod.rs b/crates/matrix-sdk-indexeddb/src/event_cache_store/mod.rs index 2968fed9788..6b9696ef518 100644 --- a/crates/matrix-sdk-indexeddb/src/event_cache_store/mod.rs +++ b/crates/matrix-sdk-indexeddb/src/event_cache_store/mod.rs @@ -41,7 +41,7 @@ use crate::{ transaction::IndexeddbEventCacheStoreTransaction, types::{ChunkType, InBandEvent, Lease, OutOfBandEvent}, }, - serializer::{Indexed, IndexedTypeSerializer}, + serializer::indexed_type::{traits::Indexed, IndexedTypeSerializer}, transaction::TransactionError, }; diff --git a/crates/matrix-sdk-indexeddb/src/event_cache_store/serializer/indexed_types.rs b/crates/matrix-sdk-indexeddb/src/event_cache_store/serializer/indexed_types.rs index 7fb7496398b..d3454669fc8 100644 --- a/crates/matrix-sdk-indexeddb/src/event_cache_store/serializer/indexed_types.rs +++ b/crates/matrix-sdk-indexeddb/src/event_cache_store/serializer/indexed_types.rs @@ -44,10 +44,17 @@ use crate::{ types::{Chunk, Event, Gap, Lease, Position}, }, serializer::{ - Indexed, IndexedKey, IndexedKeyComponentBounds, IndexedPrefixKeyBounds, - IndexedPrefixKeyComponentBounds, MaybeEncrypted, SafeEncodeSerializer, - INDEXED_KEY_LOWER_CHARACTER, INDEXED_KEY_LOWER_STRING, INDEXED_KEY_UPPER_CHARACTER, - INDEXED_KEY_UPPER_STRING, + indexed_type::{ + constants::{ + INDEXED_KEY_LOWER_CHARACTER, INDEXED_KEY_LOWER_STRING, INDEXED_KEY_UPPER_CHARACTER, + INDEXED_KEY_UPPER_STRING, + }, + traits::{ + Indexed, IndexedKey, IndexedKeyComponentBounds, IndexedPrefixKeyBounds, + IndexedPrefixKeyComponentBounds, + }, + }, + safe_encode::types::{MaybeEncrypted, SafeEncodeSerializer}, }, }; diff --git a/crates/matrix-sdk-indexeddb/src/event_cache_store/transaction.rs b/crates/matrix-sdk-indexeddb/src/event_cache_store/transaction.rs index 2f43e40514d..19b8e141170 100644 --- a/crates/matrix-sdk-indexeddb/src/event_cache_store/transaction.rs +++ b/crates/matrix-sdk-indexeddb/src/event_cache_store/transaction.rs @@ -32,8 +32,9 @@ use crate::{ }, types::{Chunk, ChunkType, Event, Gap, Lease, Position}, }, - serializer::{ - Indexed, IndexedKeyRange, IndexedPrefixKeyBounds, IndexedPrefixKeyComponentBounds, + serializer::indexed_type::{ + range::IndexedKeyRange, + traits::{Indexed, IndexedPrefixKeyBounds, IndexedPrefixKeyComponentBounds}, IndexedTypeSerializer, }, transaction::{Transaction, TransactionError}, diff --git a/crates/matrix-sdk-indexeddb/src/lib.rs b/crates/matrix-sdk-indexeddb/src/lib.rs index f161d319dd8..755f25dc690 100644 --- a/crates/matrix-sdk-indexeddb/src/lib.rs +++ b/crates/matrix-sdk-indexeddb/src/lib.rs @@ -25,8 +25,156 @@ pub use state_store::{ MigrationConflictStrategy, }; +#[cfg(feature = "event-cache-store")] +pub use crate::event_cache_store::{ + IndexeddbEventCacheStore, IndexeddbEventCacheStoreBuilder, IndexeddbEventCacheStoreError, +}; +#[cfg(feature = "media-store")] +pub use crate::media_store::{ + IndexeddbMediaStore, IndexeddbMediaStoreBuilder, IndexeddbMediaStoreError, +}; + +/// Structure containing implementations of every type +/// of store using IndexedDB for persistent storage. +/// +/// Note that each of the stores is behind a feature flag and will +/// only be available when its corresponding flag is set. +pub struct IndexeddbStores { + /// An IndexedDB-backed implementation of [`CryptoStore`][1] + /// + /// [1]: matrix_sdk_crypto::store::CryptoStore + #[cfg(feature = "e2e-encryption")] + pub crypto: IndexeddbCryptoStore, + /// An IndexedDB-backed implementation of [`StateStore`][1] + /// + /// [1]: matrix_sdk_base::store::StateStore + #[cfg(feature = "state-store")] + pub state: IndexeddbStateStore, + /// An IndexedDB-backed implementation of [`EventCacheStore`][1] + /// + /// [1]: matrix_sdk_base::event_cache::store::EventCacheStore + #[cfg(feature = "event-cache-store")] + pub event_cache: IndexeddbEventCacheStore, + /// An IndexedDB-backed implementation of [`MediaStore`][1] + /// + /// [1]: matrix_sdk_base::media::store::MediaStore + #[cfg(feature = "media-store")] + pub media: IndexeddbMediaStore, +} + +impl IndexeddbStores { + /// Opens and returns all stores using the given database name and, + /// optionally, a passphrase. + /// + /// If `e2e-encryption` and `state-store` features are not enabled, + /// `passphrase` is ignored. Otherwise `passphrase` is used to import or + /// create a [`StoreCipher`][1] which encrypts contents of all stores. + /// + /// Note that each of the stores is behind a feature flag and will only be + /// opened when the corresponding flag is set. + /// + /// [1]: matrix_sdk_store_encryption::StoreCipher + pub async fn open( + name: &str, + #[allow(unused_variables)] passphrase: Option<&str>, + ) -> Result { + #[cfg(all(feature = "e2e-encryption", feature = "state-store"))] + if let Some(passphrase) = passphrase { + return Self::open_with_passphrase(name, passphrase).await; + } + + Self::open_without_passphrase(name).await + } + + /// Opens and returns all stores using the given database name. Contents of + /// the stores are NOT encrypted. + /// + /// Note that each of the stores is behind a feature flag and will only be + /// opened when the corresponding flag is set. + #[allow(clippy::unused_async)] + pub async fn open_without_passphrase(name: &str) -> Result { + #[cfg(feature = "state-store")] + let state = IndexeddbStateStore::builder() + .name(name.to_owned()) + .build() + .await + .map_err(StoreError::from)?; + + #[cfg(feature = "e2e-encryption")] + let crypto = IndexeddbCryptoStore::open_with_name(name).await?; + + #[cfg(feature = "event-cache-store")] + let event_cache = IndexeddbEventCacheStoreBuilder::with_prefix(name).build().await?; + + #[cfg(feature = "media-store")] + let media = IndexeddbMediaStoreBuilder::with_prefix(name).build().await?; + + Ok(Self { + #[cfg(feature = "state-store")] + state, + #[cfg(feature = "e2e-encryption")] + crypto, + #[cfg(feature = "event-cache-store")] + event_cache, + #[cfg(feature = "media-store")] + media, + }) + } + + /// Opens and returns all stores using the given database name and + /// passphrase. Passphrase is used to import or create a [`StoreCipher`][1] + /// which encrypts contents of all stores. + /// + /// Note that [`IndexeddbEventCacheStore`] and [`IndexeddbMediaStore`] are + /// behind feature flags and will only be opened when their + /// corresponding flags are set. + /// + /// [1]: matrix_sdk_store_encryption::StoreCipher + #[cfg(all(feature = "e2e-encryption", feature = "state-store"))] + pub async fn open_with_passphrase( + name: &str, + passphrase: &str, + ) -> Result { + let state = IndexeddbStateStore::builder() + .name(name.to_owned()) + .passphrase(passphrase.to_owned()) + .build() + .await + .map_err(StoreError::from)?; + let store_cipher = + state.store_cipher.clone().ok_or(OpenStoreError::FailedToLoadStoreCipher)?; + + let crypto = + IndexeddbCryptoStore::open_with_store_cipher(name, Some(store_cipher.clone())).await?; + + #[cfg(feature = "event-cache-store")] + let event_cache = IndexeddbEventCacheStoreBuilder::with_prefix(name) + .store_cipher(store_cipher.clone()) + .build() + .await?; + + #[cfg(feature = "media-store")] + let media = IndexeddbMediaStoreBuilder::with_prefix(name) + .store_cipher(store_cipher.clone()) + .build() + .await?; + + Ok(Self { + state, + crypto, + #[cfg(feature = "event-cache-store")] + event_cache, + #[cfg(feature = "media-store")] + media, + }) + } +} + /// Create a [`IndexeddbStateStore`] and a [`IndexeddbCryptoStore`] that use the /// same name and passphrase. +#[deprecated( + note = "this function only opens state and crypto stores, use `IndexeddbStores::open()` instead." +)] #[cfg(all(feature = "e2e-encryption", feature = "state-store"))] pub async fn open_stores_with_name( name: &str, @@ -75,4 +223,22 @@ pub enum OpenStoreError { #[cfg(feature = "e2e-encryption")] #[error(transparent)] Crypto(#[from] IndexeddbCryptoStoreError), + + /// An error occurred while trying to load a [`StoreCipher`][1] from a + /// passphrase + /// + /// [1]: matrix_sdk_store_encryption::StoreCipher + #[cfg(feature = "e2e-encryption")] + #[error("failed to load store cipher")] + FailedToLoadStoreCipher, + + /// An error occurred with the event cache store implementation. + #[cfg(feature = "event-cache-store")] + #[error(transparent)] + Event(#[from] IndexeddbEventCacheStoreError), + + /// An error occurred with the media store implementation. + #[cfg(feature = "media-store")] + #[error(transparent)] + Media(#[from] IndexeddbMediaStoreError), } diff --git a/crates/matrix-sdk-indexeddb/src/media_store/builder.rs b/crates/matrix-sdk-indexeddb/src/media_store/builder.rs index cfc5a13333f..1dede46d019 100644 --- a/crates/matrix-sdk-indexeddb/src/media_store/builder.rs +++ b/crates/matrix-sdk-indexeddb/src/media_store/builder.rs @@ -21,7 +21,7 @@ use crate::{ media_store::{ error::IndexeddbMediaStoreError, migrations::open_and_upgrade_db, IndexeddbMediaStore, }, - serializer::{IndexedTypeSerializer, SafeEncodeSerializer}, + serializer::{indexed_type::IndexedTypeSerializer, safe_encode::types::SafeEncodeSerializer}, }; /// A type for conveniently building an [`IndexeddbMediaStore`] @@ -44,6 +44,16 @@ impl IndexeddbMediaStoreBuilder { /// [`IndexeddbMediaStore`] pub const DEFAULT_DATABASE_NAME: &'static str = "media"; + /// Create a new [`IndexeddbMediaStoreBuilder`] where the database name is + /// constructed by joining the given prefix with + /// [`Self::DEFAULT_DATABASE_NAME`] and separated by `::`. + pub fn with_prefix(prefix: &str) -> Self { + Self { + database_name: format!("{}::{}", prefix, Self::DEFAULT_DATABASE_NAME), + store_cipher: None, + } + } + /// Sets the name of the IndexedDB database which will be opened. This /// defaults to [`Self::DEFAULT_DATABASE_NAME`]. pub fn database_name(mut self, name: String) -> Self { diff --git a/crates/matrix-sdk-indexeddb/src/media_store/mod.rs b/crates/matrix-sdk-indexeddb/src/media_store/mod.rs index 18836ea8011..92b8dc77898 100644 --- a/crates/matrix-sdk-indexeddb/src/media_store/mod.rs +++ b/crates/matrix-sdk-indexeddb/src/media_store/mod.rs @@ -53,7 +53,7 @@ use crate::{ transaction::IndexeddbMediaStoreTransaction, types::{Lease, Media, MediaCleanupTime, MediaContent, MediaMetadata, UnixTime}, }, - serializer::{Indexed, IndexedTypeSerializer}, + serializer::indexed_type::{traits::Indexed, IndexedTypeSerializer}, transaction::TransactionError, }; diff --git a/crates/matrix-sdk-indexeddb/src/media_store/serializer/constants.rs b/crates/matrix-sdk-indexeddb/src/media_store/serializer/constants.rs index 5578a339061..9f007854407 100644 --- a/crates/matrix-sdk-indexeddb/src/media_store/serializer/constants.rs +++ b/crates/matrix-sdk-indexeddb/src/media_store/serializer/constants.rs @@ -17,9 +17,8 @@ use crate::{ serializer::indexed_types::{IndexedMediaContentId, IndexedMediaContentSize}, types::UnixTime, }, - serializer::{ - indexed_type::constants::{INDEXED_KEY_LOWER_UUID, INDEXED_KEY_UPPER_UUID}, - INDEXED_KEY_UPPER_DURATION_SECONDS, + serializer::indexed_type::constants::{ + INDEXED_KEY_LOWER_UUID, INDEXED_KEY_UPPER_DURATION_SECONDS, INDEXED_KEY_UPPER_UUID, }, }; diff --git a/crates/matrix-sdk-indexeddb/src/media_store/serializer/indexed_types.rs b/crates/matrix-sdk-indexeddb/src/media_store/serializer/indexed_types.rs index 6a0574230d2..fc6ed368197 100644 --- a/crates/matrix-sdk-indexeddb/src/media_store/serializer/indexed_types.rs +++ b/crates/matrix-sdk-indexeddb/src/media_store/serializer/indexed_types.rs @@ -53,8 +53,13 @@ use crate::{ types::{Lease, MediaCleanupTime, MediaContent, MediaMetadata, UnixTime}, }, serializer::{ - Indexed, IndexedKey, IndexedKeyComponentBounds, IndexedPrefixKeyComponentBounds, - MaybeEncrypted, SafeEncodeSerializer, INDEXED_KEY_LOWER_STRING, INDEXED_KEY_UPPER_STRING, + indexed_type::{ + constants::{INDEXED_KEY_LOWER_STRING, INDEXED_KEY_UPPER_STRING}, + traits::{ + Indexed, IndexedKey, IndexedKeyComponentBounds, IndexedPrefixKeyComponentBounds, + }, + }, + safe_encode::types::{MaybeEncrypted, SafeEncodeSerializer}, }, }; diff --git a/crates/matrix-sdk-indexeddb/src/media_store/transaction.rs b/crates/matrix-sdk-indexeddb/src/media_store/transaction.rs index 5d28649f7d5..e492d4aaf4b 100644 --- a/crates/matrix-sdk-indexeddb/src/media_store/transaction.rs +++ b/crates/matrix-sdk-indexeddb/src/media_store/transaction.rs @@ -33,7 +33,9 @@ use crate::{ }, types::{Lease, Media, MediaCleanupTime, MediaContent, MediaMetadata, UnixTime}, }, - serializer::{IndexedKeyRange, IndexedPrefixKeyComponentBounds, IndexedTypeSerializer}, + serializer::indexed_type::{ + range::IndexedKeyRange, traits::IndexedPrefixKeyComponentBounds, IndexedTypeSerializer, + }, transaction::{Transaction, TransactionError}, }; diff --git a/crates/matrix-sdk-indexeddb/src/serializer/indexed_type/mod.rs b/crates/matrix-sdk-indexeddb/src/serializer/indexed_type/mod.rs index b4480c56abc..66182ee3dc8 100644 --- a/crates/matrix-sdk-indexeddb/src/serializer/indexed_type/mod.rs +++ b/crates/matrix-sdk-indexeddb/src/serializer/indexed_type/mod.rs @@ -30,7 +30,7 @@ use thiserror::Error; use traits::{Indexed, IndexedKey}; use wasm_bindgen::JsValue; -use crate::serializer::SafeEncodeSerializer; +use crate::serializer::safe_encode::types::SafeEncodeSerializer; #[derive(Debug, Error)] pub enum IndexedTypeSerializerError { diff --git a/crates/matrix-sdk-indexeddb/src/serializer/indexed_type/range.rs b/crates/matrix-sdk-indexeddb/src/serializer/indexed_type/range.rs index 952b0573ec2..78ee735da69 100644 --- a/crates/matrix-sdk-indexeddb/src/serializer/indexed_type/range.rs +++ b/crates/matrix-sdk-indexeddb/src/serializer/indexed_type/range.rs @@ -13,7 +13,8 @@ // limitations under the License use crate::serializer::{ - Indexed, IndexedKey, IndexedKeyBounds, IndexedPrefixKeyBounds, SafeEncodeSerializer, + indexed_type::traits::{Indexed, IndexedKey, IndexedKeyBounds, IndexedPrefixKeyBounds}, + safe_encode::types::SafeEncodeSerializer, }; /// Representation of a range of keys of type `K`. This is loosely diff --git a/crates/matrix-sdk-indexeddb/src/serializer/indexed_type/traits.rs b/crates/matrix-sdk-indexeddb/src/serializer/indexed_type/traits.rs index a974431087c..7254cb75a5c 100644 --- a/crates/matrix-sdk-indexeddb/src/serializer/indexed_type/traits.rs +++ b/crates/matrix-sdk-indexeddb/src/serializer/indexed_type/traits.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License -use crate::serializer::SafeEncodeSerializer; +use crate::serializer::safe_encode::types::SafeEncodeSerializer; /// A conversion trait for preparing high-level types into indexed types /// which are better suited for storage in IndexedDB. diff --git a/crates/matrix-sdk-indexeddb/src/serializer/mod.rs b/crates/matrix-sdk-indexeddb/src/serializer/mod.rs index 573e2329c25..6f27c5461d1 100644 --- a/crates/matrix-sdk-indexeddb/src/serializer/mod.rs +++ b/crates/matrix-sdk-indexeddb/src/serializer/mod.rs @@ -14,29 +14,9 @@ #[cfg(feature = "e2e-encryption")] pub mod foreign; - -#[cfg(all( - feature = "e2e-encryption", - any(feature = "event-cache-store", feature = "media-store") -))] +#[cfg(feature = "indexed-type-serializer")] pub mod indexed_type; -#[cfg(all( - feature = "e2e-encryption", - any(feature = "event-cache-store", feature = "media-store") -))] -pub use indexed_type::{ - constants::{ - INDEXED_KEY_LOWER_CHARACTER, INDEXED_KEY_LOWER_STRING, INDEXED_KEY_UPPER_CHARACTER, - INDEXED_KEY_UPPER_DURATION_SECONDS, INDEXED_KEY_UPPER_STRING, - }, - range::IndexedKeyRange, - traits::{ - Indexed, IndexedKey, IndexedKeyBounds, IndexedKeyComponentBounds, IndexedPrefixKeyBounds, - IndexedPrefixKeyComponentBounds, - }, - IndexedTypeSerializer, -}; - +#[cfg(any(feature = "safe-encode-traits", feature = "safe-encode-serializer"))] pub mod safe_encode; #[cfg(feature = "e2e-encryption")] pub use safe_encode::types::{MaybeEncrypted, SafeEncodeSerializer, SafeEncodeSerializerError}; diff --git a/crates/matrix-sdk-indexeddb/src/serializer/safe_encode/mod.rs b/crates/matrix-sdk-indexeddb/src/serializer/safe_encode/mod.rs index 669b2306da8..3179ce86482 100644 --- a/crates/matrix-sdk-indexeddb/src/serializer/safe_encode/mod.rs +++ b/crates/matrix-sdk-indexeddb/src/serializer/safe_encode/mod.rs @@ -12,7 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#[cfg(feature = "safe-encode-traits")] pub mod traits; -#[cfg(feature = "e2e-encryption")] +#[cfg(feature = "safe-encode-serializer")] pub mod types; diff --git a/crates/matrix-sdk-indexeddb/src/transaction/mod.rs b/crates/matrix-sdk-indexeddb/src/transaction/mod.rs index 9791081a8fd..03074190e82 100644 --- a/crates/matrix-sdk-indexeddb/src/transaction/mod.rs +++ b/crates/matrix-sdk-indexeddb/src/transaction/mod.rs @@ -32,7 +32,11 @@ use wasm_bindgen::JsValue; use crate::{ error::{AsyncErrorDeps, GenericError}, - serializer::{Indexed, IndexedKey, IndexedKeyRange, IndexedTypeSerializer}, + serializer::indexed_type::{ + range::IndexedKeyRange, + traits::{Indexed, IndexedKey}, + IndexedTypeSerializer, + }, }; #[derive(Debug, Error)] diff --git a/crates/matrix-sdk/CHANGELOG.md b/crates/matrix-sdk/CHANGELOG.md index d06ac294059..4a16866c2ad 100644 --- a/crates/matrix-sdk/CHANGELOG.md +++ b/crates/matrix-sdk/CHANGELOG.md @@ -20,6 +20,9 @@ All notable changes to this project will be documented in this file. - Expose a new method `RoomEventCache::find_event_relations` for loading events relating to a specific event ID from the cache. [#5930](https://github.com/matrix-org/matrix-rust-sdk/pull/5930/) +- Replace in-memory stores with IndexedDB implementations when initializing + `Client` with `BuilderStoreConfig::IndexedDb`. + [#5946](https://github.com/matrix-org/matrix-rust-sdk/pull/5946) ## [0.16.0] - 2025-12-04 @@ -85,8 +88,8 @@ All notable changes to this project will be documented in this file. Client-Server API. This allows to drop the `HttpError::NotClientRequest` error in favor of a compile-time error. ([#5781](https://github.com/matrix-org/matrix-rust-sdk/pull/5781), - [#5789](https://github.com/matrix-org/matrix-rust-sdk/pull/5789), - [#5815](https://github.com/matrix-org/matrix-rust-sdk/pull/5815)) + [#5789](https://github.com/matrix-org/matrix-rust-sdk/pull/5789), + [#5815](https://github.com/matrix-org/matrix-rust-sdk/pull/5815)) - [**breaking**]: The `waveform` field was moved from `AttachmentInfo::Voice` to `BaseAudioInfo`, allowing to set it for any audio message. Its format also changed, and it is now a list of `f32` between 0 and 1. @@ -134,6 +137,7 @@ All notable changes to this project will be documented in this file. } ) ``` + ([#5560](https://github.com/matrix-org/matrix-rust-sdk/pull/5560)) ### Bugfix @@ -228,9 +232,9 @@ All notable changes to this project will be documented in this file. statically-known. Before, those events would never trigger an event handler. ([#5444](https://github.com/matrix-org/matrix-rust-sdk/pull/5444)) - All HTTP requests now have a default `read_timeout` of 60s, which means they'll disconnect if the connection stalls. - `RequestConfig::timeout` is now optional and can be disabled on a per-request basis. This will be done for - the requests used to download media, so they don't get cancelled after the default 30s timeout for no good reason. - ([#5437](https://github.com/matrix-org/matrix-rust-sdk/pull/5437)) + `RequestConfig::timeout` is now optional and can be disabled on a per-request basis. This will be done for + the requests used to download media, so they don't get cancelled after the default 30s timeout for no good reason. + ([#5437](https://github.com/matrix-org/matrix-rust-sdk/pull/5437)) ## [0.13.0] - 2025-07-10 @@ -296,7 +300,7 @@ All notable changes to this project will be documented in this file. ### Bug fixes - `m.room.avatar` has been added as required state for sliding sync until [the existing backend issue](https://github.com/element-hq/synapse/issues/18598) -causing deleted room avatars to not be flagged is fixed. ([#5293](https://github.com/matrix-org/matrix-rust-sdk/pull/5293)) + causing deleted room avatars to not be flagged is fixed. ([#5293](https://github.com/matrix-org/matrix-rust-sdk/pull/5293)) ## [0.12.0] - 2025-06-10 @@ -380,9 +384,9 @@ causing deleted room avatars to not be flagged is fixed. ([#5293](https://github - [**breaking**]: The element call widget URL configuration struct (`VirtualElementCallWidgetOptions`) and URL generation have changed. - It supports the new fields: `hide_screensharing`, `posthog_api_host`, `posthog_api_key`, - `rageshake_submit_url`, `sentry_dsn`, `sentry_environment`. + `rageshake_submit_url`, `sentry_dsn`, `sentry_environment`. - The widget URL will no longer automatically add `/room` to the base domain. For backward compatibility - the app itself would need to add `/room` to the `element_call_url`. + the app itself would need to add `/room` to the `element_call_url`. - And replaced: - `analytics_id` -> `posthog_user_id` (The widget URL query parameters will include `analytics_id` & `posthog_user_id` for backward compatibility) @@ -390,14 +394,14 @@ causing deleted room avatars to not be flagged is fixed. ([#5293](https://github The widget URL query parameters will include `skip_lobby` if `intent` is `Intent.StartCall` for backward compatibility) - `VirtualElementCallWidgetOptions` now implements `Default`. - ([#4822](https://github.com/matrix-org/matrix-rust-sdk/pull/4822)) + ([#4822](https://github.com/matrix-org/matrix-rust-sdk/pull/4822)) - [**breaking**]: The `RoomPagination::run_backwards` method has been removed and replaced by two -simpler methods: + simpler methods: - `RoomPagination::run_backwards_until()`, which will retrigger back-paginations until a certain - number of events have been received (and retry if the timeline has been reset in the background). + number of events have been received (and retry if the timeline has been reset in the background). - `RoomPagination::run_backwards_once()`, which will run a single back-pagination (and retry if - the timeline has been reset in the background). - ([#4689](https://github.com/matrix-org/matrix-rust-sdk/pull/4689)) + the timeline has been reset in the background). + ([#4689](https://github.com/matrix-org/matrix-rust-sdk/pull/4689)) - [**breaking**]: The `OAuth::account_management_url` method now caches the result of a call, subsequent calls to the method will not contact the server for a while, instead the cached URI will be returned. If caching of this URI @@ -411,8 +415,8 @@ simpler methods: ([#4647](https://github.com/matrix-org/matrix-rust-sdk/pull/4647)) - Add `Room::report_room` api. ([#4713](https://github.com/matrix-org/matrix-rust-sdk/pull/4713)) - `Client::notification_client` will create a copy of the existing `Client`, - but now it'll make sure it doesn't handle any verification events to - avoid an issue with these events being received and processed twice if + but now it'll make sure it doesn't handle any verification events to + avoid an issue with these events being received and processed twice if `NotificationProcessSetup` was `SingleSetup`. - [**breaking**] `Room::is_encrypted` is replaced by `Room::latest_encryption_state` which returns a value of the new @@ -431,6 +435,7 @@ simpler methods: ```rust room.latest_encryption_state().await?.is_encrypted() ``` + - `LocalServerBuilder`, behind the `local-server` feature, can be used to spawn a server when the end-user needs to be redirected to an address on localhost. It was used for `SsoLoginBuilder` and can now be used in other cases, like for @@ -459,7 +464,6 @@ simpler methods: ### Refactor - - [**breaking**] Switched from the unmaintained backoff crate to the [backon](https://docs.rs/backon/1.5.0/backon/) crate. As part of this change, the `RequestConfig::retry_limit` method was renamed to `RequestConfig::max_retry_time` and the parameter for the method was @@ -705,7 +709,7 @@ simpler methods: - [**breaking**]: The `RoomEventCacheUpdate::Clear` variant has been removed, as it is redundant with the `RoomEventCacheUpdate::UpdateTimelineEvents { diffs: - Vec>, .. }` where `VectorDiff` has its own `Clear` variant. +Vec>, .. }` where `VectorDiff` has its own `Clear` variant. ([#4627](https://github.com/matrix-org/matrix-rust-sdk/pull/4627)) - Improve the performance of `EventCache` (approximately 4.5 times faster). @@ -788,24 +792,22 @@ simpler methods: - Improve documentation of `Client::observe_events`. - ### Features - - Add `create_room_alias` function. - `Client::cross_process_store_locks_holder_name` is used everywhere: - - `StoreConfig::new()` now takes a - `cross_process_store_locks_holder_name` argument. - - `StoreConfig` no longer implements `Default`. - - `BaseClient::new()` has been removed. - - `BaseClient::clone_with_in_memory_state_store()` now takes a - `cross_process_store_locks_holder_name` argument. - - `BaseClient` no longer implements `Default`. - - `EventCacheStoreLock::new()` no longer takes a `key` argument. - - `BuilderStoreConfig` no longer has - `cross_process_store_locks_holder_name` field for `Sqlite` and - `IndexedDb`. +- `StoreConfig::new()` now takes a + `cross_process_store_locks_holder_name` argument. +- `StoreConfig` no longer implements `Default`. +- `BaseClient::new()` has been removed. +- `BaseClient::clone_with_in_memory_state_store()` now takes a + `cross_process_store_locks_holder_name` argument. +- `BaseClient` no longer implements `Default`. +- `EventCacheStoreLock::new()` no longer takes a `key` argument. +- `BuilderStoreConfig` no longer has + `cross_process_store_locks_holder_name` field for `Sqlite` and + `IndexedDb`. - `EncryptionSyncService` and `Notification` are using `Client::cross_process_store_locks_holder_name`. @@ -819,20 +821,20 @@ simpler methods: `Client::add_room_event_handler` but with a reactive programming pattern. Add `Client::observe_events` and `Client::observe_room_events`. - ```rust - // Get an observer. - let observer = - client.observe_events::)>(); +```rust +// Get an observer. +let observer = + client.observe_events::)>(); - // Subscribe to the observer. - let mut subscriber = observer.subscribe(); +// Subscribe to the observer. +let mut subscriber = observer.subscribe(); - // Use the subscriber as a `Stream`. - let (message_event, (room, push_actions)) = subscriber.next().await.unwrap(); - ``` +// Use the subscriber as a `Stream`. +let (message_event, (room, push_actions)) = subscriber.next().await.unwrap(); +``` - When calling `observe_events`, one has to specify the type of event (in the - example, `SyncRoomMessageEvent`) and a context (in the example, `(Room, +When calling `observe_events`, one has to specify the type of event (in the +example, `SyncRoomMessageEvent`) and a context (in the example, `(Room, Vec)`, respectively for the room and the push actions). - Implement unwedging for media uploads. @@ -870,8 +872,8 @@ simpler methods: - Implement proper redact handling in the widget driver. This allows the Rust SDK widget driver to support widgets that rely on redacting. - ### Refactor + - [**breaking**] Rename `DisplayName` to `RoomDisplayName`. - Improve `is_room_alias_format_valid` so it's more strict. diff --git a/crates/matrix-sdk/Cargo.toml b/crates/matrix-sdk/Cargo.toml index 6dd6e0ad9b5..1a1f49683fc 100644 --- a/crates/matrix-sdk/Cargo.toml +++ b/crates/matrix-sdk/Cargo.toml @@ -41,7 +41,11 @@ sqlite = [ "matrix-sdk-sqlite?/event-cache", ] bundled-sqlite = ["sqlite", "matrix-sdk-sqlite?/bundled"] -indexeddb = ["matrix-sdk-indexeddb/state-store"] +indexeddb = [ + "matrix-sdk-indexeddb/state-store", + "matrix-sdk-indexeddb/event-cache-store", + "matrix-sdk-indexeddb/media-store" +] qrcode = ["e2e-encryption", "matrix-sdk-base/qrcode"] automatic-room-key-forwarding = ["e2e-encryption", "matrix-sdk-base/automatic-room-key-forwarding"] diff --git a/crates/matrix-sdk/src/client/builder/mod.rs b/crates/matrix-sdk/src/client/builder/mod.rs index d81702013ed..f9d0f5d7700 100644 --- a/crates/matrix-sdk/src/client/builder/mod.rs +++ b/crates/matrix-sdk/src/client/builder/mod.rs @@ -706,28 +706,14 @@ async fn build_indexeddb_store_config( ) -> Result { let cross_process_store_locks_holder_name = cross_process_store_locks_holder_name.to_owned(); - #[cfg(feature = "e2e-encryption")] - let store_config = { - let (state_store, crypto_store) = - matrix_sdk_indexeddb::open_stores_with_name(name, passphrase).await?; - StoreConfig::new(cross_process_store_locks_holder_name) - .state_store(state_store) - .crypto_store(crypto_store) - }; - - #[cfg(not(feature = "e2e-encryption"))] - let store_config = { - let state_store = matrix_sdk_indexeddb::open_state_store(name, passphrase).await?; - StoreConfig::new(cross_process_store_locks_holder_name).state_store(state_store) - }; + let stores = matrix_sdk_indexeddb::IndexeddbStores::open(name, passphrase).await?; + let store_config = StoreConfig::new(cross_process_store_locks_holder_name) + .state_store(stores.state) + .event_cache_store(stores.event_cache) + .media_store(stores.media); - let store_config = { - tracing::warn!( - "The IndexedDB backend does not implement an event cache store, \ - falling back to the in-memory event cache store…" - ); - store_config.event_cache_store(matrix_sdk_base::event_cache::store::MemoryStore::new()) - }; + #[cfg(feature = "e2e-encryption")] + let store_config = store_config.crypto_store(stores.crypto); Ok(store_config) }