1 changed files with 118 additions and 1 deletions
@ -1 +1,118 @@ |
|||||||
//! This module provides a local cache for CalDAV data
|
//! This module provides a local cache for CalDAV data
|
||||||
|
|
||||||
|
use std::path::PathBuf; |
||||||
|
use std::path::Path; |
||||||
|
use std::error::Error; |
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize}; |
||||||
|
use async_trait::async_trait; |
||||||
|
|
||||||
|
use crate::traits::CalDavSource; |
||||||
|
use crate::Calendar; |
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)] |
||||||
|
pub struct Cache { |
||||||
|
backing_file: PathBuf, |
||||||
|
data: CachedData, |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Default, Debug, PartialEq, Serialize, Deserialize)] |
||||||
|
struct CachedData { |
||||||
|
calendars: Vec<Calendar>, |
||||||
|
} |
||||||
|
|
||||||
|
impl Cache { |
||||||
|
/// Get the cache file
|
||||||
|
pub fn cache_file() -> PathBuf { |
||||||
|
return PathBuf::from(String::from("~/.config/my-tasks/cache.json")) |
||||||
|
} |
||||||
|
|
||||||
|
/// Initialize a cache from the content of a backing file (if it exists, otherwise start with the default contents)
|
||||||
|
pub fn from_file(path: &Path) -> Result<Self, Box<dyn Error>> { |
||||||
|
let data = match std::fs::File::open(path) { |
||||||
|
Err(_) => { |
||||||
|
CachedData::default() |
||||||
|
}, |
||||||
|
Ok(file) => serde_json::from_reader(file)?, |
||||||
|
}; |
||||||
|
|
||||||
|
Ok(Self{ |
||||||
|
backing_file: PathBuf::from(path), |
||||||
|
data, |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
/// Initialize a cache with the default contents
|
||||||
|
pub fn new(path: &Path) -> Self { |
||||||
|
Self{ |
||||||
|
backing_file: PathBuf::from(path), |
||||||
|
data: CachedData::default(), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Store the current Cache to its backing file
|
||||||
|
fn save_to_file(&mut self) { |
||||||
|
// Save the contents to the file
|
||||||
|
let path = &self.backing_file; |
||||||
|
let file = match std::fs::File::create(path) { |
||||||
|
Err(err) => { |
||||||
|
log::warn!("Unable to save file {:?}: {}", path, err); |
||||||
|
return; |
||||||
|
}, |
||||||
|
Ok(f) => f, |
||||||
|
}; |
||||||
|
|
||||||
|
if let Err(err) = serde_json::to_writer(file, &self.data) { |
||||||
|
log::warn!("Unable to serialize: {}", err); |
||||||
|
return; |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Cache { |
||||||
|
pub fn add_calendar(&mut self, calendar: Calendar) { |
||||||
|
self.data.calendars.push(calendar); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[async_trait] |
||||||
|
impl CalDavSource for Cache { |
||||||
|
async fn get_calendars(&self) -> Result<&Vec<Calendar>, Box<dyn Error>> { |
||||||
|
Ok(&self.data.calendars) |
||||||
|
} |
||||||
|
|
||||||
|
async fn get_calendars_mut(&mut self) -> Result<Vec<&mut Calendar>, Box<dyn Error>> { |
||||||
|
Ok( |
||||||
|
self.data.calendars.iter_mut() |
||||||
|
.collect() |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)] |
||||||
|
mod tests { |
||||||
|
use super::*; |
||||||
|
|
||||||
|
use url::Url; |
||||||
|
use crate::calendar::SupportedComponents; |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn serde_cache() { |
||||||
|
let cache_path = PathBuf::from(String::from("cache.json")); |
||||||
|
|
||||||
|
let mut cache = Cache::new(&cache_path); |
||||||
|
|
||||||
|
let cal1 = Calendar::new("shopping list".to_string(), |
||||||
|
Url::parse("https://caldav.com/shopping").unwrap(), |
||||||
|
SupportedComponents::TODO); |
||||||
|
cache.add_calendar(cal1); |
||||||
|
|
||||||
|
cache.save_to_file(); |
||||||
|
|
||||||
|
let retrieved_cache = Cache::from_file(&cache_path).unwrap(); |
||||||
|
assert_eq!(cache, retrieved_cache); |
||||||
|
} |
||||||
|
} |
||||||
|
|||||||
Loading…
Reference in new issue