diff options
| author | Gustav Sörnäs <gustav@sornas.net> | 2020-11-22 22:57:40 +0100 |
|---|---|---|
| committer | Gustav Sörnäs <gustav@sornas.net> | 2020-11-22 22:58:57 +0100 |
| commit | 3e9712c3782fc9c1450738236c234c63022acd11 (patch) | |
| tree | 3f259dbfbea22ab2d31938fc202b13c786e7ae46 /src | |
| parent | e96b3d9631ce61a7d2d97290e00334e80840fbba (diff) | |
| download | kodapa-3e9712c3782fc9c1450738236c234c63022acd11.tar.gz | |
implement reminders with hard-coded meeting time
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.rs | 1 | ||||
| -rw-r--r-- | src/reminder.rs | 106 |
2 files changed, 107 insertions, 0 deletions
diff --git a/src/main.rs b/src/main.rs index 47daed8..6bd2de5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ mod agenda; mod discord; +mod reminder; mod slack; use crate::agenda::AgendaPoint; diff --git a/src/reminder.rs b/src/reminder.rs new file mode 100644 index 0000000..20e8fb8 --- /dev/null +++ b/src/reminder.rs @@ -0,0 +1,106 @@ +use chrono::{DateTime, Datelike, Duration, Local, NaiveTime, Weekday}; +use serde::{Deserialize, Serialize}; +use std::fs; +use tokio::sync::watch; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum ReminderType { + // Different types of reminders are possible. + // e.g. different reminders for the day before and one hour before. + Void, + OneHour, //TODO struct instead +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Reminder { + reminder_type: ReminderType, + last_fire: DateTime<Local>, +} + +#[derive(Serialize, Deserialize)] +pub struct Reminders { + reminders: Vec<Reminder>, +} + +impl Reminders { + fn write(&self) { + fs::write( + std::path::Path::new("reminders.json"), + serde_json::to_string_pretty(&self).expect("Can't serialize reminders"), + ) + .expect("Can't write reminders.json") + } +} + +pub async fn handle(sender: watch::Sender<ReminderType>) { + let mut interval = tokio::time::interval(tokio::time::Duration::from_millis(1000)); + + let now = Local::now(); + let next = next_meeting(); + let mut reminders = read_reminders(); + for mut reminder in &mut reminders.reminders { + match reminder.reminder_type { + ReminderType::OneHour => { + if in_remind_zone(now, next) && !in_remind_zone(reminder.last_fire, next) { + sender.broadcast(ReminderType::OneHour).unwrap(); + reminder.last_fire = now; + } + }, + _ => {}, + } + } + reminders.write(); + + loop { + interval.tick().await; + } +} + +fn read_reminders() -> Reminders { + serde_json::from_str( + &fs::read_to_string("reminders.json").expect("Can't read reminders.json") + ) + .expect("Error parsing reminders.json") +} + +fn in_remind_zone(dt: DateTime<Local>, meeting: DateTime<Local>) -> bool { + // Wether we're in a "send reminder"-zone. + // Currently implemented as "are we 1 hour before?". + ((meeting - Duration::hours(1))..meeting).contains(&dt) +} + +fn next_meeting() -> DateTime<Local> { + // Check current datetime and calculate when the next meeting is. + let now = Local::now(); + let meeting_time = NaiveTime::from_hms(12, 15, 00); + let meeting = match Datelike::weekday(&now) { + Weekday::Thu => { + // same day as meeting. + // next week if meeting has occured. + let date_delta = Duration::weeks( + if now.time() < meeting_time { 0 } else { 1 } + ); + (now.date() + date_delta).and_time(meeting_time).unwrap() + }, + _ => { + let dow_index: i64 = now.date().weekday().num_days_from_monday().into(); + let date_delta = Duration::days((3 - dow_index).rem_euclid(7)); + (now.date() + date_delta).and_time(meeting_time).unwrap() + }, + }; + assert!(meeting.weekday() == Weekday::Thu); + meeting +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn in_remind_zone() { + let now = Local::now(); + assert!(super::in_remind_zone(now, now + Duration::minutes(30))); + assert!(!super::in_remind_zone(now, now + Duration::hours(2))); + assert!(!super::in_remind_zone(now, now - Duration::minutes(30))); + } +} |
