ticker-update: use rrule
This commit is contained in:
parent
ba5b4de68d
commit
d6370aa55d
|
@ -264,6 +264,16 @@ dependencies = [
|
|||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chrono-tz"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2554a3155fec064362507487171dcc4edc3df60cb10f3a1fb10ed8094822b120"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"parse-zoneinfo",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cloudabi"
|
||||
version = "0.0.3"
|
||||
|
@ -1462,6 +1472,15 @@ dependencies = [
|
|||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parse-zoneinfo"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41"
|
||||
dependencies = [
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "1.0.1"
|
||||
|
@ -1884,6 +1903,19 @@ dependencies = [
|
|||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rrule"
|
||||
version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1ccf2e8be78bd6a32bccace1b6ae378bf093e4c4cc7c16a8a8ec3795fcf19c6"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"chrono-tz",
|
||||
"lazy_static",
|
||||
"regex",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-argon2"
|
||||
version = "0.8.3"
|
||||
|
@ -2311,6 +2343,7 @@ dependencies = [
|
|||
"libticker",
|
||||
"num_cpus",
|
||||
"reqwest",
|
||||
"rrule",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -24,11 +24,11 @@ let
|
|||
in {
|
||||
ticker-update = build {
|
||||
pname = "ticker-update";
|
||||
cargoSha256 = "04hnbwn7h5cq8pmklq7d374v64x7nqnd6brsbhdard2my5k7sd8q";
|
||||
cargoSha256 = "0limgs2lwx5vgi7x2wwwrk0z83xs4x59k56yy4ifwwz19h09knma";
|
||||
};
|
||||
ticker-serve = (build {
|
||||
pname = "ticker-serve";
|
||||
cargoSha256 = "1gr7hp0dbf53bamfwdlc2yxixglbspqq4wjqhrv5ls6njq4by33p";
|
||||
cargoSha256 = "116mhi8z9n5qmjkpzfslq4bjhgsjy1flag6lsp78v30pyghks8xx";
|
||||
}).overrideAttrs (oa: {
|
||||
postBuild = ''
|
||||
${oa.postBuild}
|
||||
|
|
|
@ -11,4 +11,5 @@ diesel = { version = "~1", features = ["postgres", "chrono"] }
|
|||
chrono = "~0.4"
|
||||
num_cpus = "~1"
|
||||
crossbeam = "~0.7"
|
||||
rrule = "0.5"
|
||||
libticker = { path = "../libticker" }
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
use std::str::FromStr;
|
||||
use std::mem::replace;
|
||||
use std::io::Read;
|
||||
use std::sync::RwLock;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use chrono::offset::Utc;
|
||||
use chrono::{Duration, offset::Utc};
|
||||
use reqwest::header::{IF_NONE_MATCH, IF_MODIFIED_SINCE, ETAG, LAST_MODIFIED, USER_AGENT};
|
||||
use diesel::{Connection, pg::PgConnection, prelude::*};
|
||||
use rrule::RRule;
|
||||
|
||||
use libticker::{
|
||||
config::{Config, CalendarOptions},
|
||||
|
@ -23,30 +25,71 @@ fn extract_vevent_objs(results: &mut Vec<Object>, mut obj: Object) {
|
|||
}
|
||||
}
|
||||
|
||||
fn obj_to_event(calendar: String, obj: &Object) -> Option<Event> {
|
||||
const RRULE_LOOKBACK: i64 = 30;
|
||||
const RRULE_LOOKAHEAD: i64 = 366;
|
||||
|
||||
fn obj_to_events(calendar: String, obj: &Object) -> Vec<Event> {
|
||||
if obj.name != "VEVENT" {
|
||||
return None;
|
||||
return vec![];
|
||||
}
|
||||
|
||||
let dtstart: Timestamp = obj.get("DTSTART")?;
|
||||
let (dtstart, dtstart_str): (Timestamp, &str) = match (obj.get("DTSTART"), obj.get("DTSTART")) {
|
||||
(Some(dtstart), Some(dtstart_str)) => (dtstart, dtstart_str),
|
||||
_ => return vec![],
|
||||
};
|
||||
let dtstart = dtstart.or_hms(0, 0, 0);
|
||||
let dtend: Option<Timestamp> = obj.get("DTEND");
|
||||
let dtend = dtend.map(|time| time.or_hms(23, 59, 59));
|
||||
let summary = obj.get("SUMMARY")?;
|
||||
let id = format!("{}{}{}{}",
|
||||
obj.get("UID").unwrap_or(""),
|
||||
dtstart,
|
||||
obj.get("DTSTAMP").unwrap_or(""),
|
||||
obj.get("RECURRENCE-ID").unwrap_or(""));
|
||||
// TODO: DESCRIPTION
|
||||
Some(Event {
|
||||
calendar, id,
|
||||
dtstart,
|
||||
dtend,
|
||||
summary,
|
||||
location: obj.get("LOCATION"),
|
||||
url: obj.get("URL"),
|
||||
})
|
||||
let summary: &str = match obj.get("SUMMARY") {
|
||||
Some(summary) => summary,
|
||||
None => return vec![],
|
||||
};
|
||||
let uid = obj.get("UID").unwrap_or("");
|
||||
let dtstamp = obj.get("DTSTAMP").unwrap_or("");
|
||||
let location = obj.get("LOCATION");
|
||||
let url = obj.get("URL");
|
||||
|
||||
let generate_event = |dtstart| {
|
||||
let id = format!("{}{}{}", uid, dtstart, dtstamp);
|
||||
Event {
|
||||
calendar: calendar.clone(),
|
||||
id,
|
||||
dtstart,
|
||||
dtend,
|
||||
summary: summary.to_owned(),
|
||||
location: location.clone(),
|
||||
url: url.clone(),
|
||||
}
|
||||
};
|
||||
|
||||
let rrule_str: Option<&str> = obj.get("rrule");
|
||||
let rrule = rrule_str.and_then(
|
||||
|rrule_str| RRule::from_str(
|
||||
&format!("DTSTART:{}\nRRULE:{}", dtstart_str, rrule_str)
|
||||
).map_err(|e| println!("Error parsing RRULE: {}", e))
|
||||
.ok()
|
||||
);
|
||||
match rrule {
|
||||
Some(rrule) => {
|
||||
let now = Utc::now();
|
||||
let start = now - Duration::days(RRULE_LOOKBACK);
|
||||
let end = now + Duration::days(RRULE_LOOKAHEAD);
|
||||
println!("rrule {}:\n{:?}", rrule_str.unwrap_or(""), rrule.into_iter()
|
||||
.skip_while(|d| *d < start)
|
||||
.take_while(|d| *d <= end)
|
||||
.map(|dtstart| dtstart.naive_utc())
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
rrule.into_iter()
|
||||
.skip_while(|d| *d < start)
|
||||
.take_while(|d| *d <= end)
|
||||
.map(|dtstart| dtstart.naive_utc())
|
||||
.map(generate_event)
|
||||
.collect()
|
||||
}
|
||||
None =>
|
||||
vec![generate_event(dtstart)],
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Resources {
|
||||
|
@ -105,13 +148,8 @@ impl Resources {
|
|||
let mut objs = vec![];
|
||||
extract_vevent_objs(&mut objs, obj);
|
||||
for obj in objs {
|
||||
if let Some(event) = obj_to_event(cal_id.to_owned(), &obj) {
|
||||
for event in obj_to_events(cal_id.to_owned(), &obj) {
|
||||
events.insert(event.id.clone(), event);
|
||||
} else {
|
||||
let dtstart: Option<&str> = obj.get("DTSTART");
|
||||
let summary: Option<&str> = obj.get("SUMMARY");
|
||||
println!("cannot convert {} {:?} {:?}",
|
||||
obj.name, dtstart, summary);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue