adk_studio/storage/
filesystem.rs1use crate::schema::{ProjectMeta, ProjectSchema};
2use anyhow::{Context, Result};
3use std::path::PathBuf;
4use tokio::fs;
5use uuid::Uuid;
6
7pub 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}