1use anyhow::{Context, Result};
2use chrono::{DateTime, Utc};
3use serde::{Deserialize, Serialize};
4use std::fs;
5use std::path::{Path, PathBuf};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct CleanEvent {
9 pub timestamp: DateTime<Utc>,
10 pub paths: Vec<PathBuf>,
11 pub bytes_freed: u64,
12 pub note: String,
13}
14
15#[derive(Debug, Default, Serialize, Deserialize)]
16pub struct History {
17 pub events: Vec<CleanEvent>,
18}
19
20fn history_path() -> Result<PathBuf> {
21 let base = dirs::data_local_dir().context("no local data dir")?;
22 Ok(base.join("diskr").join("history.json"))
23}
24
25pub fn load() -> Result<History> {
26 let path = history_path()?;
27 if !path.exists() {
28 return Ok(History::default());
29 }
30 let text = fs::read_to_string(&path)?;
31 Ok(serde_json::from_str(&text).unwrap_or_default())
32}
33
34pub fn append(event: CleanEvent) -> Result<()> {
35 let path = history_path()?;
36 if let Some(parent) = path.parent() {
37 fs::create_dir_all(parent)?;
38 }
39 let mut history = load()?;
40 history.events.push(event);
41 save(&path, &history)
42}
43
44pub fn last_event() -> Result<Option<CleanEvent>> {
45 Ok(load()?.events.last().cloned())
46}
47
48fn save(path: &Path, history: &History) -> Result<()> {
49 let text = serde_json::to_string_pretty(history)?;
50 fs::write(path, text)?;
51 Ok(())
52}