From 045ab25fb779ca172ef08c128345a66aae268cbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Tue, 20 Oct 2020 09:04:24 +0200 Subject: [PATCH] base: Add initial state store based on sled. --- matrix_sdk_base/Cargo.toml | 2 +- matrix_sdk_base/src/client.rs | 8 +-- matrix_sdk_base/src/lib.rs | 4 +- matrix_sdk_base/src/store.rs | 103 ++++++++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+), 7 deletions(-) create mode 100644 matrix_sdk_base/src/store.rs diff --git a/matrix_sdk_base/Cargo.toml b/matrix_sdk_base/Cargo.toml index 720adf17..5594c7aa 100644 --- a/matrix_sdk_base/Cargo.toml +++ b/matrix_sdk_base/Cargo.toml @@ -15,7 +15,7 @@ features = ["docs"] rustdoc-args = ["--cfg", "feature=\"docs\""] [features] -default = ["encryption", "sqlite_cryptostore", "messages"] +default = [] messages = [] encryption = ["matrix-sdk-crypto"] sqlite_cryptostore = ["matrix-sdk-crypto/sqlite_cryptostore"] diff --git a/matrix_sdk_base/src/client.rs b/matrix_sdk_base/src/client.rs index 3d39e7b8..47b12814 100644 --- a/matrix_sdk_base/src/client.rs +++ b/matrix_sdk_base/src/client.rs @@ -20,8 +20,6 @@ use std::{ sync::Arc, }; -use sled::{self, Config as SledConfig, Db as Sled}; - #[cfg(feature = "encryption")] use matrix_sdk_common::locks::Mutex; use matrix_sdk_common::{ @@ -49,7 +47,7 @@ use matrix_sdk_crypto::{ }; use zeroize::Zeroizing; -use crate::{error::Result, session::Session}; +use crate::{error::Result, session::Session, store::Store}; pub type Token = String; @@ -170,7 +168,7 @@ pub struct BaseClient { /// The current sync token that should be used for the next sync call. pub(crate) sync_token: Arc>>, /// Database - sled: Sled, + store: Store, #[cfg(feature = "encryption")] olm: Arc>>, #[cfg(feature = "encryption")] @@ -276,7 +274,7 @@ impl BaseClient { Ok(BaseClient { session: Arc::new(RwLock::new(None)), sync_token: Arc::new(RwLock::new(None)), - sled: SledConfig::new().temporary(true).open().unwrap(), + store: Store::open(), #[cfg(feature = "encryption")] olm: Arc::new(Mutex::new(None)), #[cfg(feature = "encryption")] diff --git a/matrix_sdk_base/src/lib.rs b/matrix_sdk_base/src/lib.rs index 0efe5ded..b503c28b 100644 --- a/matrix_sdk_base/src/lib.rs +++ b/matrix_sdk_base/src/lib.rs @@ -28,7 +28,6 @@ //! of Synapse in compliance with the Matrix API specification. #![deny( missing_debug_implementations, - missing_docs, trivial_casts, trivial_numeric_casts, unused_extern_crates, @@ -46,6 +45,9 @@ pub use matrix_sdk_common::*; mod client; mod error; mod session; +mod store; + +pub use store::Store; pub use client::{BaseClient, BaseClientConfig, RoomState, RoomStateType}; diff --git a/matrix_sdk_base/src/store.rs b/matrix_sdk_base/src/store.rs new file mode 100644 index 00000000..b7164ed4 --- /dev/null +++ b/matrix_sdk_base/src/store.rs @@ -0,0 +1,103 @@ +use serde_json; + +use sled::{transaction::TransactionalTree, Config, Db, Tree}; + +#[derive(Debug, Clone)] +pub struct Store { + inner: Db, + session_tree: Tree, +} + +use crate::Session; + +pub struct TransactionalStore<'a> { + inner: &'a TransactionalTree, +} + +impl<'a> std::fmt::Debug for TransactionalStore<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("TransactionalStore").finish() + } +} + +impl<'a> TransactionalStore<'a> { + pub fn store_session(&self, session: &Session) { + self.inner + .insert("session", serde_json::to_vec(session).unwrap()) + .unwrap(); + } +} + +impl Store { + pub fn open() -> Self { + let db = Config::new().temporary(true).open().unwrap(); + let session_tree = db.open_tree("session").unwrap(); + + Self { + inner: db, + session_tree, + } + } + + pub fn get_session(&self) -> Option { + self.session_tree + .get("session") + .unwrap() + .map(|s| serde_json::from_slice(&s).unwrap()) + } + + pub async fn transaction(&self, callback: F) -> R + where + F: Fn(&TransactionalStore) -> R, + { + let ret = self + .session_tree + .transaction::<_, _, ()>(|t| { + let transaction = TransactionalStore { inner: t }; + Ok(callback(&transaction)) + }) + .unwrap(); + + self.inner.flush_async().await.unwrap(); + + ret + } +} + +#[cfg(test)] +mod test { + use matrix_sdk_common::identifiers::{user_id, DeviceIdBox, UserId}; + use matrix_sdk_test::async_test; + + use super::Store; + use crate::Session; + + fn user_id() -> UserId { + user_id!("@example:localhost") + } + + fn device_id() -> DeviceIdBox { + "DEVICEID".into() + } + + #[async_test] + async fn test_session_saving() { + let session = Session { + user_id: user_id(), + device_id: device_id().into(), + access_token: "TEST_TOKEN".to_owned(), + }; + + let store = Store::open(); + + store + .transaction(|t| { + t.store_session(&session); + () + }) + .await; + let stored_session = store.get_session().unwrap(); + + assert_eq!(session, stored_session); + } +}