diff --git a/src/main.rs b/src/main.rs index a156f21..4d9cb08 100644 --- a/src/main.rs +++ b/src/main.rs @@ -179,22 +179,23 @@ fn main() -> Result<(), Box> { &config["wiki-http-password"], is_dry_run(), ); + // get next plenum days + let today = Local::now().date_naive(); + let plenum_spec = date::parse_spec(&config["date-spec"])?; + let nearest_plenum_days = date::get_matching_dates_around(today, plenum_spec); // figure out where we are let mut last_state = ProgramState::parse(&config["state-name"]); let last_run = config.get("state-last-run").unwrap_or_default(); let last_run = NaiveDate::parse_from_str(&last_run, "%Y-%m-%d").unwrap_or_default(); // figure out where we should be - let today = Local::now().date_naive(); if (today - last_run).num_days() > 10 { if !matches!(last_state, ProgramState::Normal) { eprintln!("WARNING: last run was a long time ago, resetting state."); last_state = ProgramState::Normal; - do_cleanup(999, &config, &hedgedoc, &email, &wiki)?; + do_cleanup(999, &today, &config, &hedgedoc, &email, &wiki)?; } } let last_state = last_state; - let plenum_spec = date::parse_spec(&config["date-spec"])?; - let nearest_plenum_days = date::get_matching_dates_around(today, plenum_spec); // deltas has either 2 or 3 days, if 3 then the middle one is == 0 (i.e. today) let deltas: Vec = nearest_plenum_days.iter().map(|&d| (d - today).num_days()).collect(); // find the relevant one: @@ -212,6 +213,7 @@ fn main() -> Result<(), Box> { }, } .unwrap(); // always has at least 2 elems + let plenum_day = today.checked_add_signed(chrono::TimeDelta::days(delta)).unwrap(); let intended_state = if delta > 3 { ProgramState::Normal // nothing to do 3+ days in advance } else if delta > 1 { @@ -224,8 +226,8 @@ fn main() -> Result<(), Box> { ProgramState::Logged // after that, we want to log it to the list & the wiki }; - let action: TransitionFunction = TRANSITION_LUT[last_state.index()][intended_state.index()]; - action(delta, &config, &hedgedoc, &email, &wiki)?; + let action: TransitionFunction = TRANSITION_LUT[last_state as usize][intended_state as usize]; + action(delta, &plenum_day, &config, &hedgedoc, &email, &wiki)?; // TODO: cleanup / write new state @@ -513,31 +515,62 @@ fn try_to_remove_top_instructions(pad_content: String) -> String { result.to_string() // Wenn es nicht geklappt hat, wird einfach das Pad mit dem Kommentar zurückgegeben } +/* ***** formatting helpers ***** */ + +fn relative_date( ttp: i64 ) -> String { + if ttp.abs() > 2 { + if ttp.is_negative() { + format!( "vor {} Tagen", -ttp ) + } else { + format!( "in {} Tagen", ttp ) + } + } else { + match ttp { + 2 => "übermorgen", + 1 => "morgen", + 0 => "heute", + -1 => "gestern", + -2 => "vorgestern", + _ => unreachable!(), + }.to_string() + } +} + +fn upper_first(s: &str) -> String { + let mut c = s.chars(); + match c.next() { + Some(fst) => fst.to_uppercase().collect::() + c.as_str(), + None => String::new(), + } +} + /* ***** transition actions ***** */ fn do_announcement( - ttp: i64, config: &KV, hedgedoc: &HedgeDoc, email: &SimpleEmail, wiki: &Mediawiki, + ttp: i64, plenum_day: &NaiveDate, config: &KV, hedgedoc: &HedgeDoc, email: &SimpleEmail, wiki: &Mediawiki, ) -> Result<(), Box> { // use TTP to adjust text if needed (in {ttp} days) todo!() } fn do_reminder( - ttp: i64, config: &KV, hedgedoc: &HedgeDoc, email: &SimpleEmail, wiki: &Mediawiki, + ttp: i64, plenum_day: &NaiveDate, config: &KV, hedgedoc: &HedgeDoc, email: &SimpleEmail, wiki: &Mediawiki, ) -> Result<(), Box> { // use TTP to adjust text if needed (tomorrow or today / in {ttp} days) todo!() } fn do_protocol( - ttp: i64, config: &KV, hedgedoc: &HedgeDoc, email: &SimpleEmail, wiki: &Mediawiki, + ttp: i64, plenum_day: &NaiveDate, config: &KV, hedgedoc: &HedgeDoc, email: &SimpleEmail, wiki: &Mediawiki, ) -> Result<(), Box> { // use TTP to adjust text if needed ({-ttp} days ago) todo!() } +/// General cleanup function. Call as `(999, today, …)` for a complete reset +/// based on today as the base date. fn do_cleanup( - ttp: i64, config: &KV, hedgedoc: &HedgeDoc, email: &SimpleEmail, wiki: &Mediawiki, + ttp: i64, plenum_day: &NaiveDate, config: &KV, hedgedoc: &HedgeDoc, email: &SimpleEmail, wiki: &Mediawiki, ) -> Result<(), Box> { todo!() } @@ -546,6 +579,7 @@ fn do_cleanup( type TransitionFunction = fn( ttp: i64, + plenum_day: &NaiveDate, config: &KV, hedgedoc: &HedgeDoc, email: &SimpleEmail, @@ -562,22 +596,22 @@ const TRANSITION_LUT: [[TransitionFunction; 5]; 5] = [ /* LOGGED */ [do_cleanup, do_clean_announcement, do_clean_reminder, nop, do_cleanup], ]; -fn nop(_: i64, _: &KV, _: &HedgeDoc, _: &SimpleEmail, _: &Mediawiki) -> Result<(), Box> { +fn nop(_: i64, _: &NaiveDate, _: &KV, _: &HedgeDoc, _: &SimpleEmail, _: &Mediawiki) -> Result<(), Box> { Ok(()) } fn do_clean_announcement( - ttp: i64, config: &KV, hedgedoc: &HedgeDoc, email: &SimpleEmail, wiki: &Mediawiki, + ttp: i64, plenum_day: &NaiveDate, config: &KV, hedgedoc: &HedgeDoc, email: &SimpleEmail, wiki: &Mediawiki, ) -> Result<(), Box> { - do_cleanup(ttp, config, hedgedoc, email, wiki)?; - do_announcement(ttp, config, hedgedoc, email, wiki) + do_cleanup(ttp, plenum_day, config, hedgedoc, email, wiki)?; + do_announcement(ttp, plenum_day, config, hedgedoc, email, wiki) } fn do_clean_reminder( - ttp: i64, config: &KV, hedgedoc: &HedgeDoc, email: &SimpleEmail, wiki: &Mediawiki, + ttp: i64, plenum_day: &NaiveDate, config: &KV, hedgedoc: &HedgeDoc, email: &SimpleEmail, wiki: &Mediawiki, ) -> Result<(), Box> { - do_cleanup(ttp, config, hedgedoc, email, wiki)?; - do_reminder(ttp, config, hedgedoc, email, wiki) + do_cleanup(ttp, plenum_day, config, hedgedoc, email, wiki)?; + do_reminder(ttp, plenum_day, config, hedgedoc, email, wiki) } /// State machine type for the announcement logic, ensuring we can deal with @@ -590,30 +624,32 @@ fn do_clean_reminder( /// - Waiting – just a day of delay (after it makes sense to send a reminder) /// - Logged – protocol was written to wiki & mailing list /// -/// The bot knows in which state it is at all times. It knows this because it -/// knows in which state it isn't. By comparing where it is with where it -/// isn't, it obtains a difference, or deviation. The program logic uses -/// deviations to generate corrective commands to drive the bot from a state -/// where it is to a state where it isn't, and arriving in a state where it -/// wasn't, it now is. Consequently, the state where it is, is now the state -/// that it wasn't, and it follows that the state that it was in, is now the -/// state that it isn't in. -/// -/// In the event that the state that it is in is not the state that it wasn't, -/// the system has acquired a variation, the variation being the difference -/// between where the bot is, and where it wasn't. If variation is considered -/// to be a significant factor, it too may be corrected by the program logic. -/// However, the bot must also know where it was. -/// -/// The program logic works as follows. Because a delay has modified some -/// of the information the bot has obtained, it is not sure just when it is. -/// However, it is sure when it isn't, within reason, and it knows when it was. -/// It now subtracts when it should be from when it wasn't, or vice-versa, and -/// by differentiating this from the algebraic sum of when it shouldn't be, -/// and when it was, it is able to obtain the deviation and its variation, -/// which is called error. +/// > The bot knows in which state it is at all times. It knows this because +/// > it knows in which state it isn't. By comparing where it is with where +/// > it isn't, it obtains a difference, or deviation. The program logic uses +/// > deviations to generate corrective commands to drive the bot from a state +/// > where it is to a state where it isn't, and arriving in a state where it +/// > wasn't, it now is. Consequently, the state where it is, is now the state +/// > that it wasn't, and it follows that the state that it was in, is now the +/// > state that it isn't in. +/// > +/// > In the event that the state that it is in is not the state that it wasn't, +/// > the system has acquired a variation, the variation being the difference +/// > between where the bot is, and where it wasn't. If variation is considered +/// > to be a significant factor, it too may be corrected by the program logic. +/// > However, the bot must also know where it was. +/// > +/// > The program logic works as follows. Because a delay has modified some +/// > of the information the bot has obtained, it is not sure just when it is. +/// > However, it is sure when it isn't, within reason, and it knows when it was. +/// > It now subtracts when it should be from when it wasn't, or vice-versa, and +/// > by differentiating this from the algebraic sum of when it shouldn't be, +/// > and when it was, it is able to obtain the deviation and its variation, +/// > which is called error. +#[derive(Default, Debug)] enum ProgramState { /// Normal is the default state, with no actions currently outstanding. + #[default] Normal, /// There is an upcoming event, and the first announcement has been sent. Announced, @@ -636,16 +672,6 @@ impl ProgramState { _ => ProgramState::Normal, } } - - fn index(&self) -> usize { - match self { - ProgramState::Normal => 0, - ProgramState::Announced => 1, - ProgramState::Reminded => 2, - ProgramState::Waiting => 3, - ProgramState::Logged => 4, - } - } } impl std::fmt::Display for ProgramState {