Browse Source

ticker-update: use rrule

master
Astro 5 months ago
parent
commit
d6370aa55d
  1. 33
      Cargo.lock
  2. 4
      default.nix
  3. 1
      ticker-update/Cargo.toml
  4. 88
      ticker-update/src/main.rs

33
Cargo.lock

@ -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]]

4
default.nix

@ -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}

1
ticker-update/Cargo.toml

@ -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" }

88
ticker-update/src/main.rs

@ -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…
Cancel
Save