1- use std:: { fs , num:: NonZeroUsize , path :: Path , sync:: Arc , time:: Duration } ;
1+ use std:: { num:: NonZeroUsize , sync:: Arc , time:: Duration } ;
22
33#[ cfg( not( target_family = "wasm" ) ) ]
44use matrix_sdk:: reqwest:: Certificate ;
@@ -11,15 +11,21 @@ use matrix_sdk::{
1111 VersionBuilderError ,
1212 } ,
1313 Client as MatrixClient , ClientBuildError as MatrixClientBuildError , HttpError , IdParseError ,
14- RumaApiError , SqliteStoreConfig , ThreadingSupport ,
14+ RumaApiError , ThreadingSupport ,
1515} ;
1616use matrix_sdk_base:: crypto:: { CollectStrategy , DecryptionSettings , TrustRequirement } ;
1717use ruma:: api:: error:: { DeserializationError , FromHttpResponseError } ;
1818use tracing:: debug;
19- use zeroize:: Zeroizing ;
2019
2120use super :: client:: Client ;
22- use crate :: { client:: ClientSessionDelegate , error:: ClientError , helpers:: unwrap_or_clone_arc} ;
21+ #[ cfg( any( feature = "sqlite" , feature = "indexeddb" ) ) ]
22+ use crate :: session_store;
23+ use crate :: {
24+ client:: ClientSessionDelegate ,
25+ error:: ClientError ,
26+ helpers:: unwrap_or_clone_arc,
27+ session_store:: { SessionStoreBuilder , SessionStoreResult } ,
28+ } ;
2329
2430/// A list of bytes containing a certificate in DER or PEM form.
2531pub type CertificateBytes = Vec < u8 > ;
@@ -100,11 +106,7 @@ impl From<ClientError> for ClientBuildError {
100106
101107#[ derive( Clone , uniffi:: Object ) ]
102108pub struct ClientBuilder {
103- session_paths : Option < SessionPaths > ,
104- session_passphrase : Zeroizing < Option < String > > ,
105- session_pool_max_size : Option < usize > ,
106- session_cache_size : Option < u32 > ,
107- session_journal_size_limit : Option < u32 > ,
109+ session_store : Option < SessionStoreBuilder > ,
108110 system_is_memory_constrained : bool ,
109111 username : Option < String > ,
110112 homeserver_cfg : Option < HomeserverConfig > ,
@@ -143,11 +145,7 @@ impl ClientBuilder {
143145 #[ uniffi:: constructor]
144146 pub fn new ( ) -> Arc < Self > {
145147 Arc :: new ( Self {
146- session_paths : None ,
147- session_passphrase : Zeroizing :: new ( None ) ,
148- session_pool_max_size : None ,
149- session_cache_size : None ,
150- session_journal_size_limit : None ,
148+ session_store : None ,
151149 system_is_memory_constrained : false ,
152150 username : None ,
153151 homeserver_cfg : None ,
@@ -201,73 +199,6 @@ impl ClientBuilder {
201199 Arc :: new ( builder)
202200 }
203201
204- /// Sets the paths that the client will use to store its data and caches.
205- /// Both paths **must** be unique per session as the SDK stores aren't
206- /// capable of handling multiple users, however it is valid to use the
207- /// same path for both stores on a single session.
208- ///
209- /// Leaving this unset tells the client to use an in-memory data store.
210- pub fn session_paths ( self : Arc < Self > , data_path : String , cache_path : String ) -> Arc < Self > {
211- let mut builder = unwrap_or_clone_arc ( self ) ;
212- builder. session_paths = Some ( SessionPaths { data_path, cache_path } ) ;
213- Arc :: new ( builder)
214- }
215-
216- /// Set the passphrase for the stores given to
217- /// [`ClientBuilder::session_paths`].
218- pub fn session_passphrase ( self : Arc < Self > , passphrase : Option < String > ) -> Arc < Self > {
219- let mut builder = unwrap_or_clone_arc ( self ) ;
220- builder. session_passphrase = Zeroizing :: new ( passphrase) ;
221- Arc :: new ( builder)
222- }
223-
224- /// Set the pool max size for the SQLite stores given to
225- /// [`ClientBuilder::session_paths`].
226- ///
227- /// Each store exposes an async pool of connections. This method controls
228- /// the size of the pool. The larger the pool is, the more memory is
229- /// consumed, but also the more the app is reactive because it doesn't need
230- /// to wait on a pool to be available to run queries.
231- ///
232- /// See [`SqliteStoreConfig::pool_max_size`] to learn more.
233- pub fn session_pool_max_size ( self : Arc < Self > , pool_max_size : Option < u32 > ) -> Arc < Self > {
234- let mut builder = unwrap_or_clone_arc ( self ) ;
235- builder. session_pool_max_size = pool_max_size
236- . map ( |size| size. try_into ( ) . expect ( "`pool_max_size` is too large to fit in `usize`" ) ) ;
237- Arc :: new ( builder)
238- }
239-
240- /// Set the cache size for the SQLite stores given to
241- /// [`ClientBuilder::session_paths`].
242- ///
243- /// Each store exposes a SQLite connection. This method controls the cache
244- /// size, in **bytes (!)**.
245- ///
246- /// The cache represents data SQLite holds in memory at once per open
247- /// database file. The default cache implementation does not allocate the
248- /// full amount of cache memory all at once. Cache memory is allocated
249- /// in smaller chunks on an as-needed basis.
250- ///
251- /// See [`SqliteStoreConfig::cache_size`] to learn more.
252- pub fn session_cache_size ( self : Arc < Self > , cache_size : Option < u32 > ) -> Arc < Self > {
253- let mut builder = unwrap_or_clone_arc ( self ) ;
254- builder. session_cache_size = cache_size;
255- Arc :: new ( builder)
256- }
257-
258- /// Set the size limit for the SQLite WAL files of stores given to
259- /// [`ClientBuilder::session_paths`].
260- ///
261- /// Each store uses the WAL journal mode. This method controls the size
262- /// limit of the WAL files, in **bytes (!)**.
263- ///
264- /// See [`SqliteStoreConfig::journal_size_limit`] to learn more.
265- pub fn session_journal_size_limit ( self : Arc < Self > , limit : Option < u32 > ) -> Arc < Self > {
266- let mut builder = unwrap_or_clone_arc ( self ) ;
267- builder. session_journal_size_limit = limit;
268- Arc :: new ( builder)
269- }
270-
271202 /// Tell the client that the system is memory constrained, like in a push
272203 /// notification process for example.
273204 ///
@@ -404,6 +335,13 @@ impl ClientBuilder {
404335 Arc :: new ( builder)
405336 }
406337
338+ /// Use in-memory session storage.
339+ pub fn session_store_in_memory ( self : Arc < Self > ) -> Arc < Self > {
340+ let mut builder = unwrap_or_clone_arc ( self ) ;
341+ builder. session_store = Some ( SessionStoreBuilder :: InMemory ) ;
342+ Arc :: new ( builder)
343+ }
344+
407345 pub async fn build ( self : Arc < Self > ) -> Result < Arc < Client > , ClientBuildError > {
408346 let builder = unwrap_or_clone_arc ( self ) ;
409347 let mut inner_builder = MatrixClient :: builder ( ) ;
@@ -413,48 +351,26 @@ impl ClientBuilder {
413351 inner_builder. cross_process_store_locks_holder_name ( holder_name. clone ( ) ) ;
414352 }
415353
416- let store_path = if let Some ( session_paths) = & builder. session_paths {
417- // This is the path where both the state store and the crypto store will live.
418- let data_path = Path :: new ( & session_paths. data_path ) ;
419- // This is the path where the event cache store will live.
420- let cache_path = Path :: new ( & session_paths. cache_path ) ;
354+ let session_store_path = if let Some ( session_store) = & builder. session_store {
355+ match session_store. build ( ) ? {
356+ #[ cfg( feature = "sqlite" ) ]
357+ SessionStoreResult :: Sqlite { config, cache_path, store_path : data_path } => {
358+ inner_builder = inner_builder
359+ . sqlite_store_with_config_and_cache_path ( config, Some ( cache_path) ) ;
421360
422- debug ! (
423- data_path = %data_path. to_string_lossy( ) ,
424- event_cache_path = %cache_path. to_string_lossy( ) ,
425- "Creating directories for data (state and crypto) and cache stores." ,
426- ) ;
427-
428- fs:: create_dir_all ( data_path) ?;
429- fs:: create_dir_all ( cache_path) ?;
430-
431- let mut sqlite_store_config = if builder. system_is_memory_constrained {
432- SqliteStoreConfig :: with_low_memory_config ( data_path)
433- } else {
434- SqliteStoreConfig :: new ( data_path)
435- } ;
436-
437- sqlite_store_config =
438- sqlite_store_config. passphrase ( builder. session_passphrase . as_deref ( ) ) ;
439-
440- if let Some ( size) = builder. session_pool_max_size {
441- sqlite_store_config = sqlite_store_config. pool_max_size ( size) ;
442- }
361+ Some ( data_path)
362+ }
363+ #[ cfg( feature = "indexeddb" ) ]
364+ SessionStoreResult :: IndexedDb { name, passphrase } => {
365+ inner_builder = inner_builder. indexeddb_store ( & name, passphrase. as_deref ( ) ) ;
443366
444- if let Some ( size) = builder. session_cache_size {
445- sqlite_store_config = sqlite_store_config. cache_size ( size) ;
446- }
367+ None
368+ }
447369
448- if let Some ( limit) = builder. session_journal_size_limit {
449- sqlite_store_config = sqlite_store_config. journal_size_limit ( limit) ;
370+ SessionStoreResult :: InMemory => None ,
450371 }
451-
452- inner_builder = inner_builder
453- . sqlite_store_with_config_and_cache_path ( sqlite_store_config, Some ( cache_path) ) ;
454-
455- Some ( data_path. to_owned ( ) )
456372 } else {
457- debug ! ( "Not using a store path. " ) ;
373+ debug ! ( "Not using a session store " ) ;
458374 None
459375 } ;
460376
@@ -594,13 +510,41 @@ impl ClientBuilder {
594510 sdk_client,
595511 builder. enable_oidc_refresh_lock ,
596512 builder. session_delegate ,
597- store_path ,
513+ session_store_path ,
598514 )
599515 . await ?,
600516 ) )
601517 }
602518}
603519
520+ #[ cfg( feature = "sqlite" ) ]
521+ #[ matrix_sdk_ffi_macros:: export]
522+ impl ClientBuilder {
523+ /// Use SQLite as the session storage.
524+ pub fn session_store_with_sqlite (
525+ self : Arc < Self > ,
526+ config : Arc < session_store:: SqliteSessionStoreBuilder > ,
527+ ) -> Arc < Self > {
528+ let mut builder = unwrap_or_clone_arc ( self ) ;
529+ builder. session_store = Some ( SessionStoreBuilder :: Sqlite ( unwrap_or_clone_arc ( config) ) ) ;
530+ Arc :: new ( builder)
531+ }
532+ }
533+
534+ #[ cfg( feature = "indexeddb" ) ]
535+ #[ matrix_sdk_ffi_macros:: export]
536+ impl ClientBuilder {
537+ /// Use IndexedDB as the session storage.
538+ pub fn session_store_with_indexeddb (
539+ self : Arc < Self > ,
540+ config : Arc < session_store:: IndexedDbSessionStoreBuilder > ,
541+ ) -> Arc < Self > {
542+ let mut builder = unwrap_or_clone_arc ( self ) ;
543+ builder. session_store = Some ( SessionStoreBuilder :: IndexedDb ( unwrap_or_clone_arc ( config) ) ) ;
544+ Arc :: new ( builder)
545+ }
546+ }
547+
604548#[ cfg( not( target_family = "wasm" ) ) ]
605549#[ matrix_sdk_ffi_macros:: export]
606550impl ClientBuilder {
@@ -642,18 +586,8 @@ impl ClientBuilder {
642586 }
643587}
644588
645- /// The store paths the client will use when built.
646- #[ derive( Clone ) ]
647- struct SessionPaths {
648- /// The path that the client will use to store its data.
649- data_path : String ,
650- /// The path that the client will use to store its caches. This path can be
651- /// the same as the data path if you prefer to keep everything in one place.
652- cache_path : String ,
653- }
654-
655- #[ derive( Clone , uniffi:: Record ) ]
656589/// The config to use for HTTP requests by default in this client.
590+ #[ derive( Clone , uniffi:: Record ) ]
657591pub struct RequestConfig {
658592 /// Max number of retries.
659593 retry_limit : Option < u64 > ,
0 commit comments