#![warn(clippy::cargo, clippy::nursery, clippy::pedantic, clippy::restriction)]
#![allow(
clippy::blanket_clippy_restriction_lints,
clippy::single_char_lifetime_names,
clippy::missing_inline_in_public_items,
clippy::implicit_return,
clippy::pattern_type_mismatch
)]
use std::{
fmt::{Display, Write},
fs::OpenOptions,
io::Write as _,
path::PathBuf,
};
use twilight_http::Client;
use twilight_model::id::{
marker::{ChannelMarker, WebhookMarker},
Id,
};
pub struct ErrorHandler {
channel: Option<Id<ChannelMarker>>,
webhook: Option<(Id<WebhookMarker>, String)>,
file: Option<PathBuf>,
}
pub const DEFAULT_ERROR_MESSAGE: &str = "An error occurred, check the `stderr` for more info";
impl ErrorHandler {
#[must_use]
pub const fn new() -> Self {
Self {
channel: None,
webhook: None,
file: None,
}
}
pub fn channel(&mut self, channel_id: Id<ChannelMarker>) -> &mut Self {
self.channel = Some(channel_id);
self
}
pub fn webhook(&mut self, webhook_id: Id<WebhookMarker>, token: String) -> &mut Self {
self.webhook = Some((webhook_id, token));
self
}
pub fn file(&mut self, path: PathBuf) -> &mut Self {
self.file = Some(path);
self
}
#[allow(clippy::unwrap_used, unused_must_use, clippy::print_stderr)]
pub async fn handle(&self, http: &Client, error: impl Display + Send) {
let mut error_message = format!("\n\n{error}");
self.maybe_create_message(http, &mut error_message).await;
self.maybe_execute_webhook(http, &mut error_message).await;
self.maybe_append_error(&mut error_message);
eprintln!("{error_message}");
}
#[allow(clippy::print_stderr)]
pub fn handle_sync(&self, error: impl Display) {
let mut error_message = format!("\n\n{error}");
self.maybe_append_error(&mut error_message);
eprintln!("{error_message}");
}
#[allow(unused_must_use, clippy::unwrap_used)]
async fn maybe_create_message(&self, http: &Client, error_message: &mut String) {
if let Some(channel_id) = self.channel {
if let Err(err) = http
.create_message(channel_id)
.content(error_message)
.unwrap_or_else(|_| {
{
http.create_message(channel_id)
.content(DEFAULT_ERROR_MESSAGE)
}
.unwrap()
})
.exec()
.await
{
write!(error_message, "\n\nFailed to create message: {err}");
}
}
}
#[allow(unused_must_use, clippy::unwrap_used)]
async fn maybe_execute_webhook(&self, http: &Client, error_message: &mut String) {
if let Some((webhook_id, token)) = &self.webhook {
if let Err(err) = http
.execute_webhook(*webhook_id, token)
.content(error_message)
.unwrap_or_else(|_| {
http.execute_webhook(*webhook_id, token)
.content(DEFAULT_ERROR_MESSAGE)
.unwrap()
})
.exec()
.await
{
write!(error_message, "\n\nFailed to execute webhook: {err}");
}
}
}
#[allow(unused_must_use)]
fn maybe_append_error(&self, error_message: &mut String) {
if let Some(path) = &self.file {
if let Err(err) = OpenOptions::new()
.append(true)
.create(true)
.open(path)
.and_then(|mut file| file.write_all(error_message.as_ref()))
{
write!(error_message, "\n\nFailed to append to file: {err}");
}
}
}
}