use std::path::PathBuf;
use async_trait::async_trait;
use serde_json::Value;
use super::{Backend, Result};
use crate::agent::DeepAgentError;
pub struct FilesystemBackend {
dir: PathBuf,
}
impl FilesystemBackend {
pub fn new(dir: impl Into<PathBuf>) -> Self {
Self { dir: dir.into() }
}
fn session_path(&self, session_id: &str) -> PathBuf {
self.dir.join(format!("{session_id}.json"))
}
}
#[async_trait]
impl Backend for FilesystemBackend {
async fn save_state(&self, session_id: &str, state: &Value) -> Result<()> {
tokio::fs::create_dir_all(&self.dir)
.await
.map_err(|e| DeepAgentError::BackendError(e.to_string()))?;
let data = serde_json::to_string_pretty(state)
.map_err(|e| DeepAgentError::BackendError(e.to_string()))?;
tokio::fs::write(self.session_path(session_id), data)
.await
.map_err(|e| DeepAgentError::BackendError(e.to_string()))?;
Ok(())
}
async fn load_state(&self, session_id: &str) -> Result<Option<Value>> {
let path = self.session_path(session_id);
if !path.exists() {
return Ok(None);
}
let data = tokio::fs::read_to_string(&path)
.await
.map_err(|e| DeepAgentError::BackendError(e.to_string()))?;
let value: Value =
serde_json::from_str(&data).map_err(|e| DeepAgentError::BackendError(e.to_string()))?;
Ok(Some(value))
}
async fn list_sessions(&self) -> Result<Vec<String>> {
if !self.dir.exists() {
return Ok(Vec::new());
}
let mut sessions = Vec::new();
let mut dir = tokio::fs::read_dir(&self.dir)
.await
.map_err(|e| DeepAgentError::BackendError(e.to_string()))?;
while let Some(entry) = dir
.next_entry()
.await
.map_err(|e| DeepAgentError::BackendError(e.to_string()))?
{
let name = entry.file_name().to_string_lossy().to_string();
if let Some(session_id) = name.strip_suffix(".json") {
sessions.push(session_id.to_string());
}
}
sessions.sort();
Ok(sessions)
}
}