summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorseth <[email protected]>2023-11-30 22:18:51 -0500
committerseth <[email protected]>2023-12-01 07:12:49 -0500
commit76c0f94e6d7aa108424b34826eb7d8514b026287 (patch)
tree7315bd6dfe52c158041bed64ba39781718a69335 /src
parentdb52e639b85d79bed870020aec7a045851ca5ee3 (diff)
feat: use eyre, better logging, & refactor
small commits be damned
Diffstat (limited to 'src')
-rw-r--r--src/api/guzzle.rs30
-rw-r--r--src/api/mod.rs6
-rw-r--r--src/api/shiggy.rs30
-rw-r--r--src/colors.rs2
-rw-r--r--src/commands/ask.rs23
-rw-r--r--src/commands/bing.rs6
-rw-r--r--src/commands/convert.rs29
-rw-r--r--src/commands/copypasta.rs10
-rw-r--r--src/commands/mod.rs8
-rw-r--r--src/commands/random.rs42
-rw-r--r--src/commands/teawiespam.rs8
-rw-r--r--src/commands/version.rs6
-rw-r--r--src/handlers/error.rs42
-rw-r--r--src/handlers/event/message.rs (renamed from src/handler/message.rs)36
-rw-r--r--src/handlers/event/mod.rs (renamed from src/handler/mod.rs)16
-rw-r--r--src/handlers/event/pinboard.rs (renamed from src/handler/pinboard.rs)0
-rw-r--r--src/handlers/event/reactboard.rs (renamed from src/handler/reactboard.rs)38
-rw-r--r--src/handlers/mod.rs5
-rw-r--r--src/main.rs73
-rw-r--r--src/utils.rs60
20 files changed, 236 insertions, 234 deletions
diff --git a/src/api/guzzle.rs b/src/api/guzzle.rs
index 17d2c0c..83c159e 100644
--- a/src/api/guzzle.rs
+++ b/src/api/guzzle.rs
@@ -1,6 +1,6 @@
use crate::api::REQWEST_CLIENT;
-use crate::Error;
+use color_eyre::eyre::{eyre, Result};
use log::*;
use reqwest::StatusCode;
use serde::{Deserialize, Serialize};
@@ -11,32 +11,20 @@ struct GuzzleResponse {
}
const GUZZLE: &str = "https://api.mydadleft.me";
+const RANDOM_TEAWIE: &str = "/random_teawie";
-pub async fn get_random_teawie() -> Result<String, Error> {
- let endpoint = "/get_random_teawie";
-
+pub async fn get_random_teawie() -> Result<String> {
let req = REQWEST_CLIENT
- .get(format!("{GUZZLE}{endpoint}"))
- .build()
- .unwrap();
+ .get(format!("{GUZZLE}{RANDOM_TEAWIE}"))
+ .build()?;
info!("making request to {}", req.url());
- let resp = REQWEST_CLIENT.execute(req).await.unwrap();
+ let resp = REQWEST_CLIENT.execute(req).await?;
let status = resp.status();
if let StatusCode::OK = status {
- match resp.json::<GuzzleResponse>().await {
- Ok(data) => Ok(data.url),
- Err(why) => {
- if let Some(url) = why.url() {
- error!("error parsing json from {}! {}", url, why)
- } else {
- error!("couldn't even get the url! {}", why);
- }
-
- Err(Box::new(why))
- }
- }
+ let data = resp.json::<GuzzleResponse>().await?;
+ Ok(data.url)
} else {
error!(
"couldn't fetch random teawie from {}! {}",
@@ -44,6 +32,6 @@ pub async fn get_random_teawie() -> Result<String, Error> {
status
);
- Err(status.to_string().into())
+ Err(eyre!("failed to get random teawie with {status}"))
}
}
diff --git a/src/api/mod.rs b/src/api/mod.rs
index a1e0e97..2ce664e 100644
--- a/src/api/mod.rs
+++ b/src/api/mod.rs
@@ -3,11 +3,13 @@ use once_cell::sync::Lazy;
pub mod guzzle;
pub mod shiggy;
-pub const USER_AGENT: &str = "teawieBot/0.1.0";
+pub const USER_AGENT: &str = "teawieBot/";
pub static REQWEST_CLIENT: Lazy<reqwest::Client> = Lazy::new(|| {
+ let version = option_env!("CARGO_PKG_VERSION").unwrap_or("development");
+
reqwest::Client::builder()
- .user_agent(USER_AGENT)
+ .user_agent(format!("{USER_AGENT}/{version}"))
.build()
.unwrap_or_default()
});
diff --git a/src/api/shiggy.rs b/src/api/shiggy.rs
index 8dbadef..7a582ee 100644
--- a/src/api/shiggy.rs
+++ b/src/api/shiggy.rs
@@ -1,42 +1,30 @@
use crate::api::REQWEST_CLIENT;
-use crate::Error;
+use color_eyre::eyre::{eyre, Result};
use log::*;
use reqwest::StatusCode;
use serde::Deserialize;
const SHIGGY: &str = "https://safebooru.donmai.us";
+const RANDOM_SHIGGY: &str = "/posts/random.json?tags=kemomimi-chan_(naga_u)+naga_u&only=file_url";
#[derive(Deserialize)]
struct SafebooruResponse {
file_url: String,
}
-pub async fn get_random_shiggy() -> Result<String, Error> {
- let endpoint = "/posts/random.json?tags=kemomimi-chan_(naga_u)+naga_u&only=file_url";
-
+pub async fn get_random_shiggy() -> Result<String> {
let req = REQWEST_CLIENT
- .get(format!("{SHIGGY}{endpoint}"))
- .build()
- .unwrap();
+ .get(format!("{SHIGGY}{RANDOM_SHIGGY}"))
+ .build()?;
info!("making request to {}", req.url());
- let resp = REQWEST_CLIENT.execute(req).await.unwrap();
+ let resp = REQWEST_CLIENT.execute(req).await?;
let status = resp.status();
if let StatusCode::OK = status {
- match resp.json::<SafebooruResponse>().await {
- Ok(data) => Ok(data.file_url),
- Err(why) => {
- if let Some(url) = why.url() {
- error!("failed to make a request to {}! {}", url, why)
- } else {
- error!("couldn't even figure out the url! {}", why)
- };
-
- Err(Box::new(why))
- }
- }
+ let data = resp.json::<SafebooruResponse>().await?;
+ Ok(data.file_url)
} else {
error!(
"couldn't fetch random teawie from {}! {}",
@@ -44,6 +32,6 @@ pub async fn get_random_shiggy() -> Result<String, Error> {
status
);
- Err(status.to_string().into())
+ Err(eyre!("failed to get random teawie with {status}"))
}
}
diff --git a/src/colors.rs b/src/colors.rs
index ebd231e..5291933 100644
--- a/src/colors.rs
+++ b/src/colors.rs
@@ -2,12 +2,14 @@ use poise::serenity_prelude::Colour;
pub enum Colors {
Blue,
+ Orange,
}
impl From<Colors> for Colour {
fn from(val: Colors) -> Self {
match val {
Colors::Blue => Colour::from((136, 199, 253)),
+ Colors::Orange => Colour::from((255, 179, 74)),
}
}
}
diff --git a/src/commands/ask.rs b/src/commands/ask.rs
index 7cc82a1..3589484 100644
--- a/src/commands/ask.rs
+++ b/src/commands/ask.rs
@@ -1,6 +1,6 @@
-use crate::consts;
-use crate::utils;
-use crate::{Context, Error};
+use crate::{consts, utils, Context};
+
+use color_eyre::eyre::{Context as _, Result};
/// ask teawie a question!
#[poise::command(prefix_command, slash_command)]
@@ -9,15 +9,10 @@ pub async fn ask(
#[description = "the question you want to ask teawie"]
#[rename = "question"]
_question: String,
-) -> Result<(), Error> {
- match utils::random_choice(consts::RESPONSES) {
- Ok(resp) => {
- ctx.say(resp).await?;
- Ok(())
- }
- Err(why) => {
- ctx.say("idk").await?;
- Err(why)
- }
- }
+) -> Result<()> {
+ let resp = utils::random_choice(consts::RESPONSES)
+ .wrap_err("couldn't choose from random responses!")?;
+
+ ctx.say(resp).await?;
+ Ok(())
}
diff --git a/src/commands/bing.rs b/src/commands/bing.rs
index ed91bb3..b80ebca 100644
--- a/src/commands/bing.rs
+++ b/src/commands/bing.rs
@@ -1,8 +1,10 @@
-use crate::{Context, Error};
+use crate::Context;
+
+use color_eyre::eyre::Result;
/// make sure the wie is alive
#[poise::command(prefix_command)]
-pub async fn bing(ctx: Context<'_>) -> Result<(), Error> {
+pub async fn bing(ctx: Context<'_>) -> Result<()> {
ctx.say("bong!").await?;
Ok(())
}
diff --git a/src/commands/convert.rs b/src/commands/convert.rs
index 1f39ae4..cbbf8dc 100644
--- a/src/commands/convert.rs
+++ b/src/commands/convert.rs
@@ -1,11 +1,13 @@
-use crate::{Context, Error};
+use crate::Context;
+
use bottomify::bottom;
+use color_eyre::eyre::Result;
#[poise::command(
slash_command,
subcommands("to_fahrenheit", "to_celsius", "to_bottom", "from_bottom")
)]
-pub async fn convert(_ctx: Context<'_>) -> Result<(), Error> {
+pub async fn convert(_ctx: Context<'_>) -> Result<()> {
Ok(())
}
@@ -14,7 +16,7 @@ pub async fn convert(_ctx: Context<'_>) -> Result<(), Error> {
pub async fn to_celsius(
ctx: Context<'_>,
#[description = "what teawie will convert"] degrees_fahrenheit: f32,
-) -> Result<(), Error> {
+) -> Result<()> {
let temp = (degrees_fahrenheit - 32.0) * (5.0 / 9.0);
ctx.say(temp.to_string()).await?;
Ok(())
@@ -25,7 +27,7 @@ pub async fn to_celsius(
pub async fn to_fahrenheit(
ctx: Context<'_>,
#[description = "what teawie will convert"] degrees_celsius: f32,
-) -> Result<(), Error> {
+) -> Result<()> {
let temp = (degrees_celsius * (9.0 / 5.0)) + 32.0;
ctx.say(temp.to_string()).await?;
Ok(())
@@ -36,7 +38,7 @@ pub async fn to_fahrenheit(
pub async fn to_bottom(
ctx: Context<'_>,
#[description = "what teawie will translate into bottom"] message: String,
-) -> Result<(), Error> {
+) -> Result<()> {
let encoded = bottom::encode_string(&message);
ctx.say(encoded).await?;
Ok(())
@@ -47,17 +49,8 @@ pub async fn to_bottom(
pub async fn from_bottom(
ctx: Context<'_>,
#[description = "what teawie will translate from bottom"] message: String,
-) -> Result<(), Error> {
- let d = bottom::decode_string(&message);
- match d {
- Ok(decoded) => {
- ctx.say(decoded).await?;
- Ok(())
- }
- Err(why) => {
- ctx.say("couldn't decode that for you, i'm sowwy!! :((".to_string())
- .await?;
- Err(Box::new(why))
- }
- }
+) -> Result<()> {
+ let decoded = bottom::decode_string(&message)?;
+ ctx.say(decoded).await?;
+ Ok(())
}
diff --git a/src/commands/copypasta.rs b/src/commands/copypasta.rs
index 14a6673..313cd13 100644
--- a/src/commands/copypasta.rs
+++ b/src/commands/copypasta.rs
@@ -1,7 +1,8 @@
-use crate::{utils, Context, Error};
+use crate::{utils, Context};
use std::collections::HashMap;
+use color_eyre::eyre::{eyre, Result};
use include_dir::{include_dir, Dir};
use log::*;
@@ -58,8 +59,11 @@ fn get_copypasta(name: Copypastas) -> String {
pub async fn copypasta(
ctx: Context<'_>,
#[description = "the copypasta you want to send"] copypasta: Copypastas,
-) -> Result<(), Error> {
- let gid = ctx.guild_id().unwrap_or_default();
+) -> Result<()> {
+ let gid = ctx
+ .guild_id()
+ .ok_or_else(|| eyre!("couldnt get guild from message!"))?;
+
if !utils::is_guild_allowed(gid) {
info!("not running copypasta command in {gid}");
return Ok(());
diff --git a/src/commands/mod.rs b/src/commands/mod.rs
index b6130ab..5edf0b7 100644
--- a/src/commands/mod.rs
+++ b/src/commands/mod.rs
@@ -6,10 +6,12 @@ pub mod random;
pub mod teawiespam;
pub mod version;
-use crate::{Data, Error};
+use crate::Data;
+
+use color_eyre::eyre::Report;
use poise::Command;
-pub fn to_global_commands() -> Vec<Command<Data, Error>> {
+pub fn to_global_commands() -> Vec<Command<Data, Report>> {
vec![
ask::ask(),
bing::bing(),
@@ -21,6 +23,6 @@ pub fn to_global_commands() -> Vec<Command<Data, Error>> {
]
}
-pub fn to_guild_commands() -> Vec<Command<Data, Error>> {
+pub fn to_guild_commands() -> Vec<Command<Data, Report>> {
vec![copypasta::copypasta(), teawiespam::teawiespam()]
}
diff --git a/src/commands/random.rs b/src/commands/random.rs
index bc34928..9595d09 100644
--- a/src/commands/random.rs
+++ b/src/commands/random.rs
@@ -1,44 +1,30 @@
-use crate::{api, consts, utils, Context, Error};
+use crate::{api, consts, utils, Context};
+
+use color_eyre::eyre::Result;
#[poise::command(slash_command, subcommands("lore", "teawie", "shiggy"))]
-pub async fn random(_ctx: Context<'_>) -> Result<(), Error> {
+pub async fn random(_ctx: Context<'_>) -> Result<()> {
Ok(())
}
/// get a random piece of teawie lore!
#[poise::command(prefix_command, slash_command)]
-pub async fn lore(ctx: Context<'_>) -> Result<(), Error> {
- match utils::random_choice(consts::LORE) {
- Ok(resp) => {
- ctx.say(resp).await?;
- Ok(())
- }
- Err(why) => {
- ctx.say("i can't think of any right now :(").await?;
- Err(why)
- }
- }
+pub async fn lore(ctx: Context<'_>) -> Result<()> {
+ let resp = utils::random_choice(consts::LORE)?;
+ ctx.say(resp).await?;
+ Ok(())
}
/// get a random teawie
#[poise::command(prefix_command, slash_command)]
-pub async fn teawie(ctx: Context<'_>) -> Result<(), Error> {
- if let Ok(url) = api::guzzle::get_random_teawie().await {
- utils::send_url_as_embed(ctx, url).await
- } else {
- ctx.say("i'm too lazy to send a selfie right now :(")
- .await?;
- Ok(())
- }
+pub async fn teawie(ctx: Context<'_>) -> Result<()> {
+ let url = api::guzzle::get_random_teawie().await?;
+ utils::send_url_as_embed(ctx, url).await
}
/// get a random shiggy
#[poise::command(prefix_command, slash_command)]
-pub async fn shiggy(ctx: Context<'_>) -> Result<(), Error> {
- if let Ok(url) = api::shiggy::get_random_shiggy().await {
- utils::send_url_as_embed(ctx, url).await
- } else {
- ctx.say("i couldn't get a shiggy right now :(").await?;
- Ok(())
- }
+pub async fn shiggy(ctx: Context<'_>) -> Result<()> {
+ let url = api::shiggy::get_random_shiggy().await?;
+ utils::send_url_as_embed(ctx, url).await
}
diff --git a/src/commands/teawiespam.rs b/src/commands/teawiespam.rs
index 4964e90..da01af9 100644
--- a/src/commands/teawiespam.rs
+++ b/src/commands/teawiespam.rs
@@ -1,13 +1,15 @@
use crate::utils;
-use crate::{Context, Error};
+use crate::Context;
+
+use color_eyre::eyre::Result;
use log::*;
/// teawie will spam you.
#[poise::command(slash_command, prefix_command)]
-pub async fn teawiespam(ctx: Context<'_>) -> Result<(), Error> {
+pub async fn teawiespam(ctx: Context<'_>) -> Result<()> {
let gid = ctx.guild_id().unwrap_or_default();
if !utils::is_guild_allowed(gid) {
- info!("not running copypasta command in {gid}");
+ info!("not running teawiespam command in {gid}");
return Ok(());
}
diff --git a/src/commands/version.rs b/src/commands/version.rs
index e87ab4d..c5e97f9 100644
--- a/src/commands/version.rs
+++ b/src/commands/version.rs
@@ -1,9 +1,11 @@
use crate::colors::Colors;
-use crate::{Context, Error};
+use crate::Context;
+
+use color_eyre::eyre::Result;
/// get version info
#[poise::command(slash_command)]
-pub async fn version(ctx: Context<'_>) -> Result<(), Error> {
+pub async fn version(ctx: Context<'_>) -> Result<()> {
let sha = option_env!("GIT_SHA").unwrap_or("main");
let revision_url = format!(
diff --git a/src/handlers/error.rs b/src/handlers/error.rs
new file mode 100644
index 0000000..b4e1361
--- /dev/null
+++ b/src/handlers/error.rs
@@ -0,0 +1,42 @@
+use crate::colors::Colors;
+use crate::Data;
+
+use color_eyre::eyre::Report;
+use log::*;
+use poise::serenity_prelude::Timestamp;
+use poise::FrameworkError;
+
+pub async fn handle(error: poise::FrameworkError<'_, Data, Report>) {
+ match error {
+ FrameworkError::Setup { error, .. } => error!("error setting up client! {error:#?}"),
+
+ FrameworkError::Command { error, ctx } => {
+ error!("error in command {}:\n{error:?}", ctx.command().name);
+ ctx.send(|c| {
+ c.embed(|e| {
+ e.title("Something went wrong!")
+ .description("oopsie")
+ .timestamp(Timestamp::now())
+ .color(Colors::Orange)
+ })
+ })
+ .await
+ .ok();
+ }
+
+ FrameworkError::EventHandler {
+ error,
+ ctx: _,
+ event: _,
+ framework: _,
+ } => {
+ error!("error while handling event:\n{error:#?}");
+ }
+
+ error => {
+ if let Err(e) = poise::builtins::on_error(error).await {
+ error!("error while handling an error: {}", e);
+ }
+ }
+ }
+}
diff --git a/src/handler/message.rs b/src/handlers/event/message.rs
index 37a49bf..a84ec59 100644
--- a/src/handler/message.rs
+++ b/src/handlers/event/message.rs
@@ -1,9 +1,23 @@
-use crate::{consts, utils, Data, Error};
+use crate::{consts, utils, Data};
+
+use color_eyre::eyre::{Report, Result};
use log::*;
-use poise::serenity_prelude as serenity;
-use poise::{Event, FrameworkContext};
+use poise::serenity_prelude::{Context, Message};
+use poise::FrameworkContext;
+
+pub async fn handle(
+ ctx: &Context,
+ framework: FrameworkContext<'_, Data, Report>,
+ msg: &Message,
+) -> Result<()> {
+ if should_echo(framework, msg) {
+ msg.reply(ctx, &msg.content).await?;
+ }
+
+ Ok(())
+}
-fn should_echo(framework: FrameworkContext<'_, Data, Error>, msg: &serenity::Message) -> bool {
+fn should_echo(framework: FrameworkContext<'_, Data, Report>, msg: &Message) -> bool {
let gid = msg.guild_id.unwrap_or_default();
if msg.author.id == framework.bot_id || !utils::is_guild_allowed(gid) {
info!("not running copypasta command in {gid}");
@@ -19,17 +33,3 @@ fn should_echo(framework: FrameworkContext<'_, Data, Error>, msg: &serenity::Mes
.to_ascii_lowercase()
.contains("twitter's recommendation algorithm")
}
-
-pub async fn handle(
- ctx: &serenity::Context,
- _event: &Event<'_>,
- framework: FrameworkContext<'_, Data, Error>,
- _data: &Data,
- msg: &serenity::Message,
-) -> Result<(), Error> {
- if should_echo(framework, msg) {
- msg.reply(ctx, &msg.content).await?;
- }
-
- Ok(())
-}
diff --git a/src/handler/mod.rs b/src/handlers/event/mod.rs
index 3489b4a..09be62b 100644
--- a/src/handler/mod.rs
+++ b/src/handlers/event/mod.rs
@@ -1,25 +1,25 @@
-use crate::{Data, Error};
+use crate::Data;
+
+use color_eyre::eyre::{Report, Result};
use poise::serenity_prelude as serenity;
-use poise::Event;
+use poise::{Event, FrameworkContext};
mod message;
-pub mod pinboard;
+mod pinboard;
mod reactboard;
pub async fn handle(
ctx: &serenity::Context,
event: &Event<'_>,
- framework: poise::FrameworkContext<'_, Data, Error>,
+ framework: FrameworkContext<'_, Data, Report>,
data: &Data,
-) -> Result<(), Error> {
+) -> Result<()> {
match event {
Event::Ready { data_about_bot } => {
log::info!("logged in as {}", data_about_bot.user.name)
}
- Event::Message { new_message } => {
- message::handle(ctx, event, framework, data, new_message).await?
- }
+ Event::Message { new_message } => message::handle(ctx, framework, new_message).await?,
Event::ChannelPinsUpdate { pin } => {
if let Some(settings) = &data.settings {
diff --git a/src/handler/pinboard.rs b/src/handlers/event/pinboard.rs
index 0c87a5b..0c87a5b 100644
--- a/src/handler/pinboard.rs
+++ b/src/handlers/event/pinboard.rs
diff --git a/src/handler/reactboard.rs b/src/handlers/event/reactboard.rs
index 36f8361..3972931 100644
--- a/src/handler/reactboard.rs
+++ b/src/handlers/event/reactboard.rs
@@ -1,31 +1,29 @@
-use crate::Error;
use crate::{settings::Settings, utils};
+
+use color_eyre::eyre::{eyre, Context as _, Result};
use log::*;
use poise::serenity_prelude::{Context, Message, MessageReaction, Reaction};
-pub async fn handle(ctx: &Context, reaction: &Reaction, settings: &Settings) -> Result<(), Error> {
- let msg = match reaction.message(&ctx.http).await {
- Ok(msg) => msg,
- Err(why) => {
- warn!("couldn't get message of reaction! {}", why);
- return Err(Box::new(why));
- }
- };
+pub async fn handle(ctx: &Context, reaction: &Reaction, settings: &Settings) -> Result<()> {
+ let msg = reaction
+ .message(&ctx.http)
+ .await
+ .wrap_err("couldn't get reaction from message!")?;
- if let Some(matched) = msg
+ let matched = msg
.clone()
.reactions
.into_iter()
.find(|r| r.reaction_type == reaction.emoji)
- {
- send_to_reactboard(ctx, &matched, &msg, settings).await?;
- } else {
- warn!(
- "couldn't find any matching reactions for {} in {}",
- reaction.emoji.as_data(),
- msg.id
- )
- }
+ .ok_or_else(|| {
+ eyre!(
+ "couldn't find any matching reactions for {} in message {}!",
+ reaction.emoji.as_data(),
+ msg.id
+ )
+ })?;
+
+ send_to_reactboard(ctx, &matched, &msg, settings).await?;
Ok(())
}
@@ -35,7 +33,7 @@ async fn send_to_reactboard(
reaction: &MessageReaction,
msg: &Message,
settings: &Settings,
-) -> Result<(), Error> {
+) -> Result<()> {
if !settings.can_use_reaction(reaction) {
info!("reaction {} can't be used!", reaction.reaction_type);
return Ok(());
diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs
new file mode 100644
index 0000000..2ae0539
--- /dev/null
+++ b/src/handlers/mod.rs
@@ -0,0 +1,5 @@
+mod error;
+mod event;
+
+pub use error::handle as handle_error;
+pub use event::handle as handle_event;
diff --git a/src/main.rs b/src/main.rs
index a93e102..98ebe5f 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,19 +1,21 @@
-use std::{error, time};
+use std::time::Duration;
+use color_eyre::eyre::{eyre, Context as _, Report, Result};
use log::*;
-use poise::serenity_prelude as serentiy;
+use poise::{
+ serenity_prelude as serenity, EditTracker, Framework, FrameworkOptions, PrefixFrameworkOptions,
+};
use settings::Settings;
mod api;
mod colors;
mod commands;
mod consts;
-mod handler;
+mod handlers;
mod settings;
mod utils;
-type Error = Box<dyn error::Error + Send + Sync>;
-type Context<'a> = poise::Context<'a, Data, Error>;
+type Context<'a> = poise::Context<'a, Data, Report>;
#[derive(Clone)]
pub struct Data {
@@ -34,54 +36,43 @@ impl Default for Data {
}
}
-async fn on_error(error: poise::FrameworkError<'_, Data, Error>) {
- match error {
- poise::FrameworkError::Setup { error, .. } => panic!("failed to start bot: {error:?}"),
- poise::FrameworkError::Command { error, ctx } => {
- error!("error in command {}: {:?}", ctx.command().name, error);
- }
- error => {
- if let Err(e) = poise::builtins::on_error(error).await {
- error!("error while handling an error: {}", e);
- }
- }
- }
-}
-
#[tokio::main]
-async fn main() {
+async fn main() -> Result<()> {
+ color_eyre::install()?;
env_logger::init();
dotenvy::dotenv().ok();
- let options = poise::FrameworkOptions {
+ let token =
+ std::env::var("TOKEN").wrap_err_with(|| eyre!("Couldn't find token in environment!"))?;
+
+ let intents =
+ serenity::GatewayIntents::non_privileged() | serenity::GatewayIntents::MESSAGE_CONTENT;
+
+ let options = FrameworkOptions {
commands: commands::to_global_commands(),
+ on_error: |error| Box::pin(handlers::handle_error(error)),
+ command_check: Some(|ctx| {
+ Box::pin(async move { Ok(ctx.author().id != ctx.framework().bot_id) })
+ }),
event_handler: |ctx, event, framework, data| {
- Box::pin(handler::handle(ctx, event, framework, data))
+ Box::pin(handlers::handle_event(ctx, event, framework, data))
},
- prefix_options: poise::PrefixFrameworkOptions {
+ prefix_options: PrefixFrameworkOptions {
prefix: Some("!".into()),
- edit_tracker: Some(poise::EditTracker::for_timespan(time::Duration::from_secs(
- 3600,
- ))),
+ edit_tracker: Some(EditTracker::for_timespan(Duration::from_secs(3600))),
..Default::default()
},
- on_error: |error| Box::pin(on_error(error)),
- command_check: Some(|ctx| {
- Box::pin(async move { Ok(ctx.author().id != ctx.framework().bot_id) })
- }),
..Default::default()
};
- let framework = poise::Framework::builder()
+ let framework = Framework::builder()
+ .token(token)
+ .intents(intents)
.options(options)
- .token(std::env::var("TOKEN").expect("couldn't find token in environment."))
- .intents(
- serentiy::GatewayIntents::non_privileged() | serentiy::GatewayIntents::MESSAGE_CONTENT,
- )
.setup(|ctx, _ready, framework| {
Box::pin(async move {
poise::builtins::register_globally(ctx, &framework.options().commands).await?;
- info!("registered global commands!");
+ info!("Registered global commands!");
poise::builtins::register_in_guild(
ctx,
@@ -89,11 +80,17 @@ async fn main() {
consts::TEAWIE_GUILD,
)
.await?;
- info!("registered guild commands!");
+ info!("Registered guild commands to {}", consts::TEAWIE_GUILD);
Ok(Data::new())
})
});
- framework.run().await.unwrap()
+ tokio::select! {
+ result = framework.run() => { result.map_err(Report::from) },
+ _ = tokio::signal::ctrl_c() => {
+ info!("Interrupted! Exiting...");
+ std::process::exit(130);
+ }
+ }
}
diff --git a/src/utils.rs b/src/utils.rs
index af079ff..9a1d09c 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -1,6 +1,6 @@
-use crate::{colors, consts, Context, Error};
+use crate::{colors, consts, Context};
-use log::*;
+use color_eyre::eyre::{eyre, Result};
use once_cell::sync::Lazy;
use poise::serenity_prelude as serenity;
use rand::seq::SliceRandom;
@@ -21,13 +21,13 @@ pub fn parse_snowflakes_from_env<T, F: Fn(u64) -> T>(key: &str, f: F) -> Option<
/*
* chooses a random element from an array
*/
-pub fn random_choice<const N: usize>(arr: [&str; N]) -> Result<String, Error> {
+pub fn random_choice<const N: usize>(arr: [&str; N]) -> Result<String> {
let mut rng = rand::thread_rng();
- if let Some(resp) = arr.choose(&mut rng) {
- Ok((*resp).to_string())
- } else {
- Err(Into::into("couldn't choose from arr!"))
- }
+ let resp = arr
+ .choose(&mut rng)
+ .ok_or_else(|| eyre!("couldn't choose from array!"))?;
+
+ Ok((*resp).to_string())
}
// waiting for `round_char_boundary` to stabilize
@@ -54,31 +54,25 @@ pub fn is_guild_allowed(gid: GuildId) -> bool {
ALLOWED_GUILDS.contains(&gid)
}
-pub async fn send_url_as_embed(ctx: Context<'_>, url: String) -> Result<(), Error> {
- match Url::parse(&url) {
- Ok(parsed) => {
- let title = parsed
- .path_segments()
- .unwrap()
- .last()
- .unwrap_or("image")
- .replace("%20", " ");
-
- ctx.send(|c| {
- c.embed(|e| {
- e.title(title)
- .image(&url)
- .url(url)
- .color(colors::Colors::Blue)
- })
- })
- .await?;
- }
- Err(why) => {
- error!("failed to parse url {}! {}", url, why);
- ctx.say("i can't get that for you right now :(").await?;
- }
- }
+pub async fn send_url_as_embed(ctx: Context<'_>, url: String) -> Result<()> {
+ let parsed = Url::parse(&url)?;
+
+ let title = parsed
+ .path_segments()
+ .unwrap()
+ .last()
+ .unwrap_or("image")
+ .replace("%20", " ");
+
+ ctx.send(|c| {
+ c.embed(|e| {
+ e.title(title)
+ .image(&url)
+ .url(url)
+ .color(colors::Colors::Blue)
+ })
+ })
+ .await?;
Ok(())
}