code_mesh_core/storage/
mod.rs

1//! Storage abstractions for Code Mesh
2
3use async_trait::async_trait;
4use std::path::PathBuf;
5
6mod file;
7
8/// Storage trait for persistent data
9#[async_trait]
10pub trait Storage: Send + Sync {
11    /// Store a value with a key
12    async fn set(&self, key: &str, value: &[u8]) -> Result<(), StorageError>;
13    
14    /// Retrieve a value by key
15    async fn get(&self, key: &str) -> Result<Option<Vec<u8>>, StorageError>;
16    
17    /// Delete a value by key
18    async fn delete(&self, key: &str) -> Result<(), StorageError>;
19    
20    /// List all keys with optional prefix
21    async fn list(&self, prefix: Option<&str>) -> Result<Vec<String>, StorageError>;
22    
23    /// Check if a key exists
24    async fn exists(&self, key: &str) -> Result<bool, StorageError>;
25}
26
27/// Storage errors
28#[derive(Debug, thiserror::Error)]
29pub enum StorageError {
30    #[error("IO error: {0}")]
31    Io(#[from] std::io::Error),
32    
33    #[error("Serialization error: {0}")]
34    Serialization(#[from] serde_json::Error),
35    
36    #[error("Key not found: {0}")]
37    KeyNotFound(String),
38    
39    #[error("Storage error: {0}")]
40    Other(String),
41}
42
43/// File-based storage implementation
44pub struct FileStorage {
45    base_path: PathBuf,
46}
47
48impl FileStorage {
49    pub fn new(base_path: PathBuf) -> Self {
50        Self { base_path }
51    }
52    
53    pub fn default() -> Result<Self, StorageError> {
54        let data_dir = dirs::data_dir()
55            .ok_or_else(|| StorageError::Other("Could not find data directory".to_string()))?;
56        let base_path = data_dir.join("code-mesh").join("storage");
57        Ok(Self::new(base_path))
58    }
59    
60    fn key_to_path(&self, key: &str) -> PathBuf {
61        // Sanitize key to prevent path traversal
62        let safe_key = key.replace(['/', '\\'], "_").replace("..", "_");
63        self.base_path.join(safe_key)
64    }
65}