main: more date logic
This commit is contained in:
parent
e4aae07113
commit
88450b7a61
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…
Reference in a new issue