use crate::chunk::ChunkAddress;
use ant_protocol::storage::Chunk;
use bytes::Bytes;
use std::fs;
use std::path::PathBuf;
const CHUNK_CACHE_FOLDER: &str = "chunk_cache";
#[derive(Debug, thiserror::Error)]
pub enum ChunkCacheError {
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Failed to create cache directory: {0}")]
DirectoryCreation(String),
}
pub fn default_cache_dir() -> Result<PathBuf, ChunkCacheError> {
let mut cache_dir = dirs_next::data_dir().ok_or_else(|| {
ChunkCacheError::DirectoryCreation(
"Failed to obtain data dir, your OS might not be supported.".to_string(),
)
})?;
cache_dir.push("autonomi");
cache_dir.push("client");
cache_dir.push(CHUNK_CACHE_FOLDER);
Ok(cache_dir)
}
fn chunk_file_path(cache_dir: PathBuf, chunk_addr: &ChunkAddress) -> PathBuf {
let chunk_hash = hex::encode(chunk_addr.xorname().0);
cache_dir.join(format!("{chunk_hash}.chunk"))
}
pub fn is_chunk_cached(cache_dir: PathBuf, chunk_addr: &ChunkAddress) -> bool {
chunk_file_path(cache_dir, chunk_addr).exists()
}
pub fn store_chunk(
cache_dir: PathBuf,
chunk_addr: &ChunkAddress,
chunk: &Chunk,
) -> Result<(), ChunkCacheError> {
if !cache_dir.exists() {
fs::create_dir_all(&cache_dir).map_err(|e| {
ChunkCacheError::DirectoryCreation(format!(
"Failed to create cache directory {}: {}",
cache_dir.display(),
e
))
})?;
}
let chunk_file_path = chunk_file_path(cache_dir, chunk_addr);
fs::write(&chunk_file_path, chunk.value())?;
debug!(
"Cached chunk {} at {}",
chunk_addr.to_hex(),
chunk_file_path.display()
);
Ok(())
}
pub fn load_chunk(
cache_dir: PathBuf,
chunk_addr: &ChunkAddress,
) -> Result<Option<Chunk>, ChunkCacheError> {
let chunk_file_path = chunk_file_path(cache_dir, chunk_addr);
if !chunk_file_path.exists() {
return Ok(None);
}
match fs::read(&chunk_file_path) {
Ok(data) => {
let chunk = Chunk::new(Bytes::from(data));
debug!(
"Loaded cached chunk {} from {}",
chunk_addr.to_hex(),
chunk_file_path.display()
);
Ok(Some(chunk))
}
Err(e) => {
warn!("Failed to read cached chunk {}: {}", chunk_addr.to_hex(), e);
Ok(None)
}
}
}
pub fn delete_chunk(cache_dir: PathBuf, chunk_addr: &ChunkAddress) -> Result<(), ChunkCacheError> {
let chunk_file_path = chunk_file_path(cache_dir, chunk_addr);
if chunk_file_path.exists() {
fs::remove_file(&chunk_file_path)?;
debug!(
"Deleted cached chunk {} at {}",
chunk_addr.to_hex(),
chunk_file_path.display()
);
}
Ok(())
}
pub fn delete_chunks(
cache_dir: PathBuf,
chunk_addrs: &[ChunkAddress],
) -> Result<(), ChunkCacheError> {
for chunk_addr in chunk_addrs {
delete_chunk(cache_dir.clone(), chunk_addr)?;
}
Ok(())
}