main: more date logic

This commit is contained in:
nobody 2024-08-17 06:42:12 +02:00 committed by murmeldin
parent e4aae07113
commit 88450b7a61

View file

@ -179,22 +179,23 @@ fn main() -> Result<(), Box<dyn Error>> {
&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<i64> = nearest_plenum_days.iter().map(|&d| (d - today).num_days()).collect();
// find the relevant one:
@ -212,6 +213,7 @@ fn main() -> Result<(), Box<dyn Error>> {
},
}
.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<dyn Error>> {
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::<String>() + 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<dyn Error>> {
// 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<dyn Error>> {
// 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<dyn Error>> {
// 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<dyn Error>> {
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<dyn Error>> {
fn nop(_: i64, _: &NaiveDate, _: &KV, _: &HedgeDoc, _: &SimpleEmail, _: &Mediawiki) -> Result<(), Box<dyn Error>> {
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<dyn Error>> {
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<dyn Error>> {
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 {