use clap::Parser;
use forge_backup::{
args::Args,
backup,
config::Config,
error::{AppResult, MailerError},
mailer::MailgunMailer,
};
use std::io::{self, Write};
use which::which;
#[tokio::main]
async fn main() {
let args = Args::parse();
if !check_prerequisites() {
println!("Ensure that zip and aws are both installed an in the PATH");
std::process::exit(1);
}
let mut config = match Config::load() {
Ok(config) => config,
Err(error) => {
eprintln!("ERROR: Unable to load config");
eprintln!("{error}");
let config = Config::fallback();
println!("Using fallback config: \n{config}");
config
}
};
config.update_from_args(args);
println!("Starting backup...");
io::stdout().flush().unwrap();
match backup::run(&config) {
Ok((successes, errors)) => {
if config.notify_on_success {
match send_email(&successes, &errors, &config).await {
Ok(_) => println!("Email sent."),
Err(_) => eprintln!("Error sending email."),
}
} else {
eprintln!("\nSuccessful: \n{successes}");
eprintln!("\nErrors: \n{errors}");
}
}
Err(e) => {
eprintln!("Error Returned.");
eprintln!("{e}");
}
}
}
async fn send_email(success: &str, errors: &str, config: &Config) -> AppResult<()> {
if !config.mailgun_api_base.starts_with("http") {
return Err(
MailerError::ConfigError("api_base does not start with http".to_owned()).into(),
);
}
if config
.mailgun_api_base
.chars()
.filter(|c| *c == '.')
.count()
== 0
{
return Err(
MailerError::ConfigError("api_base does not contain any dots".to_owned()).into(),
);
}
if config.mailgun_api_key.len() < 35 {
return Err(MailerError::ConfigError("api_key is too short".to_owned()).into());
}
if config.mailgun_domain.chars().filter(|c| *c == '.').count() == 0 {
return Err(MailerError::ConfigError(
"mailgun_domain does not contain any dots".to_owned(),
)
.into());
}
let mailer = MailgunMailer::create(config);
let subject = if errors.is_empty() {
format!("SUCCESS: {} - Backup Successful", config.hostname)
} else {
format!("ERROR: {} - Backup had error(s).", config.hostname)
};
let mut body = String::new();
body.push_str(format!("HOSTNAME: {}\n\nForge backup status\n\n", config.hostname).as_str());
body.push_str(format!("SUCESS:\n{success}\n\nERROR:\n{errors}\n\n").as_str());
mailer.send(&subject, &body).await?;
Ok(())
}
fn check_prerequisites() -> bool {
let prereqs = ["zip", "aws"];
let mut passed = true;
prereqs.iter().for_each(|&cmd| {
if which(cmd).is_err() {
println!("Missing prerequisite: '{cmd}'");
passed = false;
}
});
passed
}