diff --git a/bindings/matrix-sdk-ffi/CHANGELOG.md b/bindings/matrix-sdk-ffi/CHANGELOG.md index 252f56772ca..99ce7465926 100644 --- a/bindings/matrix-sdk-ffi/CHANGELOG.md +++ b/bindings/matrix-sdk-ffi/CHANGELOG.md @@ -18,6 +18,8 @@ Breaking changes: - `RoomInfo` replaces its field `is_tombstoned: bool` with `tombstone: Option`, containing the data needed to implement the room migration UI, a message and the replacement room id. ([#5027](https://github.com/matrix-org/matrix-rust-sdk/pull/5027)) +- Encapsulate the configuration of the sqlite system into a builder `SqliteSessionBuilder` to allow for + swapping with `IndexedDbSessionBuilder` on Wasm platforms. Additions: diff --git a/bindings/matrix-sdk-ffi/Cargo.toml b/bindings/matrix-sdk-ffi/Cargo.toml index b9b603f37e8..0e3fead9f23 100644 --- a/bindings/matrix-sdk-ffi/Cargo.toml +++ b/bindings/matrix-sdk-ffi/Cargo.toml @@ -14,17 +14,17 @@ publish = false release = true [lib] -crate-type = ["cdylib", "staticlib"] +crate-type = ["cdylib", "staticlib", "lib"] [features] default = ["bundled-sqlite", "unstable-msc4274"] bundled-sqlite = ["matrix-sdk/bundled-sqlite"] unstable-msc4274 = ["matrix-sdk-ui/unstable-msc4274"] +cross-platform-api = [] [dependencies] anyhow.workspace = true as_variant.workspace = true -async-compat = "0.2.4" extension-trait = "1.0.1" eyeball-im.workspace = true futures-util.workspace = true @@ -36,21 +36,18 @@ matrix-sdk-ui = { workspace = true, features = ["uniffi"] } mime = "0.3.16" once_cell.workspace = true ruma = { workspace = true, features = ["html", "unstable-unspecified", "unstable-msc3488", "compat-unset-avatar", "unstable-msc3245-v1-compat", "unstable-msc4278"] } -sentry-tracing = "0.36.0" serde.workspace = true serde_json.workspace = true thiserror.workspace = true -tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } tracing.workspace = true tracing-appender = { version = "0.2.2" } tracing-core.workspace = true tracing-subscriber = { workspace = true, features = ["env-filter"] } -uniffi = { workspace = true, features = ["tokio"] } url.workspace = true uuid = { version = "1.4.1", features = ["v4"] } zeroize.workspace = true -[target.'cfg(not(target_os = "android"))'.dependencies.matrix-sdk] +[target.'cfg(all(not(target_os = "android"), not(target_family = "wasm")))'.dependencies.matrix-sdk] workspace = true features = [ "anyhow", @@ -64,7 +61,7 @@ features = [ "uniffi", ] -[target.'cfg(not(target_os = "android"))'.dependencies.sentry] +[target.'cfg(all(not(target_os = "android"), not(target_family = "wasm")))'.dependencies.sentry] version = "0.36.0" default-features = false features = [ @@ -77,6 +74,31 @@ features = [ "reqwest", ] +[target.'cfg(target_family = "wasm")'.dependencies] +matrix-sdk-ui = { workspace = true, features = ["js", "uniffi"] } +tokio = { workspace = true, features = ["sync", "macros"] } +uniffi = { workspace = true, features = [] } + +[target.'cfg(target_family = "wasm")'.dependencies.matrix-sdk] +workspace = true +features = [ + "anyhow", + "e2e-encryption", + "experimental-widgets", + "markdown", + "native-tls", + "socks", + "indexeddb", + "uniffi", +] + +[target.'cfg(not(target_family = "wasm"))'.dependencies] +async-compat.workspace = true +matrix-sdk-ui = { workspace = true, features = ["uniffi"] } +sentry-tracing = "0.36.0" +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } +uniffi = { workspace = true, features = ["tokio"] } + [target.'cfg(target_os = "android")'.dependencies] paranoid-android = "0.2.1" diff --git a/bindings/matrix-sdk-ffi/src/client_builder.rs b/bindings/matrix-sdk-ffi/src/client_builder.rs index 1bc37176b6b..aedc03ca972 100644 --- a/bindings/matrix-sdk-ffi/src/client_builder.rs +++ b/bindings/matrix-sdk-ffi/src/client_builder.rs @@ -1,6 +1,12 @@ -use std::{fs, num::NonZeroUsize, path::Path, sync::Arc, time::Duration}; +#[cfg(not(target_family = "wasm"))] +use std::{fs, path::Path}; +use std::{num::NonZeroUsize, sync::Arc, time::Duration}; use futures_util::StreamExt; +#[cfg(not(target_family = "wasm"))] +use matrix_sdk::reqwest::{Certificate, Proxy}; +#[cfg(not(target_family = "wasm"))] +use matrix_sdk::SqliteStoreConfig; use matrix_sdk::{ authentication::oauth::qrcode::{self, DeviceCodeErrorResponseType, LoginFailureReason}, crypto::{ @@ -9,14 +15,13 @@ use matrix_sdk::{ }, encryption::{BackupDownloadStrategy, EncryptionSettings}, event_cache::EventCacheError, - reqwest::Certificate, ruma::{ServerName, UserId}, sliding_sync::{ Error as MatrixSlidingSyncError, VersionBuilder as MatrixSlidingSyncVersionBuilder, VersionBuilderError, }, Client as MatrixClient, ClientBuildError as MatrixClientBuildError, HttpError, IdParseError, - RumaApiError, SqliteStoreConfig, + RumaApiError, }; use matrix_sdk_common::{runtime::get_runtime_handle, SendOutsideWasm, SyncOutsideWasm}; use ruma::api::error::{DeserializationError, FromHttpResponseError}; @@ -264,91 +269,30 @@ impl From for ClientBuildError { } } +#[cfg(any(not(target_family = "wasm"), feature = "cross-platform-api"))] #[derive(Clone, uniffi::Object)] -pub struct ClientBuilder { - session_paths: Option, - session_passphrase: Zeroizing>, - session_pool_max_size: Option, - session_cache_size: Option, - session_journal_size_limit: Option, +pub struct SqliteSessionBuilder { + paths: Option, + passphrase: Zeroizing>, + pool_max_size: Option, + cache_size: Option, + journal_size_limit: Option, system_is_memory_constrained: bool, - username: Option, - homeserver_cfg: Option, - user_agent: Option, - sliding_sync_version_builder: SlidingSyncVersionBuilder, - proxy: Option, - disable_ssl_verification: bool, - disable_automatic_token_refresh: bool, - cross_process_store_locks_holder_name: Option, - enable_oidc_refresh_lock: bool, - session_delegate: Option>, - additional_root_certificates: Vec>, - disable_built_in_root_certificates: bool, - encryption_settings: EncryptionSettings, - room_key_recipient_strategy: CollectStrategy, - decryption_trust_requirement: TrustRequirement, - enable_share_history_on_invite: bool, - request_config: Option, } +#[cfg(any(not(target_family = "wasm"), feature = "cross-platform-api"))] #[matrix_sdk_ffi_macros::export] -impl ClientBuilder { +impl SqliteSessionBuilder { #[uniffi::constructor] - pub fn new() -> Arc { - Arc::new(Self { - session_paths: None, - session_passphrase: Zeroizing::new(None), - session_pool_max_size: None, - session_cache_size: None, - session_journal_size_limit: None, + pub fn new() -> Self { + Self { + paths: None, + passphrase: Zeroizing::new(None), + pool_max_size: None, + cache_size: None, + journal_size_limit: None, system_is_memory_constrained: false, - username: None, - homeserver_cfg: None, - user_agent: None, - sliding_sync_version_builder: SlidingSyncVersionBuilder::None, - proxy: None, - disable_ssl_verification: false, - disable_automatic_token_refresh: false, - cross_process_store_locks_holder_name: None, - enable_oidc_refresh_lock: false, - session_delegate: None, - additional_root_certificates: Default::default(), - disable_built_in_root_certificates: false, - encryption_settings: EncryptionSettings { - auto_enable_cross_signing: false, - backup_download_strategy: - matrix_sdk::encryption::BackupDownloadStrategy::AfterDecryptionFailure, - auto_enable_backups: false, - }, - room_key_recipient_strategy: Default::default(), - decryption_trust_requirement: TrustRequirement::Untrusted, - enable_share_history_on_invite: false, - request_config: Default::default(), - }) - } - - pub fn cross_process_store_locks_holder_name( - self: Arc, - holder_name: String, - ) -> Arc { - let mut builder = unwrap_or_clone_arc(self); - builder.cross_process_store_locks_holder_name = Some(holder_name); - Arc::new(builder) - } - - pub fn enable_oidc_refresh_lock(self: Arc) -> Arc { - let mut builder = unwrap_or_clone_arc(self); - builder.enable_oidc_refresh_lock = true; - Arc::new(builder) - } - - pub fn set_session_delegate( - self: Arc, - session_delegate: Box, - ) -> Arc { - let mut builder = unwrap_or_clone_arc(self); - builder.session_delegate = Some(session_delegate.into()); - Arc::new(builder) + } } /// Sets the paths that the client will use to store its data and caches. @@ -357,17 +301,17 @@ impl ClientBuilder { /// same path for both stores on a single session. /// /// Leaving this unset tells the client to use an in-memory data store. - pub fn session_paths(self: Arc, data_path: String, cache_path: String) -> Arc { + pub fn paths(self: Arc, data_path: String, cache_path: String) -> Arc { let mut builder = unwrap_or_clone_arc(self); - builder.session_paths = Some(SessionPaths { data_path, cache_path }); + builder.paths = Some(SessionPaths { data_path, cache_path }); Arc::new(builder) } /// Set the passphrase for the stores given to - /// [`ClientBuilder::session_paths`]. - pub fn session_passphrase(self: Arc, passphrase: Option) -> Arc { + /// [`SqliteSessionBuilder::paths`]. + pub fn passphrase(self: Arc, passphrase: Option) -> Arc { let mut builder = unwrap_or_clone_arc(self); - builder.session_passphrase = Zeroizing::new(passphrase); + builder.passphrase = Zeroizing::new(passphrase); Arc::new(builder) } @@ -380,9 +324,9 @@ impl ClientBuilder { /// to wait on a pool to be available to run queries. /// /// See [`SqliteStoreConfig::pool_max_size`] to learn more. - pub fn session_pool_max_size(self: Arc, pool_max_size: Option) -> Arc { + pub fn pool_max_size(self: Arc, pool_max_size: Option) -> Arc { let mut builder = unwrap_or_clone_arc(self); - builder.session_pool_max_size = pool_max_size + builder.pool_max_size = pool_max_size .map(|size| size.try_into().expect("`pool_max_size` is too large to fit in `usize`")); Arc::new(builder) } @@ -399,9 +343,9 @@ impl ClientBuilder { /// in smaller chunks on an as-needed basis. /// /// See [`SqliteStoreConfig::cache_size`] to learn more. - pub fn session_cache_size(self: Arc, cache_size: Option) -> Arc { + pub fn cache_size(self: Arc, cache_size: Option) -> Arc { let mut builder = unwrap_or_clone_arc(self); - builder.session_cache_size = cache_size; + builder.cache_size = cache_size; Arc::new(builder) } @@ -412,9 +356,9 @@ impl ClientBuilder { /// limit of the WAL files, in **bytes (!)**. /// /// See [`SqliteStoreConfig::journal_size_limit`] to learn more. - pub fn session_journal_size_limit(self: Arc, limit: Option) -> Arc { + pub fn journal_size_limit(self: Arc, limit: Option) -> Arc { let mut builder = unwrap_or_clone_arc(self); - builder.session_journal_size_limit = limit; + builder.journal_size_limit = limit; Arc::new(builder) } @@ -430,80 +374,163 @@ impl ClientBuilder { builder.system_is_memory_constrained = true; Arc::new(builder) } +} - pub fn username(self: Arc, username: String) -> Arc { - let mut builder = unwrap_or_clone_arc(self); - builder.username = Some(username); - Arc::new(builder) +#[cfg(any(target_family = "wasm", feature = "cross-platform-api"))] +#[derive(Clone, uniffi::Object)] +pub struct IndexedDbSessionBuilder { + #[cfg_attr(not(target_family = "wasm"), allow(unused))] + name: String, + passphrase: Option, +} + +#[cfg(any(target_family = "wasm", feature = "cross-platform-api"))] +#[matrix_sdk_ffi_macros::export] +impl IndexedDbSessionBuilder { + #[uniffi::constructor] + pub fn new(name: String) -> Arc { + Arc::new(Self { name, passphrase: None }) } - pub fn server_name(self: Arc, server_name: String) -> Arc { + /// Set the passphrase for the IndexedDB store. + pub fn passphrase(self: Arc, passphrase: Option) -> Arc { let mut builder = unwrap_or_clone_arc(self); - builder.homeserver_cfg = Some(HomeserverConfig::ServerName(server_name)); + builder.passphrase = passphrase; Arc::new(builder) } +} - pub fn homeserver_url(self: Arc, url: String) -> Arc { - let mut builder = unwrap_or_clone_arc(self); - builder.homeserver_cfg = Some(HomeserverConfig::Url(url)); - Arc::new(builder) +#[derive(Clone)] +enum ClientSessionConfig { + /// Setup the client to use the SQLite store. + #[cfg(any(not(target_family = "wasm"), feature = "cross-platform-api"))] + #[cfg_attr(target_family = "wasm", allow(unused))] + Sqlite(SqliteSessionBuilder), + + /// Setup the client to use the IndexedDB store. + #[cfg(any(target_family = "wasm", feature = "cross-platform-api"))] + #[cfg_attr(not(target_family = "wasm"), allow(unused))] + IndexedDb(IndexedDbSessionBuilder), +} + +#[derive(Clone, uniffi::Object)] +pub struct ClientBuilder { + session: Option, + username: Option, + homeserver_cfg: Option, + /// Ignored on wasm32 + user_agent: Option, + sliding_sync_version_builder: SlidingSyncVersionBuilder, + /// Ignored on wasm32 + proxy: Option, + /// Ignored on wasm32 + disable_ssl_verification: bool, + disable_automatic_token_refresh: bool, + cross_process_store_locks_holder_name: Option, + enable_oidc_refresh_lock: bool, + session_delegate: Option>, + /// Ignored on wasm32 + additional_root_certificates: Vec>, + /// Ignored on wasm32 + disable_built_in_root_certificates: bool, + encryption_settings: EncryptionSettings, + room_key_recipient_strategy: CollectStrategy, + decryption_trust_requirement: TrustRequirement, + enable_share_history_on_invite: bool, + request_config: Option, +} + +#[matrix_sdk_ffi_macros::export] +impl ClientBuilder { + #[uniffi::constructor] + pub fn new() -> Arc { + Arc::new(Self { + session: None, + username: None, + homeserver_cfg: None, + user_agent: None, + sliding_sync_version_builder: SlidingSyncVersionBuilder::None, + proxy: None, + disable_ssl_verification: false, + disable_automatic_token_refresh: false, + cross_process_store_locks_holder_name: None, + enable_oidc_refresh_lock: false, + session_delegate: None, + additional_root_certificates: Default::default(), + disable_built_in_root_certificates: false, + encryption_settings: EncryptionSettings { + auto_enable_cross_signing: false, + backup_download_strategy: + matrix_sdk::encryption::BackupDownloadStrategy::AfterDecryptionFailure, + auto_enable_backups: false, + }, + room_key_recipient_strategy: Default::default(), + decryption_trust_requirement: TrustRequirement::Untrusted, + enable_share_history_on_invite: false, + request_config: Default::default(), + }) } - pub fn server_name_or_homeserver_url(self: Arc, server_name_or_url: String) -> Arc { + pub fn cross_process_store_locks_holder_name( + self: Arc, + holder_name: String, + ) -> Arc { let mut builder = unwrap_or_clone_arc(self); - builder.homeserver_cfg = Some(HomeserverConfig::ServerNameOrUrl(server_name_or_url)); + builder.cross_process_store_locks_holder_name = Some(holder_name); Arc::new(builder) } - pub fn user_agent(self: Arc, user_agent: String) -> Arc { + pub fn enable_oidc_refresh_lock(self: Arc) -> Arc { let mut builder = unwrap_or_clone_arc(self); - builder.user_agent = Some(user_agent); + builder.enable_oidc_refresh_lock = true; Arc::new(builder) } - pub fn sliding_sync_version_builder( + pub fn set_session_delegate( self: Arc, - version_builder: SlidingSyncVersionBuilder, + session_delegate: Box, ) -> Arc { let mut builder = unwrap_or_clone_arc(self); - builder.sliding_sync_version_builder = version_builder; + builder.session_delegate = Some(session_delegate.into()); Arc::new(builder) } - pub fn proxy(self: Arc, url: String) -> Arc { + pub fn username(self: Arc, username: String) -> Arc { let mut builder = unwrap_or_clone_arc(self); - builder.proxy = Some(url); + builder.username = Some(username); Arc::new(builder) } - pub fn disable_ssl_verification(self: Arc) -> Arc { + pub fn server_name(self: Arc, server_name: String) -> Arc { let mut builder = unwrap_or_clone_arc(self); - builder.disable_ssl_verification = true; + builder.homeserver_cfg = Some(HomeserverConfig::ServerName(server_name)); Arc::new(builder) } - pub fn disable_automatic_token_refresh(self: Arc) -> Arc { + pub fn homeserver_url(self: Arc, url: String) -> Arc { let mut builder = unwrap_or_clone_arc(self); - builder.disable_automatic_token_refresh = true; + builder.homeserver_cfg = Some(HomeserverConfig::Url(url)); Arc::new(builder) } - pub fn add_root_certificates( + pub fn server_name_or_homeserver_url(self: Arc, server_name_or_url: String) -> Arc { + let mut builder = unwrap_or_clone_arc(self); + builder.homeserver_cfg = Some(HomeserverConfig::ServerNameOrUrl(server_name_or_url)); + Arc::new(builder) + } + + pub fn sliding_sync_version_builder( self: Arc, - certificates: Vec, + version_builder: SlidingSyncVersionBuilder, ) -> Arc { let mut builder = unwrap_or_clone_arc(self); - builder.additional_root_certificates = certificates; - + builder.sliding_sync_version_builder = version_builder; Arc::new(builder) } - /// Don't trust any system root certificates, only trust the certificates - /// provided through - /// [`add_root_certificates`][ClientBuilder::add_root_certificates]. - pub fn disable_built_in_root_certificates(self: Arc) -> Arc { + pub fn disable_automatic_token_refresh(self: Arc) -> Arc { let mut builder = unwrap_or_clone_arc(self); - builder.disable_built_in_root_certificates = true; + builder.disable_automatic_token_refresh = true; Arc::new(builder) } @@ -583,50 +610,69 @@ impl ClientBuilder { inner_builder.cross_process_store_locks_holder_name(holder_name.clone()); } - let store_path = if let Some(session_paths) = &builder.session_paths { - // This is the path where both the state store and the crypto store will live. - let data_path = Path::new(&session_paths.data_path); - // This is the path where the event cache store will live. - let cache_path = Path::new(&session_paths.cache_path); - - debug!( - data_path = %data_path.to_string_lossy(), - event_cache_path = %cache_path.to_string_lossy(), - "Creating directories for data (state and crypto) and cache stores.", - ); - - fs::create_dir_all(data_path)?; - fs::create_dir_all(cache_path)?; + let mut store_path = None; + match builder.session { + #[cfg(all(target_family = "wasm", feature = "cross-platform-api"))] + Some(ClientSessionConfig::Sqlite(_)) => { + panic!("SQLite session config is not supported on wasm32."); + } + #[cfg(not(target_family = "wasm"))] + Some(ClientSessionConfig::Sqlite(config)) => { + if let Some(session_paths) = config.paths { + let data_path = Path::new(&session_paths.data_path); + let cache_path = Path::new(&session_paths.cache_path); + + debug!( + data_path = %data_path.to_string_lossy(), + cache_path = %cache_path.to_string_lossy(), + "Creating directories for data and cache stores.", + ); + + fs::create_dir_all(data_path)?; + fs::create_dir_all(cache_path)?; + + let mut sqlite_store_config = if config.system_is_memory_constrained { + SqliteStoreConfig::with_low_memory_config(data_path) + } else { + SqliteStoreConfig::new(data_path) + }; + + sqlite_store_config = + sqlite_store_config.passphrase(config.passphrase.as_deref()); + + if let Some(size) = config.pool_max_size { + sqlite_store_config = sqlite_store_config.pool_max_size(size); + } - let mut sqlite_store_config = if builder.system_is_memory_constrained { - SqliteStoreConfig::with_low_memory_config(data_path) - } else { - SqliteStoreConfig::new(data_path) - }; + if let Some(size) = config.cache_size { + sqlite_store_config = sqlite_store_config.cache_size(size); + } - sqlite_store_config = - sqlite_store_config.passphrase(builder.session_passphrase.as_deref()); + if let Some(limit) = config.journal_size_limit { + sqlite_store_config = sqlite_store_config.journal_size_limit(limit); + } - if let Some(size) = builder.session_pool_max_size { - sqlite_store_config = sqlite_store_config.pool_max_size(size); + inner_builder = inner_builder.sqlite_store_with_config_and_cache_path( + sqlite_store_config, + Some(cache_path), + ); + store_path = Some(data_path.to_owned()) + } else { + debug!("Not using a store path."); + } } - - if let Some(size) = builder.session_cache_size { - sqlite_store_config = sqlite_store_config.cache_size(size); + #[cfg(all(not(target_family = "wasm"), feature = "cross-platform-api"))] + Some(ClientSessionConfig::IndexedDb(_)) => { + panic!("IndexedDB session config is not supported outside of wasm32."); } - if let Some(limit) = builder.session_journal_size_limit { - sqlite_store_config = sqlite_store_config.journal_size_limit(limit); + #[cfg(target_family = "wasm")] + Some(ClientSessionConfig::IndexedDb(config)) => { + inner_builder = + inner_builder.indexeddb_store(&config.name, config.passphrase.as_deref()); } - - inner_builder = inner_builder - .sqlite_store_with_config_and_cache_path(sqlite_store_config, Some(cache_path)); - - Some(data_path.to_owned()) - } else { - debug!("Not using a store path."); - None - }; + None => debug!("Not using a session store."), + } // Determine server either from URL, server name or user ID. inner_builder = match builder.homeserver_cfg { @@ -650,48 +696,59 @@ impl ClientBuilder { } }; - let mut certificates = Vec::new(); + #[cfg(not(target_family = "wasm"))] + { + let mut certificates = Vec::new(); - for certificate in builder.additional_root_certificates { - // We don't really know what type of certificate we may get here, so let's try - // first one type, then the other. - match Certificate::from_der(&certificate) { - Ok(cert) => { - certificates.push(cert); - } - Err(der_error) => { - let cert = Certificate::from_pem(&certificate).map_err(|pem_error| { + for certificate in builder.additional_root_certificates { + // We don't really know what type of certificate we may get here, so let's try + // first one type, then the other. + match Certificate::from_der(&certificate) { + Ok(cert) => { + certificates.push(cert); + } + Err(der_error) => { + let cert = Certificate::from_pem(&certificate).map_err(|pem_error| { ClientBuildError::Generic { message: format!("Failed to add a root certificate as DER ({der_error:?}) or PEM ({pem_error:?})"), } })?; - certificates.push(cert); + certificates.push(cert); + } } } - } - - inner_builder = inner_builder.add_root_certificates(certificates); - - if builder.disable_built_in_root_certificates { - inner_builder = inner_builder.disable_built_in_root_certificates(); - } - if let Some(proxy) = builder.proxy { - inner_builder = inner_builder.proxy(proxy); - } + inner_builder = inner_builder.add_root_certificates(certificates); + if builder.disable_built_in_root_certificates { + inner_builder = inner_builder.disable_built_in_root_certificates(); + } + if let Some(proxy) = builder.proxy { + let Ok(proxy) = Proxy::all(proxy) else { + return Err(ClientBuildError::Generic { + message: "Proxy configuration is invalid.".to_owned(), + }); + }; + let Ok(http_client) = matrix_sdk::reqwest::Client::builder().proxy(proxy).build() + else { + return Err(ClientBuildError::Generic { + message: "Http client for proxy is invalid.".to_owned(), + }); + }; + inner_builder = inner_builder.http_client(http_client); + } + if builder.disable_ssl_verification { + inner_builder = inner_builder.disable_ssl_verification(); + } - if builder.disable_ssl_verification { - inner_builder = inner_builder.disable_ssl_verification(); + if let Some(user_agent) = builder.user_agent { + inner_builder = inner_builder.user_agent(user_agent); + } } if !builder.disable_automatic_token_refresh { inner_builder = inner_builder.handle_refresh_tokens(); } - if let Some(user_agent) = builder.user_agent { - inner_builder = inner_builder.user_agent(user_agent); - } - inner_builder = inner_builder .with_encryption_settings(builder.encryption_settings) .with_room_key_recipient_strategy(builder.room_key_recipient_strategy) @@ -804,6 +861,100 @@ impl ClientBuilder { } } +#[cfg(any(not(target_family = "wasm"), feature = "cross-platform-api"))] +#[matrix_sdk_ffi_macros::export] +impl ClientBuilder { + #[cfg_attr(target_family = "wasm", allow(unused))] + pub fn session_sqlite(self: Arc, config: Arc) -> Arc { + #[cfg(target_family = "wasm")] + { + panic!("SQLite session config is not supported on wasm32."); + } + #[cfg(not(target_family = "wasm"))] + { + let mut builder = unwrap_or_clone_arc(self); + builder.session = Some(ClientSessionConfig::Sqlite(config.as_ref().clone())); + Arc::new(builder) + } + } + + pub fn disable_ssl_verification(self: Arc) -> Arc { + #[cfg(target_family = "wasm")] + { + panic!("Not supported on wasm32."); + } + let mut builder = unwrap_or_clone_arc(self); + builder.disable_ssl_verification = true; + Arc::new(builder) + } + + pub fn add_root_certificates( + self: Arc, + certificates: Vec, + ) -> Arc { + #[cfg(target_family = "wasm")] + { + panic!("Not supported on wasm32."); + } + let mut builder = unwrap_or_clone_arc(self); + builder.additional_root_certificates = certificates; + + Arc::new(builder) + } + + /// Don't trust any system root certificates, only trust the certificates + /// provided through + /// [`add_root_certificates`][ClientBuilder::add_root_certificates]. + pub fn disable_built_in_root_certificates(self: Arc) -> Arc { + #[cfg(target_family = "wasm")] + { + panic!("Not supported on wasm32."); + } + + let mut builder = unwrap_or_clone_arc(self); + builder.disable_built_in_root_certificates = true; + Arc::new(builder) + } + + pub fn user_agent(self: Arc, user_agent: String) -> Arc { + #[cfg(target_family = "wasm")] + { + panic!("Not supported on wasm32."); + } + let mut builder = unwrap_or_clone_arc(self); + builder.user_agent = Some(user_agent); + Arc::new(builder) + } + + pub fn proxy(self: Arc, url: String) -> Arc { + #[cfg(target_family = "wasm")] + { + panic!("Not supported on wasm32."); + } + let mut builder = unwrap_or_clone_arc(self); + builder.proxy = Some(url); + Arc::new(builder) + } +} + +#[cfg(any(target_family = "wasm", feature = "cross-platform-api"))] +#[matrix_sdk_ffi_macros::export] +impl ClientBuilder { + #[cfg_attr(not(target_family = "wasm"), allow(unused))] + pub fn session_indexeddb(self: Arc, config: Arc) -> Arc { + #[cfg(not(target_family = "wasm"))] + { + panic!("IndexedDB session config is not supported outside of wasm32."); + } + #[cfg(target_family = "wasm")] + { + let mut builder = unwrap_or_clone_arc(self); + builder.session = Some(ClientSessionConfig::IndexedDb(config.as_ref().clone())); + Arc::new(builder) + } + } +} + /// The store paths the client will use when built. #[derive(Clone)] struct SessionPaths {