Generalize notification handling

This commit is contained in:
Michael Vines
2021-01-19 09:20:25 -08:00
parent dcaa025822
commit 332371635d

View File

@ -75,12 +75,16 @@ fn get_twilio_config() -> Result<Option<TwilioWebHook>, String> {
Ok(Some(config)) Ok(Some(config))
} }
enum NotificationType {
Discord(String),
Slack(String),
Telegram(TelegramWebHook),
Twilio(TwilioWebHook),
}
pub struct Notifier { pub struct Notifier {
client: Client, client: Client,
discord_webhook: Option<String>, notifiers: Vec<NotificationType>,
slack_webhook: Option<String>,
telegram_webhook: Option<TelegramWebHook>,
twilio_webhook: Option<TwilioWebHook>,
} }
impl Notifier { impl Notifier {
@ -91,99 +95,103 @@ impl Notifier {
pub fn new(env_prefix: &str) -> Self { pub fn new(env_prefix: &str) -> Self {
info!("Initializing {}Notifier", env_prefix); info!("Initializing {}Notifier", env_prefix);
let discord_webhook = env::var(format!("{}DISCORD_WEBHOOK", env_prefix)) let mut notifiers = vec![];
.map_err(|_| {
info!("Discord notifications disabled");
})
.ok();
let slack_webhook = env::var(format!("{}SLACK_WEBHOOK", env_prefix))
.map_err(|_| {
info!("Slack notifications disabled");
})
.ok();
let telegram_webhook = if let (Ok(bot_token), Ok(chat_id)) = ( if let Ok(webhook) = env::var(format!("{}DISCORD_WEBHOOK", env_prefix)) {
notifiers.push(NotificationType::Discord(webhook));
}
if let Ok(webhook) = env::var(format!("{}SLACK_WEBHOOK", env_prefix)) {
notifiers.push(NotificationType::Slack(webhook));
}
if let (Ok(bot_token), Ok(chat_id)) = (
env::var(format!("{}TELEGRAM_BOT_TOKEN", env_prefix)), env::var(format!("{}TELEGRAM_BOT_TOKEN", env_prefix)),
env::var(format!("{}TELEGRAM_CHAT_ID", env_prefix)), env::var(format!("{}TELEGRAM_CHAT_ID", env_prefix)),
) { ) {
Some(TelegramWebHook { bot_token, chat_id }) notifiers.push(NotificationType::Telegram(TelegramWebHook {
} else { bot_token,
info!("Telegram notifications disabled"); chat_id,
None }));
}; }
let twilio_webhook = get_twilio_config()
.map_err(|err| panic!("Twilio config error: {}", err)) if let Ok(Some(webhook)) = get_twilio_config() {
.unwrap(); notifiers.push(NotificationType::Twilio(webhook));
}
info!("{} notifiers", notifiers.len());
Notifier { Notifier {
client: Client::new(), client: Client::new(),
discord_webhook, notifiers,
slack_webhook,
telegram_webhook,
twilio_webhook,
} }
} }
pub fn is_empty(&self) -> bool {
self.notifiers.is_empty()
}
pub fn send(&self, msg: &str) { pub fn send(&self, msg: &str) {
if let Some(webhook) = &self.discord_webhook { for notifier in &self.notifiers {
for line in msg.split('\n') { match notifier {
// Discord rate limiting is aggressive, limit to 1 message a second NotificationType::Discord(webhook) => {
sleep(Duration::from_millis(1000)); for line in msg.split('\n') {
// Discord rate limiting is aggressive, limit to 1 message a second
sleep(Duration::from_millis(1000));
info!("Sending {}", line); info!("Sending {}", line);
let data = json!({ "content": line }); let data = json!({ "content": line });
loop { loop {
let response = self.client.post(webhook).json(&data).send(); let response = self.client.post(webhook).json(&data).send();
if let Err(err) = response { if let Err(err) = response {
warn!("Failed to send Discord message: \"{}\": {:?}", line, err); warn!("Failed to send Discord message: \"{}\": {:?}", line, err);
break; break;
} else if let Ok(response) = response { } else if let Ok(response) = response {
info!("response status: {}", response.status()); info!("response status: {}", response.status());
if response.status() == StatusCode::TOO_MANY_REQUESTS { if response.status() == StatusCode::TOO_MANY_REQUESTS {
warn!("rate limited!..."); warn!("rate limited!...");
warn!("response text: {:?}", response.text()); warn!("response text: {:?}", response.text());
sleep(Duration::from_secs(2)); sleep(Duration::from_secs(2));
} else { } else {
break; break;
}
}
} }
} }
} }
NotificationType::Slack(webhook) => {
let data = json!({ "text": msg });
if let Err(err) = self.client.post(webhook).json(&data).send() {
warn!("Failed to send Slack message: {:?}", err);
}
}
NotificationType::Telegram(TelegramWebHook { chat_id, bot_token }) => {
let data = json!({ "chat_id": chat_id, "text": msg });
let url = format!("https://api.telegram.org/bot{}/sendMessage", bot_token);
if let Err(err) = self.client.post(&url).json(&data).send() {
warn!("Failed to send Telegram message: {:?}", err);
}
}
NotificationType::Twilio(TwilioWebHook {
account,
token,
to,
from,
}) => {
let url = format!(
"https://{}:{}@api.twilio.com/2010-04-01/Accounts/{}/Messages.json",
account, token, account
);
let params = [("To", to), ("From", from), ("Body", &msg.to_string())];
if let Err(err) = self.client.post(&url).form(&params).send() {
warn!("Failed to send Twilio message: {:?}", err);
}
}
} }
} }
if let Some(webhook) = &self.slack_webhook {
let data = json!({ "text": msg });
if let Err(err) = self.client.post(webhook).json(&data).send() {
warn!("Failed to send Slack message: {:?}", err);
}
}
if let Some(TelegramWebHook { chat_id, bot_token }) = &self.telegram_webhook {
let data = json!({ "chat_id": chat_id, "text": msg });
let url = format!("https://api.telegram.org/bot{}/sendMessage", bot_token);
if let Err(err) = self.client.post(&url).json(&data).send() {
warn!("Failed to send Telegram message: {:?}", err);
}
}
if let Some(TwilioWebHook {
account,
token,
to,
from,
}) = &self.twilio_webhook
{
let url = format!(
"https://{}:{}@api.twilio.com/2010-04-01/Accounts/{}/Messages.json",
account, token, account
);
let params = [("To", to), ("From", from), ("Body", &msg.to_string())];
if let Err(err) = self.client.post(&url).form(&params).send() {
warn!("Failed to send Twilio message: {:?}", err);
}
}
} }
} }