lol what are good commits
This commit is contained in:
parent
d543802181
commit
4b7a981a88
13 changed files with 189 additions and 112 deletions
49
Cargo.lock
generated
49
Cargo.lock
generated
|
@ -304,7 +304,10 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"dotenv",
|
"dotenv",
|
||||||
|
"env_logger",
|
||||||
"futures",
|
"futures",
|
||||||
|
"lazy_static",
|
||||||
|
"log",
|
||||||
"rand",
|
"rand",
|
||||||
"regex",
|
"regex",
|
||||||
"serenity",
|
"serenity",
|
||||||
|
@ -334,6 +337,19 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_logger"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
|
||||||
|
dependencies = [
|
||||||
|
"atty",
|
||||||
|
"humantime",
|
||||||
|
"log",
|
||||||
|
"regex",
|
||||||
|
"termcolor",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fake-simd"
|
name = "fake-simd"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
|
@ -561,6 +577,15 @@ version = "1.3.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9"
|
checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "humantime"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
|
||||||
|
dependencies = [
|
||||||
|
"quick-error",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "0.13.5"
|
version = "0.13.5"
|
||||||
|
@ -967,6 +992,12 @@ dependencies = [
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quick-error"
|
||||||
|
version = "1.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
|
@ -1401,6 +1432,15 @@ dependencies = [
|
||||||
"winapi 0.3.8",
|
"winapi 0.3.8",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termcolor"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
@ -1799,6 +1839,15 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-util"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.3.8",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
|
|
@ -15,4 +15,7 @@ futures = "0.3"
|
||||||
tokio = { version = "0.2", features = ["full"] }
|
tokio = { version = "0.2", features = ["full"] }
|
||||||
dotenv = "0.15"
|
dotenv = "0.15"
|
||||||
rand = "0.7"
|
rand = "0.7"
|
||||||
unicode-segmentation = "1.6.0"
|
unicode-segmentation = "1.6"
|
||||||
|
log = "0.4"
|
||||||
|
env_logger = "0.7"
|
||||||
|
lazy_static = "1.4"
|
|
@ -1,3 +1,4 @@
|
||||||
|
use log::error;
|
||||||
use serenity::framework::standard::{macros::command, Args, CommandResult};
|
use serenity::framework::standard::{macros::command, Args, CommandResult};
|
||||||
use serenity::model::channel::Message;
|
use serenity::model::channel::Message;
|
||||||
use serenity::prelude::Context;
|
use serenity::prelude::Context;
|
||||||
|
@ -6,7 +7,16 @@ use serenity::prelude::Context;
|
||||||
async fn clap(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult {
|
async fn clap(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||||
let resp = match args
|
let resp = match args
|
||||||
.iter()
|
.iter()
|
||||||
.map(|e: Result<String, _>| e.unwrap())
|
.map(|arg: Result<String, _>| match arg {
|
||||||
|
Ok(arg) => arg,
|
||||||
|
Err(e) => {
|
||||||
|
error!(
|
||||||
|
"Failed to cast clap arg to String; returning empty string instead: {:?}",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
String::default()
|
||||||
|
}
|
||||||
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.as_slice()
|
.as_slice()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/// This was directly ported from the Java version. I make no quality assurances.
|
||||||
use serenity::framework::standard::{macros::command, Args, CommandResult};
|
use serenity::framework::standard::{macros::command, Args, CommandResult};
|
||||||
use serenity::model::channel::Message;
|
use serenity::model::channel::Message;
|
||||||
use serenity::prelude::Context;
|
use serenity::prelude::Context;
|
||||||
|
|
|
@ -7,10 +7,15 @@ use serenity::prelude::Context;
|
||||||
async fn heck(ctx: &mut Context, msg: &Message) -> CommandResult {
|
async fn heck(ctx: &mut Context, msg: &Message) -> CommandResult {
|
||||||
let db_pool = ctx.data.clone();
|
let db_pool = ctx.data.clone();
|
||||||
let mut db_pool = db_pool.write().await;
|
let mut db_pool = db_pool.write().await;
|
||||||
let db_pool = db_pool.get_mut::<DbConnPool>().unwrap();
|
let db_pool = db_pool
|
||||||
|
.get_mut::<DbConnPool>()
|
||||||
|
.expect("No db pool in context?!");
|
||||||
let value = db_pool.get_heck().await;
|
let value = db_pool.get_heck().await;
|
||||||
msg.channel_id
|
msg.channel_id
|
||||||
.say(ctx, format!("This command has been hecked {} times", value))
|
.say(
|
||||||
|
ctx,
|
||||||
|
format!("This command has been hecked {} times", value?),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
47
src/main.rs
47
src/main.rs
|
@ -1,9 +1,12 @@
|
||||||
use crate::commands::GENERAL_GROUP;
|
use crate::commands::GENERAL_GROUP;
|
||||||
use crate::passive::Handler;
|
use crate::passive::Handler;
|
||||||
use serenity::client::Client;
|
use env_logger;
|
||||||
|
use log::error;
|
||||||
|
use serenity::client::{validate_token, Client};
|
||||||
use serenity::framework::standard::StandardFramework;
|
use serenity::framework::standard::StandardFramework;
|
||||||
use std::env;
|
use std::env;
|
||||||
use util::db::DbConnPool;
|
use util::db::DbConnPool;
|
||||||
|
use util::error::KuranteError;
|
||||||
|
|
||||||
mod commands;
|
mod commands;
|
||||||
mod passive;
|
mod passive;
|
||||||
|
@ -12,28 +15,48 @@ mod util;
|
||||||
pub(crate) const COMMAND_PREFIX: &str = "~";
|
pub(crate) const COMMAND_PREFIX: &str = "~";
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
async fn main() {
|
||||||
|
std::process::exit(match run().await {
|
||||||
|
Ok(_) => 0,
|
||||||
|
Err(_) => 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run() -> Result<(), KuranteError> {
|
||||||
|
// Init dotenv vars before the env logger
|
||||||
dotenv::dotenv().ok();
|
dotenv::dotenv().ok();
|
||||||
|
env_logger::init();
|
||||||
|
|
||||||
let framework = StandardFramework::new()
|
let framework = StandardFramework::new()
|
||||||
.configure(|c| c.prefix(COMMAND_PREFIX))
|
.configure(|c| c.prefix(COMMAND_PREFIX))
|
||||||
.group(&GENERAL_GROUP);
|
.group(&GENERAL_GROUP);
|
||||||
|
|
||||||
let mut client =
|
let token = match env::var("DISCORD_TOKEN") {
|
||||||
Client::new_with_extras(&env::var("DISCORD_TOKEN").expect("token"), |extras| {
|
Ok(token) => match validate_token(&token) {
|
||||||
extras
|
Ok(_) => token,
|
||||||
.event_handler(Handler::default())
|
Err(_) => {
|
||||||
.framework(framework)
|
error!("Provided token was invalid.");
|
||||||
})
|
return Err(KuranteError::InvalidToken);
|
||||||
.await
|
}
|
||||||
.expect("Error creating client");
|
},
|
||||||
|
Err(e) => {
|
||||||
|
error!("`DISCORD_TOKEN` environment variable was not set. Unable to start bot!");
|
||||||
|
return Err(e.into());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut client = Client::new_with_extras(token, |extras| {
|
||||||
|
extras
|
||||||
|
.event_handler(Handler::default())
|
||||||
|
.framework(framework)
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut data = client.data.write().await;
|
let mut data = client.data.write().await;
|
||||||
data.insert::<DbConnPool>(DbConnPool::new().await);
|
data.insert::<DbConnPool>(DbConnPool::new().await?);
|
||||||
}
|
}
|
||||||
|
|
||||||
// start listening for events by starting a single shard
|
|
||||||
if let Err(why) = client.start().await {
|
if let Err(why) = client.start().await {
|
||||||
println!("An error occurred while running the client: {:?}", why);
|
println!("An error occurred while running the client: {:?}", why);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,30 +1,12 @@
|
||||||
|
use crate::simple_responder;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serenity::async_trait;
|
use serenity::async_trait;
|
||||||
use serenity::model::channel::Message;
|
use serenity::model::channel::Message;
|
||||||
use serenity::prelude::{Context, EventHandler};
|
use serenity::prelude::{Context, EventHandler};
|
||||||
|
|
||||||
pub(crate) struct YellResponder {
|
simple_responder!(
|
||||||
regex: Regex,
|
YellResponder,
|
||||||
}
|
r"A+H{5,}",
|
||||||
|
"its ok ur gonna get a 6* someday"
|
||||||
impl Default for YellResponder {
|
);
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
regex: Regex::new(r"A+H{5,}").unwrap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl EventHandler for YellResponder {
|
|
||||||
async fn message(&self, ctx: Context, message: Message) {
|
|
||||||
let content = &message.content_safe(ctx.clone()).await;
|
|
||||||
if self.regex.is_match(content) {
|
|
||||||
message
|
|
||||||
.channel_id
|
|
||||||
.say(ctx, "its ok ur gonna get a 6* someday")
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,30 +1,12 @@
|
||||||
|
use crate::simple_responder;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serenity::async_trait;
|
use serenity::async_trait;
|
||||||
use serenity::model::channel::Message;
|
use serenity::model::channel::Message;
|
||||||
use serenity::prelude::{Context, EventHandler};
|
use serenity::prelude::{Context, EventHandler};
|
||||||
|
|
||||||
pub(crate) struct BestDoctorResponder {
|
simple_responder!(
|
||||||
regex: Regex,
|
BestDoctorResponder,
|
||||||
}
|
r"[iI].*(?:best|genius) doc",
|
||||||
|
"smol brain doctor..."
|
||||||
impl Default for BestDoctorResponder {
|
);
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
regex: Regex::new(r"[iI].*(?:best|genius) doc").unwrap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl EventHandler for BestDoctorResponder {
|
|
||||||
async fn message(&self, ctx: Context, message: Message) {
|
|
||||||
let content = &message.content_safe(ctx.clone()).await;
|
|
||||||
if self.regex.is_match(content) {
|
|
||||||
message
|
|
||||||
.channel_id
|
|
||||||
.say(ctx, "smol brain doctor..")
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,29 +1,11 @@
|
||||||
|
use crate::simple_responder;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serenity::async_trait;
|
use serenity::async_trait;
|
||||||
use serenity::model::channel::Message;
|
use serenity::model::channel::Message;
|
||||||
use serenity::prelude::{Context, EventHandler};
|
use serenity::prelude::{Context, EventHandler};
|
||||||
|
|
||||||
pub(crate) struct FufufuResponder {
|
simple_responder!(FufufuResponder, r"(?:[fF][uU]){3,}", (get_desu()));
|
||||||
regex: Regex,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for FufufuResponder {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
regex: Regex::new(r"(?:[fF][uU]){3,}").unwrap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl EventHandler for FufufuResponder {
|
|
||||||
async fn message(&self, ctx: Context, message: Message) {
|
|
||||||
let content = &message.content_safe(ctx.clone()).await;
|
|
||||||
if self.regex.is_match(content) {
|
|
||||||
message.channel_id.say(ctx, get_desu()).await.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const DESU_STRINGS: &[&str] = &[
|
const DESU_STRINGS: &[&str] = &[
|
||||||
"です。",
|
"です。",
|
||||||
|
|
|
@ -17,9 +17,9 @@ impl Default for Handler {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
responders: vec![
|
responders: vec![
|
||||||
Box::new(BestDoctorResponder::default()),
|
Box::new(BestDoctorResponder),
|
||||||
Box::new(FufufuResponder::default()),
|
Box::new(FufufuResponder),
|
||||||
Box::new(YellResponder::default()),
|
Box::new(YellResponder),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,3 +33,25 @@ impl EventHandler for Handler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! simple_responder {
|
||||||
|
// $phrase should be `expr`, see https://github.com/dtolnay/async-trait/issues/46
|
||||||
|
// above issue is blocked on rustc bug, see https://github.com/rust-lang/rust/issues/43081
|
||||||
|
($name:tt, $regex:expr, $phrase:tt) => {
|
||||||
|
lazy_static! {
|
||||||
|
static ref REGEX: Regex = Regex::new($regex).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct $name;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl EventHandler for $name {
|
||||||
|
async fn message(&self, ctx: Context, message: Message) {
|
||||||
|
if REGEX.is_match(&message.content_safe(ctx.clone()).await) {
|
||||||
|
message.channel_id.say(ctx, $phrase).await.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use serenity::prelude::TypeMapKey;
|
use serenity::prelude::TypeMapKey;
|
||||||
use sqlx::{
|
use sqlx::{
|
||||||
sqlite::{SqliteConnection, SqlitePool},
|
sqlite::{SqliteConnection, SqlitePool},
|
||||||
Pool,
|
Error, Pool,
|
||||||
};
|
};
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
|
@ -12,22 +12,21 @@ pub(crate) struct DbConnPool {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DbConnPool {
|
impl DbConnPool {
|
||||||
pub async fn new() -> Self {
|
pub async fn new() -> Result<Self, Error> {
|
||||||
Self {
|
Ok(Self {
|
||||||
pool: init_pool().await,
|
pool: init_pool().await?,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
pub async fn get_heck(&self) -> i32 {
|
|
||||||
|
pub async fn get_heck(&self) -> Result<i32, Error> {
|
||||||
sqlx::query!("UPDATE Heck SET count = count + 1")
|
sqlx::query!("UPDATE Heck SET count = count + 1")
|
||||||
.execute(&self.pool)
|
.execute(&self.pool)
|
||||||
.await
|
.await?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
sqlx::query!("SELECT count FROM Heck")
|
Ok(sqlx::query!("SELECT count FROM Heck")
|
||||||
.fetch_one(&self.pool)
|
.fetch_one(&self.pool)
|
||||||
.await
|
.await?
|
||||||
.unwrap()
|
.count)
|
||||||
.count
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,30 +34,26 @@ impl TypeMapKey for DbConnPool {
|
||||||
type Value = Self;
|
type Value = Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn init_pool() -> DbPool {
|
async fn init_pool() -> Result<DbPool, Error> {
|
||||||
let pool = SqlitePool::builder()
|
let pool = SqlitePool::builder()
|
||||||
.build(&env::var("DATABASE_URL").unwrap())
|
.build(&env::var("DATABASE_URL").unwrap())
|
||||||
.await
|
.await?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"CREATE TABLE IF NOT EXISTS Heck (id INTEGER PRIMARY KEY NOT NULL, count INTEGER NOT NULL)"
|
"CREATE TABLE IF NOT EXISTS Heck (id INTEGER PRIMARY KEY NOT NULL, count INTEGER NOT NULL)"
|
||||||
)
|
)
|
||||||
.execute(&pool)
|
.execute(&pool)
|
||||||
.await
|
.await?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
if sqlx::query!("SELECT count FROM Heck")
|
if sqlx::query!("SELECT count FROM Heck")
|
||||||
.fetch_all(&pool)
|
.fetch_all(&pool)
|
||||||
.await
|
.await?
|
||||||
.unwrap()
|
|
||||||
.is_empty()
|
.is_empty()
|
||||||
{
|
{
|
||||||
sqlx::query!("INSERT INTO Heck VALUES (1, 0)")
|
sqlx::query!("INSERT INTO Heck VALUES (1, 0)")
|
||||||
.execute(&pool)
|
.execute(&pool)
|
||||||
.await
|
.await?;
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pool
|
Ok(pool)
|
||||||
}
|
}
|
||||||
|
|
22
src/util/error.rs
Normal file
22
src/util/error.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
pub enum KuranteError {
|
||||||
|
MissingEnvVar(std::env::VarError),
|
||||||
|
Bot(serenity::Error),
|
||||||
|
InvalidToken,
|
||||||
|
Database(sqlx::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates a from implementation from the specified type to the provided
|
||||||
|
/// bunbun error.
|
||||||
|
macro_rules! from_error {
|
||||||
|
($from:ty, $to:ident) => {
|
||||||
|
impl From<$from> for KuranteError {
|
||||||
|
fn from(e: $from) -> Self {
|
||||||
|
Self::$to(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
from_error!(std::env::VarError, MissingEnvVar);
|
||||||
|
from_error!(serenity::Error, Bot);
|
||||||
|
from_error!(sqlx::Error, Database);
|
|
@ -1 +1,2 @@
|
||||||
pub mod db;
|
pub mod db;
|
||||||
|
pub mod error;
|
||||||
|
|
Loading…
Reference in a new issue