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 Aug 6, 2024
1 parent 41758ce commit 718d013
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 2 deletions.
4 changes: 4 additions & 0 deletions libparsec/crates/client/src/workspace/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use std::{

use libparsec_client_connection::AuthenticatedCmds;
use libparsec_platform_async::lock::Mutex as AsyncMutex;
use libparsec_platform_storage::PREVENT_SYNC_PATTERN_EMPTY_PATTERN;
use libparsec_types::prelude::*;

use crate::{certif::CertificateOps, event_bus::EventBus, ClientConfig};
Expand Down Expand Up @@ -149,6 +150,9 @@ impl WorkspaceOps {
certificates_ops.clone(),
config.workspace_storage_cache_size.cache_size(),
realm_id,
// TODO: https://github.com/Scille/parsec-cloud/issues/7828
// Use pattern provided by config
&Regex::from_regex_str(PREVENT_SYNC_PATTERN_EMPTY_PATTERN)?,
)
.await?;

Expand Down
12 changes: 11 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 @@ -128,6 +129,7 @@ impl WorkspaceStore {
certificates_ops: Arc<CertificateOps>,
cache_size: u64,
realm_id: VlobID,
pattern: &Regex,
) -> Result<Self, anyhow::Error> {
// 1) Open the database

Expand Down Expand Up @@ -172,7 +174,15 @@ 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(),
pattern,
)
.await?;

// 4) All set !

Ok(Self {
realm_id,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// 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::*;

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

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

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

if fully_applied {
return Ok(());
}

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

for encoded_manifest in &manifests {
// Only the prevent sync pattern could be applied to a folder type manifest.
// We assume that workspace manifest and folder manifest could both be deserialize as folder manifest.
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());
if new_folder != folder {
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,
})
}
}
}

storage
.update_manifests(updated_manifest.drain(..))
.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;
}
updated_manifest.clear();
offset += PAGE_SIZE;
}
storage
.mark_prevent_sync_pattern_fully_applied(pattern)
.await
.map_err(|e| ApplyPreventSyncPatternError::Internal(e.into()))?;
Ok(())
}

fn decode_folder(
encoded: &[u8],
symkey: &SecretKey,
) -> Result<Option<LocalFolderManifest>, ApplyPreventSyncPatternError> {
match LocalFolderManifest::decrypt_and_load(encoded, symkey) {
Ok(manifest) => Ok(Some(manifest)),
// We consider that BadSerialization indicate that the manifest is not of folder type.
Err(DataError::BadSerialization { .. }) => Ok(None),
Err(e) => Err(ApplyPreventSyncPatternError::Internal(anyhow::anyhow!(
"Local database contains invalid data: {e}"
))),
}
}
2 changes: 1 addition & 1 deletion libparsec/crates/platform_storage/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ pub mod workspace;
mod testbed;

/// Do not match anything (https://stackoverflow.com/a/2302992/2846140)
const PREVENT_SYNC_PATTERN_EMPTY_PATTERN: &str = r"^\b$";
pub const PREVENT_SYNC_PATTERN_EMPTY_PATTERN: &str = r"^\b$";
1 change: 1 addition & 0 deletions libparsec/crates/types/src/local_manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,7 @@ impl_transparent_data_format_conversion!(
);

impl_local_manifest_dump!(LocalFolderManifest);
impl_local_manifest_load!(LocalFolderManifest);

impl LocalFolderManifest {
pub fn new(author: DeviceID, parent: VlobID, timestamp: DateTime) -> Self {
Expand Down

0 comments on commit 718d013

Please sign in to comment.