Skip to content

Commit

Permalink
typed errors
Browse files Browse the repository at this point in the history
  • Loading branch information
onlycs committed Sep 6, 2023
1 parent c17b883 commit 4b1428e
Show file tree
Hide file tree
Showing 28 changed files with 500 additions and 194 deletions.
9 changes: 5 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ poise = "0.5.5"
serde = { version = "1.0.171", features = ["derive"] }
serde_json = "1.0.104"
simple_logger = "4.2.0"
thiserror = "1.0.48"
tokio = "1.29.1"

[dependencies.prisma-client-rust]
Expand Down
2 changes: 1 addition & 1 deletion src/commands/ping.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::prelude::*;

#[poise::command(slash_command)]
pub async fn ping(ctx: Context<'_>) -> Result<()> {
pub async fn ping(ctx: Context<'_>) -> Result<(), CommandError> {
let created_timestamp = ctx.created_at().timestamp_millis();
let now = serenity::Timestamp::now().timestamp_millis();
let latency = now - created_timestamp;
Expand Down
4 changes: 2 additions & 2 deletions src/commands/setting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ macro_rules! user_setting {
ctx: Context<'_>,
#[description = "the value to set"] value: Option<<settings::$stg as UserSetting>::Value>,
#[description = "manage this user, admins only"] user: Option<serenity::Member>
) -> Result<()> {
) -> Result<(), CommandError> {
let loading = Loading::new(&ctx, "Locking settings.\nDepending on how long the bot has been up, this may take awhile.").await?;
let mut data = ctx.data().lock().await;
let settings = &mut data.settings;
Expand Down Expand Up @@ -57,7 +57,7 @@ macro_rules! user_setting {
macro_rules! settings_wrapper {
($($fnname:expr),*) => {
#[poise::command(slash_command, subcommands($($fnname,)*))]
pub async fn settings(_: Context<'_>) -> Result<()> {
pub async fn settings(_: Context<'_>) -> Result<(), CommandError> {
Ok(())
}
};
Expand Down
224 changes: 224 additions & 0 deletions src/error/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
use crate::prelude::*;

#[derive(Error, Debug)]
pub enum PrismaError {
#[error("prisma query error")]
PrismaQuery(#[from] QueryError),

#[error("prisma create error")]
PrismaCreate(#[from] NewClientError),

#[error("{0} not found in database")]
NotFound(String),
}

#[derive(Error, Debug)]
pub enum CommandError {
#[error("serenity error")]
Serenity(#[from] serenity::Error),

#[error("prisma query error")]
PrismaQuery(#[from] QueryError),

#[error("prisma create error")]
PrismaCreate(#[from] NewClientError),

#[error("prisma relation not fetched error")]
PrismaRelationNotFetched(#[from] RelationNotFetchedError),

#[error("settings error")]
SettingsError(#[from] SettingsError),

#[error("prisma error")]
Prisma(#[from] PrismaError),
}

#[derive(Error, Debug)]
pub enum EventError {
#[error("serde error")]
Serde(#[from] serde_json::Error),
}

#[derive(Error, Debug)]
pub enum StarboardError {
#[error("prisma query error")]
PrismaQuery(#[from] QueryError),

#[error("prisma create error")]
PrismaCreate(#[from] NewClientError),

#[error("prisma relation not fetched error")]
PrismaRelationNotFetched(#[from] RelationNotFetchedError),

#[error("the following message with id {0} was not found in the database")]
MessageNotInDatabase(serenity::MessageId),

#[error("message clone error")]
MessageClone(#[from] MessageCloneError),

#[error("serenity error")]
Serenity(#[from] serenity::Error),
}

#[derive(Error, Debug)]
pub enum LoggingError {
#[error("prisma query error")]
PrismaQuery(#[from] QueryError),

#[error("prisma create error")]
PrismaCreate(#[from] NewClientError),

#[error("prisma relation not fetched error")]
PrismaRelationNotFetched(#[from] RelationNotFetchedError),

#[error("serenity error")]
Serenity(#[from] serenity::Error),

#[error("channel with id {0} is a thread")]
ChannelIsThread(serenity::ChannelId),

#[error("could not find user with id {0} in the database")]
UserNotInDatabase(serenity::UserId),

#[error("user with id {0} does not have a color role in the database")]
UserNoColorRole(serenity::UserId),

#[error("could not find nci in ctx.cache")]
NciNotFound,

#[error("color parse error")]
Color(#[from] ColorParseError),
}

#[derive(Error, Debug)]
pub enum SettingsError {
#[error("serde error")]
Serde(#[from] serde_json::Error),

#[error("<{0}>::default_value failed")]
DefaultValueFailed(String),

#[error("<{0}>::on_change failed")]
OnChangeFailed(String),
}

#[derive(Error, Debug)]
pub enum ColorParseError {
#[error("failed to parse from hex {0}")]
ParseHex(String),

#[error("failed to parse from color name {0}")]
ParseName(String),

#[error("Color::from_str failed to parse {0}")]
ParseStr(String),
}

#[derive(Error, Debug)]
pub enum MessageCloneError {
#[error("serenity error")]
Serenity(#[from] serenity::Error),

#[error("prisma query error")]
PrismaQuery(#[from] QueryError),

#[error("prisma create error")]
PrismaCreate(#[from] NewClientError),

#[error("prisma relation not fetched error")]
PrismaRelationNotFetched(#[from] RelationNotFetchedError),

#[error("webhook not found while trying to resync")]
NoWebhook,

#[error("webhook message not found after cloning")]
NoWebhookMessage,

#[error("could not find nci in ctx.cache")]
NciNotFound,
}

#[derive(Error, Debug)]
pub enum AnyError {
#[error("serenity error")]
Serenity(#[from] serenity::Error),

#[error("prisma query error")]
PrismaQuery(#[from] QueryError),

#[error("prisma create error")]
PrismaCreate(#[from] NewClientError),

#[error("prisma relation not fetched error")]
PrismaRelationNotFetched(#[from] RelationNotFetchedError),

#[error("anyhow error")]
Anyhow(#[from] anyhow::Error),

#[error("message clone error")]
Clone(#[from] MessageCloneError),

#[error("color parse error")]
Color(#[from] ColorParseError),

#[error("command error")]
Command(#[from] CommandError),

#[error("event emitter error")]
Event(#[from] EventError),

#[error("database logging error")]
Logging(#[from] LoggingError),

#[error("settings error")]
Settings(#[from] SettingsError),

#[error("starboard error")]
Starboard(#[from] StarboardError),

#[error("prisma error")]
Prisma(#[from] PrismaError),
}

pub trait MakeError<T, E> {
fn make_error(self, error: E) -> Result<T, E>;
}

impl<T, U, E> MakeError<T, E> for Result<T, U> {
fn make_error(self, error: E) -> Result<T, E> {
match self {
Ok(n) => Ok(n),
Err(_) => Err(error),
}
}
}

impl<T, E> MakeError<T, E> for Option<T> {
fn make_error(self, error: E) -> Result<T, E> {
match self {
Some(n) => Ok(n),
None => Err(error),
}
}
}

macro_rules! bail {

Check warning on line 205 in src/error/mod.rs

View workflow job for this annotation

GitHub Actions / build

unused macro definition: `bail`
($err:expr) => {
return Err($err);
};
}

macro_rules! anyhow {
($msg:literal $(,)?) => {
AnyError::Anyhow(anyhow::anyhow!($msg))
};
($err:expr $(,)?) => {
AnyError::Anyhow(anyhow::anyhow!($err))
};
($fmt:expr, $($arg:tt)*) => {
AnyError::Anyhow(anyhow::anyhow!($fmt, $($arg)*))
};
}

pub(crate) use anyhow;
pub(crate) use bail;
8 changes: 4 additions & 4 deletions src/events/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::prelude::*;
use futures::{future::BoxFuture, Future, FutureExt};
use std::{any::TypeId, collections::HashMap};

type Output = Result<()>;
type Output = Result<(), AnyError>;
type AsyncOutput = BoxFuture<'static, Output>;

pub struct Listener {
Expand All @@ -27,7 +27,7 @@ impl EventEmitter {
_event: Event, /* making the user specify generic argument for this looks ugly af */
argument: Event::Argument,
context: &serenity::Context,
) -> Result<()>
) -> Result<(), EventError>
where
Event: EmitterEvent,
{
Expand Down Expand Up @@ -60,7 +60,7 @@ impl EventEmitter {
) where
Event: EmitterEvent,
Callback: Fn(Event::Argument, serenity::Context) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<()>> + Send + 'static,
Fut: Future<Output = Output> + Send + 'static,
{
let parsed_callback = move |bytes: Vec<u8>, ctx: serenity::Context| {
callback(serde_json::from_slice(&bytes).unwrap(), ctx).boxed()
Expand Down Expand Up @@ -89,7 +89,7 @@ impl EventEmitter {
) where
Event: EmitterEvent,
Callback: Fn(Event::Argument, serenity::Context) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<()>> + Send + 'static,
Fut: Future<Output = Output> + Send + 'static,
Filter: Fn(Event::Argument) -> bool + Send + Sync + 'static,
{
let parsed_callback = move |bytes: Vec<u8>, ctx: serenity::Context| {
Expand Down
2 changes: 1 addition & 1 deletion src/events/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::prelude::*;

pub async fn handle(framework_error: poise::FrameworkError<'_, Shared<Data>, anyhow::Error>) -> Result<()> {
pub async fn handle(framework_error: poise::FrameworkError<'_, Shared<Data>, CommandError>) -> Result<(), serenity::Error> {
match &framework_error {
poise::FrameworkError::Command { error, ctx } => {
if error.to_string().starts_with("Warning: ") {
Expand Down
7 changes: 5 additions & 2 deletions src/events/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ pub mod payloads;

use crate::prelude::*;

pub async fn event_handler(ctx: serenity::Context, event: poise::Event<'_>) -> Result<()> {
let data_arc = data::get_serenity(&ctx).await?;
pub async fn event_handler(
ctx: serenity::Context,
event: poise::Event<'_>,
) -> Result<(), EventError> {
let data_arc = data::get_serenity(&ctx).await;
let mut data = data_arc.lock().await;
let event_emitter = &mut data.emitter;

Expand Down
Loading

0 comments on commit 4b1428e

Please sign in to comment.