1use ron::ser::PrettyConfig;
2use serde::{Deserialize, Serialize};
3use std::fmt::Debug;
4use std::fs::{self, File, OpenOptions};
5use std::io::{Read, Write};
6use std::path::PathBuf;
7use thiserror::Error;
8
9use log::debug;
10use log::info;
11use log::log;
12use log::warn;
13
14use crate::manager::StoreManager;
15
16#[derive(Error, Debug)]
17pub enum StoreError {
18 #[error("RON parsing error: {0}")]
19 RonParse(#[source] ron::error::SpannedError),
20
21 #[error("RON error: {0}")]
22 Ron(#[source] ron::error::Error),
23
24 #[error("Failed to open file: {0}")]
25 FileOpen(#[source] std::io::Error),
26
27 #[error("Failed to read from file: {0}")]
28 Read(#[source] std::io::Error),
29
30 #[error("Failed to create directory: {0}")]
31 CreateDir(#[source] std::io::Error),
32
33 #[error("Failed to write to file: {0}")]
34 Write(#[source] std::io::Error),
35}
36
37#[derive(Debug, Default)]
38pub enum StoringType {
39 Cache,
40 #[default]
41 Data,
42 Config,
43}
44
45pub trait Storing: Serialize + for<'de> Deserialize<'de> + Default {
46 fn store_type() -> StoringType {
47 StoringType::default()
48 }
49}
50
51#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
55pub struct StoreHandle<T> {
56 store_id: String,
57 store: T,
58}
59
60impl<T: Storing> StoreHandle<T> {
61 pub fn new(store_id: &str) -> Self {
62 Self {
63 store: T::default(),
64 store_id: store_id.to_owned(),
65 }
66 }
67
68 fn set_store(&mut self, store: T) {
69 debug!("Setting store with id: {}", self.store_id);
70 self.store = store;
71 }
72
73 pub fn get_store_mut(&mut self) -> &mut T {
75 &mut self.store
76 }
77
78 pub fn get_store(&self) -> &T {
80 &self.store
81 }
82
83 pub fn store_id(&self) -> &str {
84 &self.store_id
85 }
86}
87
88#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
140pub struct Storage {
141 cache_dir: PathBuf,
142 data_dir: PathBuf,
143 config_dir: PathBuf,
144}
145
146impl Storage {
147 pub fn new(app_id: &str) -> Self {
153 Self {
154 data_dir: dirs::data_dir()
155 .expect("Failed to determine cache directory path")
156 .join(app_id),
157 config_dir: dirs::config_dir()
158 .expect("Failed to determine data directory path")
159 .join(app_id),
160 cache_dir: dirs::cache_dir()
161 .expect("Failed to determine configuration directory path")
162 .join(app_id),
163 }
164 }
165
166 pub fn from_dirs(cache_dir: PathBuf, data_dir: PathBuf, config_dir: PathBuf) -> Self {
168 Self {
169 cache_dir,
170 data_dir,
171 config_dir,
172 }
173 }
174
175 pub fn new_manager<T: Storing>(&self, store_id: &str) -> Result<StoreManager<T>, StoreError> {
177 StoreManager::<T>::new(self, store_id)
178 }
179
180 pub fn new_handle<T: Storing>(&self, store_id: &str) -> StoreHandle<T> {
182 StoreHandle::<T>::new(store_id)
183 }
184
185 pub fn read<T: Storing>(&self, handle: &mut StoreHandle<T>) -> Result<(), StoreError> {
198 debug!("Reading store with id: {}", handle.store_id());
199 self.open_file::<T, _>(
200 |file, handle| {
201 let store = Self::read_string(file).map_err(StoreError::Read)?;
202 let store_data: T = ron::from_str(&store).map_err(StoreError::RonParse)?;
203
204 handle.set_store(store_data);
205
206 info!("Successfully read store with id: {}", handle.store_id());
207 Ok(())
208 },
209 handle,
210 )
211 }
212
213 pub fn write<T: Storing>(&self, handle: &mut StoreHandle<T>) -> Result<(), StoreError> {
226 debug!("Writing store with id: {}", handle.store_id());
227 self.open_file::<T, _>(
228 |file: &mut File, handle| {
229 let store = handle.get_store_mut();
230
231 let str =
232 ron::ser::to_string_pretty(&store, PrettyConfig::new().compact_arrays(true))
233 .map_err(StoreError::Ron)?;
234
235 file.set_len(0).map_err(StoreError::Write)?;
236 file.write_all(str.as_bytes()).map_err(StoreError::Write)?;
237 file.flush().map_err(StoreError::Write)?;
238
239 info!("Successfully wrote store with id: {}", handle.store_id());
240 Ok(())
241 },
242 handle,
243 )
244 }
245
246 fn open_file<T, F>(
258 &self,
259 mut operation: F,
260 handle: &mut StoreHandle<T>,
261 ) -> Result<(), StoreError>
262 where
263 T: Storing,
264 F: FnMut(&mut File, &mut StoreHandle<T>) -> Result<(), StoreError>,
265 {
266 let mut dir_path = self.dir_path::<T>();
267 dir_path.push(handle.store_id()); debug!("Opening file at path: {:?}", dir_path);
270
271 match OpenOptions::new()
272 .read(true)
273 .write(true)
274 .create(false)
275 .truncate(false)
276 .open(&dir_path)
277 {
278 Ok(mut config) => {
279 debug!("File opened successfully at path: {:?}", dir_path);
280 operation(&mut config, handle)
281 }
282 Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
283 warn!(
284 "File not found at path: {:?}, creating default store",
285 dir_path
286 );
287 self.store_default::<T>(dir_path)?;
288 self.open_file(operation, handle)
289 }
290 Err(err) => {
291 warn!(
292 "Failed to open file at path: {:?}, error: {:?}",
293 dir_path, err
294 );
295 Err(StoreError::FileOpen(err))
296 }
297 }
298 }
299
300 fn store_default<T: Storing>(&self, path: PathBuf) -> Result<(), StoreError> {
301 debug!("Storing default configuration at path: {:?}", path);
302 if let Some(parent) = path.parent() {
303 fs::create_dir_all(parent).map_err(StoreError::CreateDir)?;
304 info!("Created directory for path: {:?}", parent);
305 }
306
307 let default_store = T::default();
308 let str = ron::ser::to_string_pretty(&default_store, PrettyConfig::new())
309 .map_err(StoreError::Ron)?;
310 fs::write(&path, str).map_err(StoreError::Write)?;
311 info!("Default store written at path: {:?}", &path);
312
313 Ok(())
314 }
315
316 fn dir_path<T: Storing>(&self) -> PathBuf {
317 let path = match T::store_type() {
318 StoringType::Cache => self.cache_dir.clone(),
319 StoringType::Data => self.data_dir.clone(),
320 StoringType::Config => self.config_dir.clone(),
321 };
322 debug!(
323 "Resolved directory path for store type: {:?} to path: {:?}",
324 T::store_type(),
325 path
326 );
327 path
328 }
329
330 fn read_string(mut file: &File) -> Result<String, std::io::Error> {
331 let mut buf = String::new();
332 file.read_to_string(&mut buf)?;
333 debug!("Read string from file, length: {}", buf.len());
334 Ok(buf)
335 }
336}