➕ offset feature
							parent
							
								
									0a73740b16
								
							
						
					
					
						commit
						bb619b2452
					
				|  | @ -7,6 +7,9 @@ type Result <T> = std::result::Result <T, crate::error::Error>; | ||||||
| pub struct Config { | pub struct Config { | ||||||
| 	pub interval_secs: u64, | 	pub interval_secs: u64, | ||||||
| 	pub prompt: String, | 	pub prompt: String, | ||||||
|  | 	
 | ||||||
|  | 	// Open dev tools in a web browser and run `Math.random () * 2225`
 | ||||||
|  | 	pub offset_secs: u64, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Default for Config { | impl Default for Config { | ||||||
|  | @ -14,6 +17,7 @@ impl Default for Config { | ||||||
| 		Self { | 		Self { | ||||||
| 			interval_secs: 2225, | 			interval_secs: 2225, | ||||||
| 			prompt: "Write a journal entry, then hit Tab, Enter to submit it.".into (), | 			prompt: "Write a journal entry, then hit Tab, Enter to submit it.".into (), | ||||||
|  | 			offset_secs: 0, | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -35,6 +39,11 @@ impl Config { | ||||||
| 				let val = u64::from_str (&val).map_err (|_| CannotParseArg ("--interval-secs <u64>"))?; | 				let val = u64::from_str (&val).map_err (|_| CannotParseArg ("--interval-secs <u64>"))?; | ||||||
| 				that.interval_secs = val; | 				that.interval_secs = val; | ||||||
| 			} | 			} | ||||||
|  | 			else if arg == "--offset-secs" { | ||||||
|  | 				let val = args.next ().ok_or (ParamNeedsArg ("--offset-secs"))?; | ||||||
|  | 				let val = u64::from_str (&val).map_err (|_| CannotParseArg ("--offset-secs <u64>"))?; | ||||||
|  | 				that.offset_secs = val; | ||||||
|  | 			} | ||||||
| 			else if arg == "--prompt" { | 			else if arg == "--prompt" { | ||||||
| 				let val = args.next ().ok_or (ParamNeedsArg ("--prompt"))?; | 				let val = args.next ().ok_or (ParamNeedsArg ("--prompt"))?; | ||||||
| 				that.prompt = val; | 				that.prompt = val; | ||||||
|  | @ -44,3 +53,11 @@ impl Config { | ||||||
| 		Ok (that) | 		Ok (that) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | #[cfg (test)] | ||||||
|  | mod test { | ||||||
|  | 	#[test] | ||||||
|  | 	fn parse () { | ||||||
|  | 		
 | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										11
									
								
								src/main.rs
								
								
								
								
							
							
						
						
									
										11
									
								
								src/main.rs
								
								
								
								
							|  | @ -21,12 +21,13 @@ use tokio::{ | ||||||
| 	io::AsyncWriteExt, | 	io::AsyncWriteExt, | ||||||
| 	time::{ | 	time::{ | ||||||
| 		Duration, | 		Duration, | ||||||
| 		interval, | 		interval_at, | ||||||
| 	}, | 	}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| mod config; | mod config; | ||||||
| mod error; | mod error; | ||||||
|  | mod offset; | ||||||
| 
 | 
 | ||||||
| use config::Config; | use config::Config; | ||||||
| use error::Error; | use error::Error; | ||||||
|  | @ -40,7 +41,13 @@ async fn main () -> Result <(), Error> { | ||||||
| 	let app = app::App::default (); | 	let app = app::App::default (); | ||||||
| 	
 | 	
 | ||||||
| 	tokio::spawn (async move { | 	tokio::spawn (async move { | ||||||
| 		let mut i = interval (Duration::from_secs (config.interval_secs)); | 		let mut i = interval_at ( | ||||||
|  | 			offset::get_next_tick ( | ||||||
|  | 				config.interval_secs, | ||||||
|  | 				config.offset_secs, | ||||||
|  | 			).into (), | ||||||
|  | 			Duration::from_secs (config.interval_secs), | ||||||
|  | 		); | ||||||
| 		i.set_missed_tick_behavior (tokio::time::MissedTickBehavior::Skip); | 		i.set_missed_tick_behavior (tokio::time::MissedTickBehavior::Skip); | ||||||
| 		
 | 		
 | ||||||
| 		loop { | 		loop { | ||||||
|  |  | ||||||
|  | @ -0,0 +1,33 @@ | ||||||
|  | use std::{ | ||||||
|  | 	time::{ | ||||||
|  | 		Duration, | ||||||
|  | 		Instant, | ||||||
|  | 		SystemTime, | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | pub fn get_next_tick (interval_secs: u64, offset_secs: u64) -> Instant { | ||||||
|  | 	let now_sys = SystemTime::now (); | ||||||
|  | 	let now_mono = Instant::now (); | ||||||
|  | 	
 | ||||||
|  | 	let phase = get_phase (now_sys, interval_secs, offset_secs); | ||||||
|  | 	now_mono.checked_add (Duration::from_millis (interval_secs * 1000 - u64::try_from (phase).unwrap ())).unwrap () | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn get_phase (now: SystemTime, interval_secs: u64, offset_secs: u64) -> u64 { | ||||||
|  | 	let ms_since_epoch = now.duration_since (SystemTime::UNIX_EPOCH).unwrap ().as_millis (); | ||||||
|  | 	u64::try_from ((ms_since_epoch + u128::from (offset_secs) * 1000) % (u128::from (interval_secs) * 1000)).unwrap () | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[cfg (test)] | ||||||
|  | mod test { | ||||||
|  | 	use super::*; | ||||||
|  | 	
 | ||||||
|  | 	#[test] | ||||||
|  | 	fn test () { | ||||||
|  | 		let now = SystemTime::UNIX_EPOCH.checked_add (Duration::from_secs (1649201544)).unwrap (); | ||||||
|  | 		
 | ||||||
|  | 		assert_eq! (get_phase (now, 2225, 0), 394000); | ||||||
|  | 		assert_eq! (get_phase (now, 2225, 30), 424000); | ||||||
|  | 	} | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	 _
						_