Skip to content

Commit

Permalink
Ensure prevent sync pattern is applied on startup
Browse files Browse the repository at this point in the history
Closes #7779, Closes #7780
  • Loading branch information
FirelightFlagboy committed Jul 31, 2024
1 parent 39ef448 commit 3baa014
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 1 deletion.
10 changes: 9 additions & 1 deletion libparsec/crates/client/src/workspace/store/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod file_updater;
mod folder_updater;
mod manifest_access;
mod per_manifest_update_lock;
mod prevent_sync_pattern;
mod reparent_updater;
mod resolve_path;
mod sync_updater;
Expand Down Expand Up @@ -172,7 +173,14 @@ impl WorkspaceStore {
}
};

// 3) All set !
// 3) Ensure the prevent sync pattern is applied to the workspace
prevent_sync_pattern::ensure_prevent_sync_pattern_applied_to_wksp(
&mut storage,
device.clone(),
)
.await?;

// 4) All set !

Ok(Self {
realm_id,
Expand Down
118 changes: 118 additions & 0 deletions libparsec/crates/client/src/workspace/store/prevent_sync_pattern.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS
use std::sync::Arc;

use libparsec_platform_storage::workspace::{UpdateManifestData, WorkspaceStorage};
use libparsec_types::{
prelude::{anyhow, thiserror},
DataError, LocalDevice, LocalFolderManifest, LocalWorkspaceManifest, SecretKey,
};

#[derive(Debug, thiserror::Error)]
pub enum ApplyPreventSyncPatternError {
#[error("Decryption error")]
DecryptionError,
#[error(transparent)]
Internal(anyhow::Error),
}

pub(super) async fn ensure_prevent_sync_pattern_applied_to_wksp(
storage: &mut WorkspaceStorage,
device: Arc<LocalDevice>,
) -> Result<(), ApplyPreventSyncPatternError> {
const PAGE_SIZE: u32 = 1000;

let (pattern, fully_applied) = storage
.get_prevent_sync_pattern()
.await
.map_err(ApplyPreventSyncPatternError::Internal)?;

if fully_applied {
return Ok(());
}

let mut offset = 0;
loop {
let manifests = storage
.list_manifests(offset, PAGE_SIZE)
.await
.map_err(ApplyPreventSyncPatternError::Internal)?;

let mut updated_manifest = Vec::with_capacity(manifests.len());
for encoded_manifest in &manifests {
if let Some(folder) = decode_folder(encoded_manifest, &device.local_symkey)? {
let new_folder =
folder.apply_prevent_sync_pattern(Some(&pattern), device.time_provider.now());
// TODO: Is it ok to just check the updated field (DateTime) to see if the manifest has changed,
// or better to do a full eq ?
if new_folder.updated != folder.updated {
updated_manifest.push(UpdateManifestData {
entry_id: new_folder.base.id,
encrypted: new_folder.dump_and_encrypt(&device.local_symkey),
need_sync: new_folder.need_sync,
base_version: new_folder.base.version,
})
}
} else if let Some(workspace) =
decode_workspace(encoded_manifest, &device.local_symkey)?
{
let new_workspace = LocalWorkspaceManifest(
workspace
.apply_prevent_sync_pattern(Some(&pattern), device.time_provider.now()),
);
// TODO: Is it ok to just check the updated field (DateTime) to see if the manifest has changed,
// or better to do a full eq ?
if new_workspace.updated != workspace.updated {
updated_manifest.push(UpdateManifestData {
entry_id: new_workspace.base.id,
encrypted: new_workspace.dump_and_encrypt(&device.local_symkey),
need_sync: new_workspace.need_sync,
base_version: new_workspace.base.version,
})
}
}
}

storage
.update_manifests(updated_manifest.into_iter())
.await
.map_err(ApplyPreventSyncPatternError::Internal)?;

// The manifests list is not filled to the page size,
// We consider that another call will result in an empty list, so we can stop here.
if manifests.len() < PAGE_SIZE as usize {
break;
}
offset += PAGE_SIZE;
}
storage
.mark_prevent_sync_pattern_fully_applied(&pattern)
.await
.map_err(ApplyPreventSyncPatternError::Internal)?;
Ok(())
}

fn decode_folder(
encoded: &[u8],
symkey: &SecretKey,
) -> Result<Option<LocalFolderManifest>, ApplyPreventSyncPatternError> {
match LocalFolderManifest::decrypt_and_load(encoded, symkey) {
Ok(manifest) => Ok(Some(manifest)),
Err(DataError::Decryption) => Err(ApplyPreventSyncPatternError::DecryptionError),
// We consider that BadSerialization indicate that the manifest is not of folder type.
Err(DataError::BadSerialization { .. }) => Ok(None),
Err(e) => Err(ApplyPreventSyncPatternError::Internal(e.into())),
}
}

fn decode_workspace(
encoded: &[u8],
symkey: &SecretKey,
) -> Result<Option<LocalWorkspaceManifest>, ApplyPreventSyncPatternError> {
match LocalWorkspaceManifest::decrypt_and_load(encoded, symkey) {
Ok(manifest) => Ok(Some(manifest)),
Err(DataError::Decryption) => Err(ApplyPreventSyncPatternError::DecryptionError),
// We consider that BadSerialization indicate that the manifest is not of workspace type.
Err(DataError::BadSerialization { .. }) => Ok(None),
Err(e) => Err(ApplyPreventSyncPatternError::Internal(e.into())),
}
}

0 comments on commit 3baa014

Please sign in to comment.