state_store: add initial_use to let client know its safe to load state

This commit is contained in:
Devin R 2020-04-23 21:57:54 -04:00
parent 183fffe85e
commit 316295bb77
4 changed files with 20 additions and 5 deletions

View file

@ -610,7 +610,9 @@ impl AsyncClient {
#[instrument]
pub async fn sync(&self, mut sync_settings: SyncSettings) -> Result<sync_events::Response> {
{
if self.base_client.read().await.is_state_store_synced() {
// if the client hasn't been synced from the state store don't sync again
if !self.base_client.read().await.is_state_store_synced() {
// this will bail out returning false if the store has not been set up
if let Ok(synced) = self.sync_with_state_store().await {
if synced {
// once synced, update the sync token to the last known state from `StateStore`.

View file

@ -148,6 +148,11 @@ impl Client {
/// Returns `true` when a sync has successfully completed.
pub(crate) async fn sync_with_state_store(&mut self) -> Result<bool> {
if let Some(store) = self.state_store.as_ref() {
// return false and continues with a sync request then saves the state and creates
// and populates the files during the sync
if !store.initial_use().await? {
return Ok(false);
}
let ClientState {
session,
sync_token,

View file

@ -60,6 +60,10 @@ impl ClientState {
/// Abstraction around the data store to avoid unnecessary request on client initialization.
#[async_trait::async_trait]
pub trait StateStore: Send + Sync {
/// Signals to the `AsyncClient` if this is the first time a StateStore` has been used.
///
/// Returns true if `StateStore` has been set up and ready to be loaded from.
async fn initial_use(&self) -> Result<bool>;
/// Loads the state of `BaseClient` through `StateStore::Store` type.
async fn load_client_state(&self) -> Result<ClientState>;
/// Load the state of a single `Room` by `RoomId`.

View file

@ -29,6 +29,12 @@ impl JsonStore {
#[async_trait::async_trait]
impl StateStore for JsonStore {
async fn initial_use(&self) -> Result<bool> {
let mut path = self.path.clone();
path.push("client.json");
Ok(fs::read_to_string(path).map_or(false, |s| !s.is_empty()))
}
async fn load_client_state(&self) -> Result<ClientState> {
let mut path = self.path.clone();
path.push("client.json");
@ -242,10 +248,8 @@ mod test {
AsyncClient::new_with_config(homeserver.clone(), Some(session.clone()), config)
.unwrap();
let sync_settings = SyncSettings::new().timeout(std::time::Duration::from_millis(3000));
// fake a sync to skip the load with the state store, this will fail as the files won't exist
// but the `AsyncClient::sync` will skip `StateStore::load_*`
assert!(client.sync_with_state_store().await.is_err());
// gather state to save to the db
// gather state to save to the db, the first time through loading will be skipped
let _ = client.sync(sync_settings.clone()).await.unwrap();
// now syncing the client will update from the state store