use async_trait::async_trait;
use std::path::PathBuf;
mod file;
#[async_trait]
pub trait Storage: Send + Sync {
async fn set(&self, key: &str, value: &[u8]) -> Result<(), StorageError>;
async fn get(&self, key: &str) -> Result<Option<Vec<u8>>, StorageError>;
async fn delete(&self, key: &str) -> Result<(), StorageError>;
async fn list(&self, prefix: Option<&str>) -> Result<Vec<String>, StorageError>;
async fn exists(&self, key: &str) -> Result<bool, StorageError>;
}
#[derive(Debug, thiserror::Error)]
pub enum StorageError {
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Serialization error: {0}")]
Serialization(#[from] serde_json::Error),
#[error("Key not found: {0}")]
KeyNotFound(String),
#[error("Storage error: {0}")]
Other(String),
}
pub struct FileStorage {
base_path: PathBuf,
}
impl FileStorage {
pub fn new(base_path: PathBuf) -> Self {
Self { base_path }
}
pub fn default() -> Result<Self, StorageError> {
let data_dir = dirs::data_dir()
.ok_or_else(|| StorageError::Other("Could not find data directory".to_string()))?;
let base_path = data_dir.join("code-mesh").join("storage");
Ok(Self::new(base_path))
}
fn key_to_path(&self, key: &str) -> PathBuf {
let safe_key = key.replace(['/', '\\'], "_").replace("..", "_");
self.base_path.join(safe_key)
}
}