fancier error handling for config
This commit is contained in:
parent
e4be6d9588
commit
9a90b18caf
|
@ -1,11 +1,14 @@
|
||||||
use std::{
|
use std::{
|
||||||
env::{self, VarError},
|
env::{self, VarError},
|
||||||
|
error::Error,
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Context};
|
||||||
|
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub capture_images: bool,
|
pub capture_images: bool,
|
||||||
pub capture_audio_duration: Option<f64>,
|
pub capture_audio_duration: Option<f64>,
|
||||||
|
@ -22,37 +25,62 @@ pub struct Config {
|
||||||
|
|
||||||
const VAR_PREFIX: &str = "SCREENCAP_BOT_";
|
const VAR_PREFIX: &str = "SCREENCAP_BOT_";
|
||||||
|
|
||||||
fn get_var(name: &str) -> Result<String, VarError> {
|
fn get_var(name: &str) -> anyhow::Result<Option<String>> {
|
||||||
env::var(VAR_PREFIX.to_string() + name)
|
let var_name = VAR_PREFIX.to_string() + name;
|
||||||
}
|
match env::var(&var_name) {
|
||||||
|
Ok(v) => Ok(Some(v)),
|
||||||
fn parse_var<E: Debug, T: FromStr<Err = E>>(name: &str) -> Result<T, VarError> {
|
Err(VarError::NotPresent) => Ok(None),
|
||||||
get_var(name).map(|s| {
|
Err(e) => Err(e).with_context(|| format!("Failed to read variable {}", var_name)),
|
||||||
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 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 mut rng = rand::thread_rng();
|
||||||
|
|
||||||
let conf = config::load();
|
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!"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
info!("Loading shows from {}", conf.shows_file.display());
|
info!("Loading shows from {}", conf.shows_file.display());
|
||||||
let shows = shows::load(&conf.shows_file).with_context(|| {
|
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,
|
Some(d) => media_info.duration_secs - d,
|
||||||
None => media_info.duration_secs,
|
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 timestamp = max_timestamp * rng.sample::<f64, _>(Standard);
|
||||||
let formatted_timestamp = format_timestamp(timestamp, Some(media_info.duration_secs));
|
let formatted_timestamp = format_timestamp(timestamp, Some(media_info.duration_secs));
|
||||||
info!("Taking capture at {}", formatted_timestamp);
|
info!("Taking capture at {}", formatted_timestamp);
|
||||||
|
|
Loading…
Reference in a new issue