//! Filesystem layout for zesdex's persistent and scratch data directories. //! //! # Flow //! //! [`Store::new`] resolves all paths from OS data dir / temp dir → //! [`ensure_dirs`](Store::ensure_dirs) creates them on startup. //! //! # Components //! //! - `Store` — resolved path bundle (base, memory, scratch, images, downloads) //! - `new` — path computation (no I/O) //! - `ensure_dirs` — creates all directories if missing use serde::{Deserialize, Serialize}; use std::path::PathBuf; use tracing; /// Resolved paths for all data directories zesdex reads from and writes to. /// /// Why: centralizing path computation here means every consumer agrees on /// where memory, scratch, session images, and downloads live. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Store { /// Top-level data directory, e.g. `~/.local/share/zesdex`. pub base_dir: PathBuf, /// Temporary scratch root, usually under the OS temp dir. pub scratch_root: PathBuf, /// Directory for persistent memory files (`.md` summaries). pub memory_dir: PathBuf, /// Directory for per-session image snapshots. pub session_images_dir: PathBuf, /// Directory for downloaded files. pub download_dir: PathBuf, } impl Store { /// Compute the standard set of zesdex data directory paths. /// /// Flow: OS data dir (or `.local/share` fallback) + "zesdex" → base dir; /// scratch root comes from the OS temp dir instead, since it's disposable. /// /// Why: paths are computed, not created — call `ensure_dirs` before use. pub fn new() -> Self { let base = if let Some(data_dir) = std::env::var("XDG_DATA_HOME").ok() .or_else(|| std::env::var("HOME").ok().map(|h| format!("{h}/.local/share"))) { PathBuf::from(data_dir).join("zesdex") } else { PathBuf::from(".local/share/zesdex") }; let scratch = std::env::temp_dir().join("zesdex-scratch"); Store { memory_dir: base.join("memory"), scratch_root: scratch, session_images_dir: base.join("session-images"), download_dir: base.join("downloads"), base_dir: base, } } /// Create all store directories (base, memory, scratch, session images, /// downloads) if missing. /// /// Return: `Err` on the first directory that fails to create. pub fn ensure_dirs(&self) -> std::io::Result<()> { tracing::debug!(base = %self.base_dir.display(), "ensuring store directories exist"); std::fs::create_dir_all(&self.base_dir)?; std::fs::create_dir_all(&self.memory_dir)?; std::fs::create_dir_all(&self.scratch_root)?; std::fs::create_dir_all(&self.session_images_dir)?; std::fs::create_dir_all(&self.download_dir)?; Ok(()) } } impl Default for Store { fn default() -> Self { Self::new() } }