DAV storage methods

This commit is contained in:
mdecimus
2025-03-06 18:35:46 +01:00
parent 3554dea4cb
commit eadd36f4cb
35 changed files with 1289 additions and 206 deletions

View File

@@ -8,10 +8,13 @@ resolver = "2"
utils = { path = "../utils" }
common = { path = "../common" }
jmap_proto = { path = "../jmap-proto" }
trc = { path = "../trc" }
directory = { path = "../directory" }
dav-proto = { path = "/Users/me/code/dav-proto" }
calcard = { path = "/Users/me/code/calcard" }
hashify = "0.2"
rkyv = { version = "0.8.10", features = ["little_endian"] }
percent-encoding = "2.3.1"
[features]
test_mode = []

View File

@@ -0,0 +1,72 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs Ltd <hello@stalw.art>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use std::sync::Arc;
use common::{Files, Server};
use jmap_proto::types::collection::Collection;
use percent_encoding::NON_ALPHANUMERIC;
use trc::AddContext;
use utils::bimap::IdBimap;
use crate::file::FileNode;
pub trait FileHierarchy: Sync + Send {
fn fetch_file_hierarchy(
&self,
account_id: u32,
) -> impl Future<Output = trc::Result<Arc<Files>>> + Send;
}
impl FileHierarchy for Server {
async fn fetch_file_hierarchy(&self, account_id: u32) -> trc::Result<Arc<Files>> {
let change_id = self
.store()
.get_last_change_id(account_id, Collection::FileNode)
.await
.caused_by(trc::location!())?;
if let Some(files) = self
.inner
.cache
.files
.get(&account_id)
.filter(|x| x.modseq == change_id)
{
Ok(files)
} else {
let mut files = build_file_hierarchy(self, account_id).await?;
files.modseq = change_id;
let files = Arc::new(files);
self.inner.cache.files.insert(account_id, files.clone());
Ok(files)
}
}
}
async fn build_file_hierarchy(server: &Server, account_id: u32) -> trc::Result<Files> {
let list = server
.fetch_folders::<FileNode>(account_id, Collection::FileNode)
.await
.caused_by(trc::location!())?
.format(|_, name| {
percent_encoding::utf8_percent_encode(name, NON_ALPHANUMERIC)
.to_string()
.into()
});
let mut files = Files {
files: IdBimap::with_capacity(list.len()),
size: std::mem::size_of::<Files>() as u64,
modseq: None,
};
for (id, name) in list.into_iterator() {
files.size +=
(std::mem::size_of::<u32>() + std::mem::size_of::<String>() + name.len()) as u64;
files.files.insert(id, name);
}
Ok(files)
}

View File

@@ -14,8 +14,13 @@ use super::{ArchivedFileNode, FileNode};
impl IndexableObject for FileNode {
fn index_values(&self) -> impl Iterator<Item = IndexValue<'_>> {
let mut filters = Vec::with_capacity(5);
filters.extend([
let size = self.dead_properties.size() as u32
+ self.display_name.as_ref().map_or(0, |n| n.len() as u32)
+ self.name.len() as u32;
let mut values = Vec::with_capacity(6);
values.extend([
IndexValue::Text {
field: Property::Name.into(),
value: self.name.to_lowercase().into(),
@@ -28,16 +33,22 @@ impl IndexableObject for FileNode {
]);
if let Some(file) = &self.file {
filters.extend([
let size = size + file.size;
values.extend([
IndexValue::Blob {
value: file.blob_hash.clone(),
},
IndexValue::U32 {
field: Property::Size.into(),
value: file.size.into(),
value: size.into(),
},
IndexValue::Quota { used: file.size },
IndexValue::Quota { used: size },
]);
} else {
values.push(IndexValue::Quota { used: size });
}
filters.into_iter()
values.into_iter()
}
}

View File

@@ -4,8 +4,10 @@
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
pub mod hierarchy;
pub mod index;
use dav_proto::schema::request::DeadProperty;
use jmap_proto::types::value::AclGrant;
use utils::BlobHash;
@@ -17,8 +19,10 @@ pub struct FileNode {
pub name: String,
pub display_name: Option<String>,
pub file: Option<FileProperties>,
pub created: u64,
pub modified: u64,
pub created: i64,
pub modified: i64,
pub change_id: u64,
pub dead_properties: DeadProperty,
pub acls: Vec<AclGrant>,
}