1use crate::reminder::Reminder;
2use anyhow::{Context, Result};
3use std::fs;
4use std::path::PathBuf;
5use uuid::Uuid;
6
7pub struct Storage {
8 path: PathBuf,
9}
10
11impl Storage {
12 pub fn new() -> Result<Self> {
13 let data_dir = dirs::data_local_dir()
14 .context("Failed to get local data directory")?
15 .join("reminder-cli");
16
17 fs::create_dir_all(&data_dir)?;
18
19 Ok(Self {
20 path: data_dir.join("reminders.json"),
21 })
22 }
23
24 pub fn load(&self) -> Result<Vec<Reminder>> {
25 if !self.path.exists() {
26 return Ok(Vec::new());
27 }
28
29 let content = fs::read_to_string(&self.path)
30 .context("Failed to read reminders file")?;
31
32 if content.trim().is_empty() {
33 return Ok(Vec::new());
34 }
35
36 let reminders: Vec<Reminder> = serde_json::from_str(&content)
37 .context("Failed to parse reminders JSON")?;
38
39 Ok(reminders)
40 }
41
42 pub fn save(&self, reminders: &[Reminder]) -> Result<()> {
43 let content = serde_json::to_string_pretty(reminders)
44 .context("Failed to serialize reminders")?;
45
46 fs::write(&self.path, content)
47 .context("Failed to write reminders file")?;
48
49 Ok(())
50 }
51
52 pub fn add(&self, reminder: Reminder) -> Result<()> {
53 let mut reminders = self.load()?;
54 reminders.push(reminder);
55 self.save(&reminders)
56 }
57
58 pub fn delete(&self, id: Uuid) -> Result<bool> {
59 let mut reminders = self.load()?;
60 let initial_len = reminders.len();
61 reminders.retain(|r| r.id != id);
62
63 if reminders.len() == initial_len {
64 return Ok(false);
65 }
66
67 self.save(&reminders)?;
68 Ok(true)
69 }
70
71 pub fn update(&self, id: Uuid, updater: impl FnOnce(&mut Reminder)) -> Result<bool> {
72 let mut reminders = self.load()?;
73
74 if let Some(reminder) = reminders.iter_mut().find(|r| r.id == id) {
75 updater(reminder);
76 self.save(&reminders)?;
77 Ok(true)
78 } else {
79 Ok(false)
80 }
81 }
82
83 pub fn get(&self, id: Uuid) -> Result<Option<Reminder>> {
84 let reminders = self.load()?;
85 Ok(reminders.into_iter().find(|r| r.id == id))
86 }
87
88 pub fn pid_file_path() -> Result<PathBuf> {
89 let data_dir = dirs::data_local_dir()
90 .context("Failed to get local data directory")?
91 .join("reminder-cli");
92
93 fs::create_dir_all(&data_dir)?;
94 Ok(data_dir.join("daemon.pid"))
95 }
96
97 pub fn log_file_path() -> Result<PathBuf> {
98 let data_dir = dirs::data_local_dir()
99 .context("Failed to get local data directory")?
100 .join("reminder-cli");
101
102 fs::create_dir_all(&data_dir)?;
103 Ok(data_dir.join("daemon.log"))
104 }
105}