adk_studio/storage/
filesystem.rs

1use crate::schema::{ProjectMeta, ProjectSchema};
2use anyhow::{Context, Result};
3use std::path::PathBuf;
4use tokio::fs;
5use uuid::Uuid;
6
7/// File-based project storage
8pub struct FileStorage {
9    base_dir: PathBuf,
10}
11
12impl FileStorage {
13    pub async fn new(base_dir: PathBuf) -> Result<Self> {
14        fs::create_dir_all(&base_dir).await?;
15        Ok(Self { base_dir })
16    }
17
18    fn project_path(&self, id: Uuid) -> PathBuf {
19        self.base_dir.join(format!("{}.json", id))
20    }
21
22    pub async fn list(&self) -> Result<Vec<ProjectMeta>> {
23        let mut projects = Vec::new();
24        let mut entries = fs::read_dir(&self.base_dir).await?;
25
26        while let Some(entry) = entries.next_entry().await? {
27            let path = entry.path();
28            if path.extension().is_some_and(|e| e == "json") {
29                if let Ok(content) = fs::read_to_string(&path).await {
30                    if let Ok(project) = serde_json::from_str::<ProjectSchema>(&content) {
31                        projects.push(ProjectMeta::from(&project));
32                    }
33                }
34            }
35        }
36
37        projects.sort_by(|a, b| b.updated_at.cmp(&a.updated_at));
38        Ok(projects)
39    }
40
41    pub async fn get(&self, id: Uuid) -> Result<ProjectSchema> {
42        let path = self.project_path(id);
43        let content =
44            fs::read_to_string(&path).await.with_context(|| format!("Project {} not found", id))?;
45        serde_json::from_str(&content).context("Invalid project format")
46    }
47
48    pub async fn save(&self, project: &ProjectSchema) -> Result<()> {
49        let path = self.project_path(project.id);
50        let content = serde_json::to_string_pretty(project)?;
51        fs::write(&path, content).await?;
52        Ok(())
53    }
54
55    pub async fn delete(&self, id: Uuid) -> Result<()> {
56        let path = self.project_path(id);
57        fs::remove_file(&path).await.with_context(|| format!("Project {} not found", id))
58    }
59
60    pub async fn exists(&self, id: Uuid) -> bool {
61        self.project_path(id).exists()
62    }
63}