main: more date logic
This commit is contained in:
		
							parent
							
								
									e4aae07113
								
							
						
					
					
						commit
						88450b7a61
					
				
					 1 changed files with 75 additions and 49 deletions
				
			
		
							
								
								
									
										124
									
								
								src/main.rs
									
										
									
									
									
								
							
							
						
						
									
										124
									
								
								src/main.rs
									
										
									
									
									
								
							| 
						 | 
					@ -179,22 +179,23 @@ fn main() -> Result<(), Box<dyn Error>> {
 | 
				
			||||||
        &config["wiki-http-password"],
 | 
					        &config["wiki-http-password"],
 | 
				
			||||||
        is_dry_run(),
 | 
					        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
 | 
					    // figure out where we are
 | 
				
			||||||
    let mut last_state = ProgramState::parse(&config["state-name"]);
 | 
					    let mut last_state = ProgramState::parse(&config["state-name"]);
 | 
				
			||||||
    let last_run = config.get("state-last-run").unwrap_or_default();
 | 
					    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();
 | 
					    let last_run = NaiveDate::parse_from_str(&last_run, "%Y-%m-%d").unwrap_or_default();
 | 
				
			||||||
    // figure out where we should be
 | 
					    // figure out where we should be
 | 
				
			||||||
    let today = Local::now().date_naive();
 | 
					 | 
				
			||||||
    if (today - last_run).num_days() > 10 {
 | 
					    if (today - last_run).num_days() > 10 {
 | 
				
			||||||
        if !matches!(last_state, ProgramState::Normal) {
 | 
					        if !matches!(last_state, ProgramState::Normal) {
 | 
				
			||||||
            eprintln!("WARNING: last run was a long time ago, resetting state.");
 | 
					            eprintln!("WARNING: last run was a long time ago, resetting state.");
 | 
				
			||||||
            last_state = ProgramState::Normal;
 | 
					            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 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)
 | 
					    // deltas has either 2 or 3 days, if 3 then the middle one is == 0 (i.e. today)
 | 
				
			||||||
    let deltas: Vec<i64> = nearest_plenum_days.iter().map(|&d| (d - today).num_days()).collect();
 | 
					    let deltas: Vec<i64> = nearest_plenum_days.iter().map(|&d| (d - today).num_days()).collect();
 | 
				
			||||||
    // find the relevant one:
 | 
					    // find the relevant one:
 | 
				
			||||||
| 
						 | 
					@ -212,6 +213,7 @@ fn main() -> Result<(), Box<dyn Error>> {
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    .unwrap(); // always has at least 2 elems
 | 
					    .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 {
 | 
					    let intended_state = if delta > 3 {
 | 
				
			||||||
        ProgramState::Normal // nothing to do 3+ days in advance
 | 
					        ProgramState::Normal // nothing to do 3+ days in advance
 | 
				
			||||||
    } else if delta > 1 {
 | 
					    } else if delta > 1 {
 | 
				
			||||||
| 
						 | 
					@ -224,8 +226,8 @@ fn main() -> Result<(), Box<dyn Error>> {
 | 
				
			||||||
        ProgramState::Logged // after that, we want to log it to the list & the wiki
 | 
					        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()];
 | 
					    let action: TransitionFunction = TRANSITION_LUT[last_state as usize][intended_state as usize];
 | 
				
			||||||
    action(delta, &config, &hedgedoc, &email, &wiki)?;
 | 
					    action(delta, &plenum_day, &config, &hedgedoc, &email, &wiki)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // TODO: cleanup / write new state
 | 
					    // 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
 | 
					    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::<String>() + c.as_str(),
 | 
				
			||||||
 | 
					        None => String::new(),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ***** transition actions ***** */
 | 
					/* ***** transition actions ***** */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn do_announcement(
 | 
					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<dyn Error>> {
 | 
					) -> Result<(), Box<dyn Error>> {
 | 
				
			||||||
    // use TTP to adjust text if needed (in {ttp} days)
 | 
					    // use TTP to adjust text if needed (in {ttp} days)
 | 
				
			||||||
    todo!()
 | 
					    todo!()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn do_reminder(
 | 
					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<dyn Error>> {
 | 
					) -> Result<(), Box<dyn Error>> {
 | 
				
			||||||
    // use TTP to adjust text if needed (tomorrow or today / in {ttp} days)
 | 
					    // use TTP to adjust text if needed (tomorrow or today / in {ttp} days)
 | 
				
			||||||
    todo!()
 | 
					    todo!()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn do_protocol(
 | 
					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<dyn Error>> {
 | 
					) -> Result<(), Box<dyn Error>> {
 | 
				
			||||||
    // use TTP to adjust text if needed ({-ttp} days ago)
 | 
					    // use TTP to adjust text if needed ({-ttp} days ago)
 | 
				
			||||||
    todo!()
 | 
					    todo!()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// General cleanup function. Call as `(999, today, …)` for a complete reset
 | 
				
			||||||
 | 
					/// based on today as the base date.
 | 
				
			||||||
fn do_cleanup(
 | 
					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<dyn Error>> {
 | 
					) -> Result<(), Box<dyn Error>> {
 | 
				
			||||||
    todo!()
 | 
					    todo!()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -546,6 +579,7 @@ fn do_cleanup(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type TransitionFunction = fn(
 | 
					type TransitionFunction = fn(
 | 
				
			||||||
    ttp: i64,
 | 
					    ttp: i64,
 | 
				
			||||||
 | 
					    plenum_day: &NaiveDate,
 | 
				
			||||||
    config: &KV,
 | 
					    config: &KV,
 | 
				
			||||||
    hedgedoc: &HedgeDoc,
 | 
					    hedgedoc: &HedgeDoc,
 | 
				
			||||||
    email: &SimpleEmail,
 | 
					    email: &SimpleEmail,
 | 
				
			||||||
| 
						 | 
					@ -562,22 +596,22 @@ const TRANSITION_LUT: [[TransitionFunction; 5]; 5] = [
 | 
				
			||||||
    /* LOGGED    */ [do_cleanup, do_clean_announcement, do_clean_reminder, nop,     do_cleanup],
 | 
					    /* LOGGED    */ [do_cleanup, do_clean_announcement, do_clean_reminder, nop,     do_cleanup],
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn nop(_: i64, _: &KV, _: &HedgeDoc, _: &SimpleEmail, _: &Mediawiki) -> Result<(), Box<dyn Error>> {
 | 
					fn nop(_: i64, _: &NaiveDate, _: &KV, _: &HedgeDoc, _: &SimpleEmail, _: &Mediawiki) -> Result<(), Box<dyn Error>> {
 | 
				
			||||||
    Ok(())
 | 
					    Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn do_clean_announcement(
 | 
					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<dyn Error>> {
 | 
					) -> Result<(), Box<dyn Error>> {
 | 
				
			||||||
    do_cleanup(ttp, config, hedgedoc, email, wiki)?;
 | 
					    do_cleanup(ttp, plenum_day, config, hedgedoc, email, wiki)?;
 | 
				
			||||||
    do_announcement(ttp, config, hedgedoc, email, wiki)
 | 
					    do_announcement(ttp, plenum_day, config, hedgedoc, email, wiki)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn do_clean_reminder(
 | 
					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<dyn Error>> {
 | 
					) -> Result<(), Box<dyn Error>> {
 | 
				
			||||||
    do_cleanup(ttp, config, hedgedoc, email, wiki)?;
 | 
					    do_cleanup(ttp, plenum_day, config, hedgedoc, email, wiki)?;
 | 
				
			||||||
    do_reminder(ttp, 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
 | 
					/// 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)
 | 
					/// - Waiting – just a day of delay (after it makes sense to send a reminder)
 | 
				
			||||||
/// - Logged – protocol was written to wiki & mailing list
 | 
					/// - Logged – protocol was written to wiki & mailing list
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// The bot knows in which state it is at all times. It knows this because it
 | 
					/// > The bot knows in which state it is at all times. It knows this because
 | 
				
			||||||
/// knows in which state it isn't. By comparing where it is with where it
 | 
					/// > it knows in which state it isn't. By comparing where it is with where
 | 
				
			||||||
/// isn't, it obtains a difference, or deviation. The program logic uses
 | 
					/// > 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
 | 
					/// > 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
 | 
					/// > 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
 | 
					/// > 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
 | 
					/// > that it wasn't, and it follows that the state that it was in, is now the
 | 
				
			||||||
/// state that it isn't in.
 | 
					/// > state that it isn't in.
 | 
				
			||||||
///
 | 
					/// >
 | 
				
			||||||
/// In the event that the state that it is in is not the state that it wasn't,
 | 
					/// > 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
 | 
					/// > 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
 | 
					/// > 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.
 | 
					/// > to be a significant factor, it too may be corrected by the program logic.
 | 
				
			||||||
/// However, the bot must also know where it was.
 | 
					/// > However, the bot must also know where it was.
 | 
				
			||||||
///
 | 
					/// >
 | 
				
			||||||
/// The program logic works as follows. Because a delay has modified some
 | 
					/// > 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.
 | 
					/// > 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.
 | 
					/// > 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
 | 
					/// > 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,
 | 
					/// > 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,
 | 
					/// > and when it was, it is able to obtain the deviation and its variation,
 | 
				
			||||||
/// which is called error.
 | 
					/// > which is called error.
 | 
				
			||||||
 | 
					#[derive(Default, Debug)]
 | 
				
			||||||
enum ProgramState {
 | 
					enum ProgramState {
 | 
				
			||||||
    /// Normal is the default state, with no actions currently outstanding.
 | 
					    /// Normal is the default state, with no actions currently outstanding.
 | 
				
			||||||
 | 
					    #[default]
 | 
				
			||||||
    Normal,
 | 
					    Normal,
 | 
				
			||||||
    /// There is an upcoming event, and the first announcement has been sent.
 | 
					    /// There is an upcoming event, and the first announcement has been sent.
 | 
				
			||||||
    Announced,
 | 
					    Announced,
 | 
				
			||||||
| 
						 | 
					@ -636,16 +672,6 @@ impl ProgramState {
 | 
				
			||||||
            _ => ProgramState::Normal,
 | 
					            _ => 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 {
 | 
					impl std::fmt::Display for ProgramState {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue