Turning calendars into Arc<Mutex>
This commit is contained in:
parent
d07a2b9493
commit
060f33b4bd
8 changed files with 199 additions and 91 deletions
161
src/client.rs
161
src/client.rs
|
@ -3,15 +3,18 @@
|
|||
use std::error::Error;
|
||||
use std::convert::TryFrom;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use reqwest::Method;
|
||||
use reqwest::header::CONTENT_TYPE;
|
||||
use minidom::Element;
|
||||
use url::Url;
|
||||
|
||||
use crate::utils::{find_elem, find_elems};
|
||||
use crate::calendar::cached_calendar::CachedCalendar;
|
||||
use crate::calendar::remote_calendar::RemoteCalendar;
|
||||
use crate::calendar::CalendarId;
|
||||
use crate::traits::CalDavSource;
|
||||
use crate::traits::PartialCalendar;
|
||||
|
||||
|
||||
|
@ -71,9 +74,17 @@ pub struct Client {
|
|||
username: String,
|
||||
password: String,
|
||||
|
||||
/// The interior mutable part of a Client.
|
||||
/// This data may be retrieved once and then cached
|
||||
cached_replies: Mutex<CachedReplies>,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Default)]
|
||||
struct CachedReplies {
|
||||
principal: Option<Url>,
|
||||
calendar_home_set: Option<Url>,
|
||||
calendars: Option<HashMap<CalendarId, CachedCalendar>>,
|
||||
calendars: Option<HashMap<CalendarId, Arc<Mutex<RemoteCalendar>>>>,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
|
@ -85,9 +96,7 @@ impl Client {
|
|||
url,
|
||||
username: username.to_string(),
|
||||
password: password.to_string(),
|
||||
principal: None,
|
||||
calendar_home_set: None,
|
||||
calendars: None,
|
||||
cached_replies: Mutex::new(CachedReplies::default()),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -111,33 +120,30 @@ impl Client {
|
|||
let text = self.sub_request(url, body, 0).await?;
|
||||
|
||||
let mut current_element: &Element = &text.parse().unwrap();
|
||||
items.iter()
|
||||
.map(|item| {
|
||||
for item in items {
|
||||
current_element = find_elem(¤t_element, item).unwrap();
|
||||
})
|
||||
.collect::<()>();
|
||||
|
||||
}
|
||||
Ok(current_element.text())
|
||||
}
|
||||
|
||||
/// Return the Principal URL, or fetch it from server if not known yet
|
||||
async fn get_principal(&mut self) -> Result<Url, Box<dyn Error>> {
|
||||
if let Some(p) = &self.principal {
|
||||
async fn get_principal(&self) -> Result<Url, Box<dyn Error>> {
|
||||
if let Some(p) = &self.cached_replies.lock().unwrap().principal {
|
||||
return Ok(p.clone());
|
||||
}
|
||||
|
||||
let href = self.sub_request_and_process(&self.url, DAVCLIENT_BODY.into(), &["current-user-principal", "href"]).await?;
|
||||
let mut principal_url = self.url.clone();
|
||||
principal_url.set_path(&href);
|
||||
self.principal = Some(principal_url.clone());
|
||||
self.cached_replies.lock().unwrap().principal = Some(principal_url.clone());
|
||||
log::debug!("Principal URL is {}", href);
|
||||
|
||||
return Ok(principal_url);
|
||||
}
|
||||
|
||||
/// Return the Homeset URL, or fetch it from server if not known yet
|
||||
async fn get_cal_home_set(&mut self) -> Result<Url, Box<dyn Error>> {
|
||||
if let Some(h) = &self.calendar_home_set {
|
||||
async fn get_cal_home_set(&self) -> Result<Url, Box<dyn Error>> {
|
||||
if let Some(h) = &self.cached_replies.lock().unwrap().calendar_home_set {
|
||||
return Ok(h.clone());
|
||||
}
|
||||
let principal_url = self.get_principal().await?;
|
||||
|
@ -145,16 +151,88 @@ impl Client {
|
|||
let href = self.sub_request_and_process(&principal_url, HOMESET_BODY.into(), &["calendar-home-set", "href"]).await?;
|
||||
let mut chs_url = self.url.clone();
|
||||
chs_url.set_path(&href);
|
||||
self.calendar_home_set = Some(chs_url.clone());
|
||||
self.cached_replies.lock().unwrap().calendar_home_set = Some(chs_url.clone());
|
||||
log::debug!("Calendar home set URL is {:?}", chs_url.path());
|
||||
|
||||
Ok(chs_url)
|
||||
}
|
||||
|
||||
async fn populate_calendars(&self) -> Result<(), Box<dyn Error>> {
|
||||
let cal_home_set = self.get_cal_home_set().await?;
|
||||
|
||||
let text = self.sub_request(&cal_home_set, CAL_BODY.into(), 1).await?;
|
||||
|
||||
let root: Element = text.parse().unwrap();
|
||||
let reps = find_elems(&root, "response");
|
||||
let mut calendars = HashMap::new();
|
||||
for rep in reps {
|
||||
let display_name = find_elem(rep, "displayname").map(|e| e.text()).unwrap_or("<no name>".to_string());
|
||||
log::debug!("Considering calendar {}", display_name);
|
||||
|
||||
// We filter out non-calendar items
|
||||
let resource_types = match find_elem(rep, "resourcetype") {
|
||||
None => continue,
|
||||
Some(rt) => rt,
|
||||
};
|
||||
let mut found_calendar_type = false;
|
||||
for resource_type in resource_types.children() {
|
||||
if resource_type.name() == "calendar" {
|
||||
found_calendar_type = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if found_calendar_type == false {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We filter out the root calendar collection, that has an empty supported-calendar-component-set
|
||||
let el_supported_comps = match find_elem(rep, "supported-calendar-component-set") {
|
||||
None => continue,
|
||||
Some(comps) => comps,
|
||||
};
|
||||
if el_supported_comps.children().count() == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let calendar_href = match find_elem(rep, "href") {
|
||||
None => {
|
||||
log::warn!("Calendar {} has no URL! Ignoring it.", display_name);
|
||||
continue;
|
||||
},
|
||||
Some(h) => h.text(),
|
||||
};
|
||||
|
||||
let mut this_calendar_url = self.url.clone();
|
||||
this_calendar_url.set_path(&calendar_href);
|
||||
|
||||
let supported_components = match crate::calendar::SupportedComponents::try_from(el_supported_comps.clone()) {
|
||||
Err(err) => {
|
||||
log::warn!("Calendar {} has invalid supported components ({})! Ignoring it.", display_name, err);
|
||||
continue;
|
||||
},
|
||||
Ok(sc) => sc,
|
||||
};
|
||||
let this_calendar = RemoteCalendar::new(display_name, this_calendar_url, supported_components);
|
||||
log::info!("Found calendar {}", this_calendar.name());
|
||||
calendars.insert(this_calendar.id().clone(), Arc::new(Mutex::new(this_calendar)));
|
||||
}
|
||||
|
||||
let mut replies = self.cached_replies.lock().unwrap();
|
||||
replies.calendars = Some(calendars);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl CalDavSource<RemoteCalendar> for Client {
|
||||
/// Return the list of calendars, or fetch from server if not known yet
|
||||
pub async fn get_calendars(&mut self) -> Result<HashMap<CalendarId, CachedCalendar>, Box<dyn Error>> {
|
||||
if let Some(c) = &self.calendars {
|
||||
return Ok(c.clone());
|
||||
/*
|
||||
async fn get_calendars(&self) -> Result<&HashMap<CalendarId, RemoteCalendar>, Box<dyn Error>> {
|
||||
let mut replies = self.cached_replies.lock().unwrap();
|
||||
|
||||
if let Some(c) = &replies.calendars {
|
||||
return Ok(c);
|
||||
}
|
||||
let cal_home_set = self.get_cal_home_set().await?;
|
||||
|
||||
|
@ -210,37 +288,36 @@ impl Client {
|
|||
},
|
||||
Ok(sc) => sc,
|
||||
};
|
||||
let this_calendar = CachedCalendar::new(display_name, this_calendar_url, supported_components);
|
||||
let this_calendar = RemoteCalendar::new(display_name, this_calendar_url, supported_components);
|
||||
log::info!("Found calendar {}", this_calendar.name());
|
||||
calendars.insert(this_calendar.id().clone(), this_calendar);
|
||||
}
|
||||
|
||||
self.calendars = Some(calendars.clone());
|
||||
Ok(calendars)
|
||||
replies.calendars = Some(calendars);
|
||||
Ok(&calendars)
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
async fn get_calendars(&self) -> Result<HashMap<CalendarId, Arc<Mutex<RemoteCalendar>>>, Box<dyn Error>> {
|
||||
self.populate_calendars().await?;
|
||||
|
||||
match &self.cached_replies.lock().unwrap().calendars {
|
||||
Some(cals) => {
|
||||
return Ok(cals.clone())
|
||||
},
|
||||
None => return Err("No calendars available".into())
|
||||
};
|
||||
}
|
||||
|
||||
pub async fn get_tasks(&mut self, calendar: &CalendarId) -> Result<(), Box<dyn Error>> {
|
||||
let method = Method::from_bytes(b"REPORT")
|
||||
.expect("cannot create REPORT method.");
|
||||
|
||||
let res = reqwest::Client::new()
|
||||
.request(method, calendar.as_str())
|
||||
.header("Depth", 1)
|
||||
.header(CONTENT_TYPE, "application/xml")
|
||||
.basic_auth(self.username.clone(), Some(self.password.clone()))
|
||||
.body(TASKS_BODY)
|
||||
.send()
|
||||
.await?;
|
||||
let text = res.text().await?;
|
||||
|
||||
let el: Element = text.parse().unwrap();
|
||||
let responses = find_elems(&el, "response");
|
||||
|
||||
for _response in responses {
|
||||
println!("(a response)\n");
|
||||
async fn get_calendar(&self, id: CalendarId) -> Option<Arc<Mutex<RemoteCalendar>>> {
|
||||
self.cached_replies.lock().unwrap()
|
||||
.calendars
|
||||
.as_ref()
|
||||
.and_then(|cals| cals.get(&id))
|
||||
.map(|cal| cal.clone())
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue