fancier error handling for config
This commit is contained in:
		
							parent
							
								
									e4be6d9588
								
							
						
					
					
						commit
						9a90b18caf
					
				
					 2 changed files with 67 additions and 39 deletions
				
			
		|  | @ -1,11 +1,14 @@ | |||
| use std::{ | ||||
|     env::{self, VarError}, | ||||
|     error::Error, | ||||
|     fmt::Debug, | ||||
|     path::PathBuf, | ||||
|     str::FromStr, | ||||
|     time::Duration, | ||||
| }; | ||||
| 
 | ||||
| use anyhow::{anyhow, Context}; | ||||
| 
 | ||||
| pub struct Config { | ||||
|     pub capture_images: bool, | ||||
|     pub capture_audio_duration: Option<f64>, | ||||
|  | @ -22,37 +25,62 @@ pub struct Config { | |||
| 
 | ||||
| const VAR_PREFIX: &str = "SCREENCAP_BOT_"; | ||||
| 
 | ||||
| fn get_var(name: &str) -> Result<String, VarError> { | ||||
|     env::var(VAR_PREFIX.to_string() + name) | ||||
| } | ||||
| 
 | ||||
| fn parse_var<E: Debug, T: FromStr<Err = E>>(name: &str) -> Result<T, VarError> { | ||||
|     get_var(name).map(|s| { | ||||
|         s.parse() | ||||
|             .unwrap_or_else(|e| panic!("Failed to parse {}{}: {:?}", VAR_PREFIX, name, e)) | ||||
|     }) | ||||
| } | ||||
| 
 | ||||
| fn expect_var(name: &str) -> String { | ||||
|     get_var(name).unwrap_or_else(|_| panic!("{}{} must be set", VAR_PREFIX, name)) | ||||
| } | ||||
| 
 | ||||
| pub fn load() -> Config { | ||||
|     let capture_images = parse_var("CAPTURE_IMAGES").unwrap_or(true); | ||||
| 
 | ||||
|     Config { | ||||
|         capture_images, | ||||
|         capture_audio_duration: parse_var("CAPTURE_AUDIO_DURATION").ok(), | ||||
|         shows_file: parse_var("SHOWS_FILE").unwrap_or(PathBuf::from("./shows.yaml")), | ||||
|         global_tags: get_var("GLOBAL_TAGS") | ||||
|             .map(|s| s.split(',').map(String::from).collect()) | ||||
|             .unwrap_or_default(), | ||||
|         post_interval: Duration::from_secs(parse_var("POST_INTERVAL").unwrap_or_default()), | ||||
|         cohost_email: expect_var("COHOST_EMAIL"), | ||||
|         cohost_password: expect_var("COHOST_PASSWORD"), | ||||
|         cohost_page: expect_var("COHOST_PAGE"), | ||||
|         cohost_draft: parse_var("COHOST_DRAFT").unwrap_or(false), | ||||
|         cohost_cw: parse_var("COHOST_CW").unwrap_or(capture_images), | ||||
|         eighteen_plus: parse_var("18PLUS").unwrap_or(false), | ||||
| fn get_var(name: &str) -> anyhow::Result<Option<String>> { | ||||
|     let var_name = VAR_PREFIX.to_string() + name; | ||||
|     match env::var(&var_name) { | ||||
|         Ok(v) => Ok(Some(v)), | ||||
|         Err(VarError::NotPresent) => Ok(None), | ||||
|         Err(e) => Err(e).with_context(|| format!("Failed to read variable {}", var_name)), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn parse_var<E: Debug + Send + Sync + Error + 'static, T: FromStr<Err = E>>( | ||||
|     name: &str, | ||||
| ) -> anyhow::Result<Option<T>> { | ||||
|     get_var(name)? | ||||
|         .map(|s| { | ||||
|             s.parse() | ||||
|                 .with_context(|| format!("Failed to parse variable {}{}", VAR_PREFIX, name)) | ||||
|         }) | ||||
|         .transpose() | ||||
| } | ||||
| 
 | ||||
| fn require_var(name: &str) -> anyhow::Result<String> { | ||||
|     get_var(name)?.ok_or_else(|| anyhow!("{}{} must be set", VAR_PREFIX, name)) | ||||
| } | ||||
| 
 | ||||
| pub fn load() -> anyhow::Result<Config> { | ||||
|     let capture_images = parse_var("CAPTURE_IMAGES")?.unwrap_or(true); | ||||
| 
 | ||||
|     let capture_audio_duration = parse_var("CAPTURE_AUDIO_DURATION")?; | ||||
|     if let Some(d) = capture_audio_duration { | ||||
|         if d <= 0.0 { | ||||
|             return Err(anyhow!( | ||||
|                 "{}CAPTURE_AUDIO_DURATION cannot be <= 0", | ||||
|                 VAR_PREFIX | ||||
|             )); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if let (false, None) = (capture_images, capture_audio_duration) { | ||||
|         return Err(anyhow!( | ||||
|             "At least one of image capture and audio capture must be enabled!" | ||||
|         )); | ||||
|     } | ||||
| 
 | ||||
|     Ok(Config { | ||||
|         capture_images, | ||||
|         capture_audio_duration, | ||||
|         shows_file: parse_var("SHOWS_FILE")?.unwrap_or_else(|| PathBuf::from("./shows.yaml")), | ||||
|         global_tags: get_var("GLOBAL_TAGS")? | ||||
|             .map(|s| s.split(',').map(String::from).collect()) | ||||
|             .unwrap_or_default(), | ||||
|         post_interval: Duration::from_secs(parse_var("POST_INTERVAL")?.unwrap_or_default()), | ||||
|         cohost_email: require_var("COHOST_EMAIL")?, | ||||
|         cohost_password: require_var("COHOST_PASSWORD")?, | ||||
|         cohost_page: require_var("COHOST_PAGE")?, | ||||
|         cohost_draft: parse_var("COHOST_DRAFT")?.unwrap_or(false), | ||||
|         cohost_cw: parse_var("COHOST_CW")?.unwrap_or(capture_images), | ||||
|         eighteen_plus: parse_var("18PLUS")?.unwrap_or(false), | ||||
|     }) | ||||
| } | ||||
|  |  | |||
							
								
								
									
										14
									
								
								src/main.rs
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								src/main.rs
									
										
									
									
									
								
							|  | @ -27,13 +27,7 @@ async fn main() -> anyhow::Result<()> { | |||
| 
 | ||||
|     let mut rng = rand::thread_rng(); | ||||
| 
 | ||||
|     let conf = config::load(); | ||||
| 
 | ||||
|     if let (false, None) = (conf.capture_images, conf.capture_audio_duration) { | ||||
|         return Err(anyhow!( | ||||
|             "At least one of image capture and audio capture must be enabled!" | ||||
|         )); | ||||
|     } | ||||
|     let conf = config::load()?; | ||||
| 
 | ||||
|     info!("Loading shows from {}", conf.shows_file.display()); | ||||
|     let shows = shows::load(&conf.shows_file).with_context(|| { | ||||
|  | @ -110,6 +104,12 @@ async fn post_random_capture<R: Rng>( | |||
|         Some(d) => media_info.duration_secs - d, | ||||
|         None => media_info.duration_secs, | ||||
|     }; | ||||
|     if max_timestamp < 0.0 { | ||||
|         return Err(anyhow!( | ||||
|             "Media file {} is too short to take audio clip!", | ||||
|             file.display() | ||||
|         )); | ||||
|     } | ||||
|     let timestamp = max_timestamp * rng.sample::<f64, _>(Standard); | ||||
|     let formatted_timestamp = format_timestamp(timestamp, Some(media_info.duration_secs)); | ||||
|     info!("Taking capture at {}", formatted_timestamp); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue