use super::Content;
use crate::error::Error;
use crate::platform;
use crate::platform::ffi;
use std::path::Path;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::PoisonError;
pub struct LocalContentStore {
pub(crate) handle: ffi::CzLocalContentStore,
}
unsafe impl Send for LocalContentStore {}
unsafe impl Sync for LocalContentStore {}
impl LocalContentStore {
pub fn new(path: &Path) -> Result<Self, Error> {
let outcome = platform::outcome(
ffi::cz_local_content_store_new(&path.display().to_string()),
format!("open the content store at {}", path.display()),
)?;
Ok(Self {
handle: outcome.local_content_store(),
})
}
pub fn get(&self, digest: &str) -> Result<Option<Content>, Error> {
let handle = platform::outcome(self.handle.get(digest), format!("get {digest}"))?.content();
Ok(handle.is_some().then_some(Content { handle }))
}
pub fn delete(&self, digests: Vec<String>) -> Result<(Vec<String>, u64), Error> {
let outcome = platform::outcome(self.handle.delete_digests(digests), "delete content")?;
Ok((outcome.strings(), outcome.number()))
}
pub fn delete_keeping(&self, keeping: Vec<String>) -> Result<(Vec<String>, u64), Error> {
let outcome = platform::outcome(self.handle.delete_keeping(keeping), "delete content")?;
Ok((outcome.strings(), outcome.number()))
}
pub fn ingest(&self, body: impl FnOnce(&Path) -> Result<(), Error> + Send + 'static) -> Result<Vec<String>, Error> {
let failure = Arc::new(Mutex::new(None));
let slot = Arc::clone(&failure);
let outcome = self.handle.ingest(Box::new(move |directory: String| {
body(Path::new(&directory))
.map_err(|error| *slot.lock().unwrap_or_else(PoisonError::into_inner) = Some(error))
.is_ok()
}));
platform::outcome(outcome, "ingest content")
.map(|outcome| outcome.strings())
.map_err(|error| {
failure
.lock()
.unwrap_or_else(PoisonError::into_inner)
.take()
.unwrap_or(error)
})
}
pub fn total_allocated_size(&self) -> Result<u64, Error> {
platform::outcome(self.handle.total_allocated_size(), "size the content store").map(|outcome| outcome.number())
}
}