summaryrefslogtreecommitdiff
path: root/makima/daemon/src/temp.rs
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-01-11 05:52:14 +0000
committersoryu <soryu@soryu.co>2026-01-15 00:21:16 +0000
commit87044a747b47bd83249d61a45842c7f7b2eae56d (patch)
treeef2000ce79ffcc2723ef841acef5aa1deb1d5378 /makima/daemon/src/temp.rs
parent077820c4167c168072d217a1b01df840463a12a8 (diff)
downloadsoryu-87044a747b47bd83249d61a45842c7f7b2eae56d.tar.gz
soryu-87044a747b47bd83249d61a45842c7f7b2eae56d.zip
Contract system
Diffstat (limited to 'makima/daemon/src/temp.rs')
-rw-r--r--makima/daemon/src/temp.rs224
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"));
- }
-}