diff options
Diffstat (limited to 'makima/daemon/src/temp.rs')
| -rw-r--r-- | makima/daemon/src/temp.rs | 224 |
1 files changed, 0 insertions, 224 deletions
diff --git a/makima/daemon/src/temp.rs b/makima/daemon/src/temp.rs deleted file mode 100644 index 015b21b..0000000 --- a/makima/daemon/src/temp.rs +++ /dev/null @@ -1,224 +0,0 @@ -//! Managed temporary directory for tasks without repositories. -//! -//! Tasks that don't have a repository URL and aren't subtasks (which inherit -//! from parent) use a managed temp directory in ~/.makima/temp/. The directory -//! is automatically cleaned up when it exceeds a size limit. - -use std::path::PathBuf; - -use tokio::fs; -use uuid::Uuid; - -/// Maximum size of the temp directory before cleanup (5GB). -const MAX_TEMP_SIZE_BYTES: u64 = 5 * 1024 * 1024 * 1024; - -/// Manages temporary directories for tasks without repositories. -pub struct TempManager { - /// Base directory for temp task directories (~/.makima/temp/). - temp_dir: PathBuf, -} - -impl TempManager { - /// Create a new TempManager. - pub fn new() -> Self { - let home = dirs::home_dir().unwrap_or_else(|| PathBuf::from(".")); - Self { - temp_dir: home.join(".makima").join("temp"), - } - } - - /// Create a new TempManager with a custom base directory. - #[allow(dead_code)] - pub fn with_base_dir(base_dir: PathBuf) -> Self { - Self { temp_dir: base_dir } - } - - /// Get the base temp directory path. - pub fn temp_dir(&self) -> &PathBuf { - &self.temp_dir - } - - /// Create a temp directory for a task. - /// - /// This creates a directory at ~/.makima/temp/task-{id}/ and triggers - /// cleanup if the total size exceeds the limit. - pub async fn create_task_dir(&self, task_id: Uuid) -> Result<PathBuf, std::io::Error> { - // Ensure base directory exists - fs::create_dir_all(&self.temp_dir).await?; - - // Check size and cleanup if needed - if let Err(e) = self.cleanup_if_needed().await { - tracing::warn!("Temp directory cleanup failed: {}", e); - // Continue anyway, cleanup is best-effort - } - - // Create task-specific directory - let task_dir = self.temp_dir.join(format!("task-{}", task_id)); - fs::create_dir_all(&task_dir).await?; - - tracing::info!( - task_id = %task_id, - path = %task_dir.display(), - "Created temp directory for task" - ); - - Ok(task_dir) - } - - /// Calculate total size of temp directory recursively. - async fn get_total_size(&self) -> Result<u64, std::io::Error> { - if !self.temp_dir.exists() { - return Ok(0); - } - - let mut total = 0u64; - let mut stack = vec![self.temp_dir.clone()]; - - while let Some(dir) = stack.pop() { - let mut entries = match fs::read_dir(&dir).await { - Ok(e) => e, - Err(_) => continue, - }; - - while let Ok(Some(entry)) = entries.next_entry().await { - let metadata = match entry.metadata().await { - Ok(m) => m, - Err(_) => continue, - }; - - if metadata.is_dir() { - stack.push(entry.path()); - } else { - total += metadata.len(); - } - } - } - - Ok(total) - } - - /// Remove oldest directories if total size exceeds limit. - async fn cleanup_if_needed(&self) -> Result<(), std::io::Error> { - let size = self.get_total_size().await?; - if size <= MAX_TEMP_SIZE_BYTES { - return Ok(()); - } - - tracing::info!( - current_size_mb = size / 1024 / 1024, - limit_mb = MAX_TEMP_SIZE_BYTES / 1024 / 1024, - "Temp directory exceeds size limit, starting cleanup" - ); - - // Get all task dirs with modification times - let mut dirs: Vec<(PathBuf, std::time::SystemTime, u64)> = vec![]; - let mut entries = fs::read_dir(&self.temp_dir).await?; - - while let Ok(Some(entry)) = entries.next_entry().await { - let path = entry.path(); - if !path.is_dir() { - continue; - } - - let metadata = match entry.metadata().await { - Ok(m) => m, - Err(_) => continue, - }; - - let modified = metadata.modified().unwrap_or(std::time::UNIX_EPOCH); - let dir_size = self.get_dir_size(&path).await.unwrap_or(0); - dirs.push((path, modified, dir_size)); - } - - // Sort by oldest first - dirs.sort_by(|a, b| a.1.cmp(&b.1)); - - // Remove oldest until under limit - let mut current_size = size; - for (path, _, dir_size) in dirs { - if current_size <= MAX_TEMP_SIZE_BYTES { - break; - } - - tracing::info!( - path = %path.display(), - size_mb = dir_size / 1024 / 1024, - "Removing old temp directory" - ); - - if let Err(e) = fs::remove_dir_all(&path).await { - tracing::warn!(path = %path.display(), error = %e, "Failed to remove temp directory"); - continue; - } - - current_size = current_size.saturating_sub(dir_size); - } - - tracing::info!( - new_size_mb = current_size / 1024 / 1024, - "Temp directory cleanup complete" - ); - - Ok(()) - } - - /// Calculate size of a directory recursively. - async fn get_dir_size(&self, path: &PathBuf) -> Result<u64, std::io::Error> { - let mut total = 0u64; - let mut stack = vec![path.clone()]; - - while let Some(dir) = stack.pop() { - let mut entries = match fs::read_dir(&dir).await { - Ok(e) => e, - Err(_) => continue, - }; - - while let Ok(Some(entry)) = entries.next_entry().await { - let metadata = match entry.metadata().await { - Ok(m) => m, - Err(_) => continue, - }; - - if metadata.is_dir() { - stack.push(entry.path()); - } else { - total += metadata.len(); - } - } - } - - Ok(total) - } - - /// Remove a specific task's temp directory. - #[allow(dead_code)] - pub async fn remove_task_dir(&self, task_id: Uuid) -> Result<(), std::io::Error> { - let task_dir = self.temp_dir.join(format!("task-{}", task_id)); - if task_dir.exists() { - fs::remove_dir_all(&task_dir).await?; - tracing::info!( - task_id = %task_id, - path = %task_dir.display(), - "Removed temp directory for task" - ); - } - Ok(()) - } -} - -impl Default for TempManager { - fn default() -> Self { - Self::new() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_temp_manager_default_dir() { - let manager = TempManager::new(); - assert!(manager.temp_dir().ends_with(".makima/temp")); - } -} |
