diff --git a/src/bin/dummy.rs b/examples/basic.rs similarity index 51% rename from src/bin/dummy.rs rename to examples/basic.rs index 21a4a78..1e978b2 100644 --- a/src/bin/dummy.rs +++ b/examples/basic.rs @@ -1,4 +1,3 @@ -/* use std::path::Path; use my_tasks::{client::Client, traits::CalDavSource}; @@ -8,31 +7,33 @@ use my_tasks::settings::URL; use my_tasks::settings::USERNAME; use my_tasks::settings::PASSWORD; -const CACHE_FILE: &str = "caldav_cache.json"; -*/ +const CACHE_FOLDER: &str = "example_cache"; + #[tokio::main] async fn main() { - /* - let cache_path = Path::new(CACHE_FILE); + env_logger::init(); - let mut client = Client::new(URL, USERNAME, PASSWORD).unwrap(); - let mut cache = match Cache::from_file(&cache_path) { + let cache_path = Path::new(CACHE_FOLDER); + + let client = Client::new(URL, USERNAME, PASSWORD).unwrap(); + let cache = match Cache::from_folder(&cache_path) { Ok(cache) => cache, Err(err) => { log::warn!("Invalid cache file: {}. Using a default cache", err); Cache::new(&cache_path) } }; - let provider = Provider::new(client, cache); + let mut provider = Provider::new(client, cache); let cals = provider.local().get_calendars().await.unwrap(); println!("---- before sync -----"); - my_tasks::utils::print_calendar_list(cals); + my_tasks::utils::print_calendar_list(&cals).await; - provider.sync(); + if let Err(err) = provider.sync().await { + log::error!("Unable to sync: {}", err); + } println!("---- after sync -----"); - my_tasks::utils::print_calendar_list(cals); - */ - + let cals = provider.local().get_calendars().await.unwrap(); + my_tasks::utils::print_calendar_list(&cals).await; } diff --git a/src/cache.rs b/src/cache.rs index c2f8d08..679a37c 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -116,11 +116,6 @@ impl Cache { } - pub fn add_calendar(&mut self, calendar: Arc>) { - let id = calendar.lock().unwrap().id().clone(); - self.data.calendars.insert(id, calendar); - } - /// Compares two Caches to check they have the same current content /// /// This is not a complete equality test: some attributes (last sync date, deleted items...) may differ @@ -187,6 +182,15 @@ impl CalDavSource for Cache { async fn get_calendar(&self, id: &CalendarId) -> Option>> { self.data.calendars.get(id).map(|arc| arc.clone()) } + + async fn insert_calendar(&mut self, new_calendar: CachedCalendar) -> Result<(), Box> { + let id = new_calendar.id().clone(); + log::debug!("Inserting local calendar {}", id); + match self.data.calendars.insert(id, Arc::new(Mutex::new(new_calendar))) { + Some(_) => Err("Attempt to insert calendar failed: there is alredy such a calendar.".into()), + None => Ok(()) , + } + } } #[cfg(test)] @@ -207,7 +211,8 @@ mod tests { let cal1 = CachedCalendar::new("shopping list".to_string(), Url::parse("https://caldav.com/shopping").unwrap(), SupportedComponents::TODO); - cache.add_calendar(Arc::new(Mutex::new(cal1))); + cache.insert_calendar(cal1).await.unwrap(); + cache.save_to_folder().unwrap(); diff --git a/src/calendar/cached_calendar.rs b/src/calendar/cached_calendar.rs index 36604c1..9b4d405 100644 --- a/src/calendar/cached_calendar.rs +++ b/src/calendar/cached_calendar.rs @@ -21,16 +21,6 @@ pub struct CachedCalendar { items: HashMap, } -impl CachedCalendar { - /// Create a new calendar - pub fn new(name: String, id: CalendarId, supported_components: SupportedComponents) -> Self { - Self { - name, id, supported_components, - items: HashMap::new(), - } - } -} - #[async_trait] impl BaseCalendar for CachedCalendar { fn name(&self) -> &str { @@ -54,6 +44,13 @@ impl BaseCalendar for CachedCalendar { #[async_trait] impl CompleteCalendar for CachedCalendar { + fn new(name: String, id: CalendarId, supported_components: SupportedComponents) -> Self { + Self { + name, id, supported_components, + items: HashMap::new(), + } + } + async fn get_item_ids(&self) -> Result, Box> { Ok(self.items.iter() .map(|(id, _)| id.clone()) diff --git a/src/client.rs b/src/client.rs index 4e212b7..81bc81a 100644 --- a/src/client.rs +++ b/src/client.rs @@ -230,5 +230,9 @@ impl CalDavSource for Client { .and_then(|cals| cals.get(id)) .map(|cal| cal.clone()) } + + async fn insert_calendar(&mut self, new_calendar: RemoteCalendar) -> Result<(), Box> { + Err("Not implemented".into()) + } } diff --git a/src/provider.rs b/src/provider.rs index c25592b..ae16088 100644 --- a/src/provider.rs +++ b/src/provider.rs @@ -7,6 +7,7 @@ use std::marker::PhantomData; use crate::traits::{CalDavSource, DavCalendar}; use crate::traits::CompleteCalendar; use crate::item::SyncStatus; +use crate::calendar::SupportedComponents; /// A data source that combines two `CalDavSources` (usually a server and a local cache), which is able to sync both sources. pub struct Provider @@ -58,13 +59,21 @@ where for (id, cal_remote) in cals_remote { let mut cal_remote = cal_remote.lock().unwrap(); - let cal_local = match self.local.get_calendar(&id).await { - None => { - log::error!("TODO: implement here"); + let cal_local = loop { + if let Some(cal) = self.local.get_calendar(&id).await { + break cal; + } + + // This calendar does not exist locally yet, let's add it + log::error!("TODO: what name/SP should we choose?"); + let new_calendar = T::new(String::from("new calendar"), id.clone(), SupportedComponents::TODO); + + if let Err(err) = self.local.insert_calendar(new_calendar).await { + log::warn!("Unable to create local calendar {}: {}. Skipping it.", id, err); continue; - }, - Some(cal) => cal, + } }; + let mut cal_local = cal_local.lock().unwrap(); // Step 1 - find the differences diff --git a/src/traits.rs b/src/traits.rs index 881a19a..c558a59 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -8,6 +8,7 @@ use crate::item::Item; use crate::item::ItemId; use crate::item::VersionTag; use crate::calendar::CalendarId; +use crate::calendar::SupportedComponents; #[async_trait] pub trait CalDavSource { @@ -16,6 +17,8 @@ pub trait CalDavSource { async fn get_calendars(&self) -> Result>>, Box>; /// Returns the calendar matching the ID async fn get_calendar(&self, id: &CalendarId) -> Option>>; + /// Insert a calendar if it did not exist + async fn insert_calendar(&mut self, new_calendar: T) -> Result<(), Box>; } /// This trait contains functions that are common to all calendars @@ -72,6 +75,8 @@ pub trait DavCalendar : BaseCalendar { /// Usually, these are local calendars fully backed by a local folder #[async_trait] pub trait CompleteCalendar : BaseCalendar { + fn new(name: String, id: CalendarId, supported_components: SupportedComponents) -> Self; + /// Get the IDs of all current items in this calendar async fn get_item_ids(&self) -> Result, Box>;