diff options
author | Vincent Breitmoser <look@my.amazin.horse> | 2019-01-22 00:26:08 +0100 |
---|---|---|
committer | Vincent Breitmoser <look@my.amazin.horse> | 2019-01-22 00:26:09 +0100 |
commit | c29e7535e7b0cdfd1ac75e6d0b32a16105032f40 (patch) | |
tree | 5cd8cb5f7b6b3c4b7e8f544cf46923b733a6002d /src/icalwrap | |
parent | a129d318c3e2b26f453ba16d3f408ef3436354bf (diff) |
work around race conditions in libical
libical has some weird behavior that makes it not thread-safe. we
synchronize calls to libical timezone conversion methods to work
around this problem.
https://github.com/libical/libical/issues/86
https://github.com/libical/libical/commit/0ebf2d9a7183be94991c2681c6e3f009c64cf7cc
Diffstat (limited to 'src/icalwrap')
-rw-r--r-- | src/icalwrap/icaltime.rs | 21 | ||||
-rw-r--r-- | src/icalwrap/icalvevent.rs | 14 | ||||
-rw-r--r-- | src/icalwrap/mod.rs | 10 |
3 files changed, 37 insertions, 8 deletions
diff --git a/src/icalwrap/icaltime.rs b/src/icalwrap/icaltime.rs index 5ab54cd..72aa533 100644 --- a/src/icalwrap/icaltime.rs +++ b/src/icalwrap/icaltime.rs @@ -4,6 +4,7 @@ use chrono::prelude::*; use ical; use utils::dateutil; use super::IcalTimeZone; +use super::TZ_MUTEX; use std::fmt::{Error,Display,Formatter}; use std::str::FromStr; @@ -17,6 +18,7 @@ impl IcalTime { } pub fn from_timestamp(timestamp: i64) -> Self { + let _lock = TZ_MUTEX.lock(); let utc = IcalTimeZone::utc(); let is_date = 0; let time = unsafe { @@ -25,6 +27,11 @@ impl IcalTime { IcalTime{ time } } + pub fn get_timestamp(&self) -> i64 { + let _lock = TZ_MUTEX.lock(); + unsafe { ical::icaltime_as_timet_with_zone(self.time, self.time.zone) } + } + pub fn as_date(&self) -> IcalTime { let mut time = self.time.clone(); time.is_date = 1; @@ -39,10 +46,12 @@ impl IcalTime { } pub fn with_timezone(&self, timezone: &IcalTimeZone) -> IcalTime { + let _lock = TZ_MUTEX.lock(); let time = unsafe { ical::icaltime_convert_to_zone(self.time, **timezone) }; - IcalTime { time } + let result = IcalTime { time }; + result } } @@ -85,6 +94,12 @@ impl FromStr for IcalTime { } } +impl From<ical::icaltimetype> for IcalTime { + fn from(time: ical::icaltimetype) -> IcalTime { + IcalTime { time } + } +} + impl<T: Into<IcalTime> + Clone> From<&T> for IcalTime { fn from(time: &T) -> IcalTime { time.clone().into() @@ -132,6 +147,7 @@ mod tests { let now = IcalTime::now(); assert_eq!("20130101T010203Z", now.to_string()); + assert_eq!(1357002123, now.get_timestamp()); } #[test] @@ -141,7 +157,7 @@ mod tests { let time = IcalTime::from(local_time); assert_eq!("Europe/Berlin", time.get_timezone().get_name()); - assert_eq!("20140101T010203", time.to_string()); + assert_eq!(1388534523, time.get_timestamp()); } #[test] @@ -153,6 +169,7 @@ mod tests { assert_eq!("US/Eastern", time.get_timezone().get_name()); assert_eq!("20121231T200203", time.to_string()); + assert_eq!(1357002123, time.get_timestamp()); } #[test] diff --git a/src/icalwrap/icalvevent.rs b/src/icalwrap/icalvevent.rs index a57b0da..126eb77 100644 --- a/src/icalwrap/icalvevent.rs +++ b/src/icalwrap/icalvevent.rs @@ -3,6 +3,7 @@ use std::ffi::CStr; use super::IcalComponent; use super::IcalVCalendar; +use super::IcalTime; use ical; pub struct IcalVEvent { @@ -61,15 +62,16 @@ impl IcalVEvent { } } - pub fn get_dtstart_unix(&self) -> Option<i64> { + pub fn get_dtstart_ical(&self) -> Option<IcalTime> { match self.instance_timestamp { - Some(timestamp) => Some(timestamp.timestamp()), + Some(timestamp) => Some(IcalTime::from_timestamp(timestamp.timestamp())), None => unsafe { let dtstart = ical::icalcomponent_get_dtstart(self.ptr); if ical::icaltime_is_null_time(dtstart) == 1 { None } else { - Some(ical::icaltime_as_timet_with_zone(dtstart, dtstart.zone)) + let icaltime = IcalTime::from(dtstart); + Some(icaltime) } } } @@ -77,12 +79,12 @@ impl IcalVEvent { pub fn get_dtend(&self) -> Option<DateTime<Local>> { let dtend = self.get_dtend_unix()?; - Some(Utc.timestamp(dtend, 0).with_timezone(&Local)) + Some(Local.timestamp(dtend, 0)) } pub fn get_dtstart(&self) -> Option<DateTime<Local>> { - let dtstart = self.get_dtstart_unix()?; - Some(Utc.timestamp(dtstart, 0).with_timezone(&Local)) + let dtstart = self.get_dtstart_ical()?.get_timestamp(); + Some(Local.timestamp(dtstart, 0)) } pub fn get_dtstart_date(&self) -> Option<Date<Local>> { diff --git a/src/icalwrap/mod.rs b/src/icalwrap/mod.rs index dc41b71..ca0e0da 100644 --- a/src/icalwrap/mod.rs +++ b/src/icalwrap/mod.rs @@ -5,6 +5,16 @@ mod icalcomponent; mod icaltime; mod icaltimezone; +// libical does some weird, non-threadsafe things in timezone methods, notably +// icaltime_convert_to_zone (which is also called in icaltime_as_timet_with_zone) +// see these two (independent!) bugs: +// https://github.com/libical/libical/issues/86 +// https://github.com/libical/libical/commit/0ebf2d9a7183be94991c2681c6e3f009c64cf7cc +use std::sync::Mutex; +lazy_static! { + static ref TZ_MUTEX: Mutex<i32> = Mutex::new(0); +} + pub use self::icalvcalendar::IcalVCalendar; pub use self::icalvcalendar::IcalEventIter; pub use self::icalvevent::IcalVEvent; |