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"], | ||||
|         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 { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 nobody
						nobody