added db
This commit is contained in:
parent
b73cb21a94
commit
1673087e07
9 changed files with 202 additions and 4 deletions
62
Cargo.lock
generated
62
Cargo.lock
generated
|
|
@ -375,6 +375,18 @@ dependencies = [
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fallible-iterator"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fallible-streaming-iterator"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "2.3.0"
|
version = "2.3.0"
|
||||||
|
|
@ -403,6 +415,12 @@ version = "1.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foldhash"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "foreign-types"
|
name = "foreign-types"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
|
|
@ -572,12 +590,30 @@ version = "0.14.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.15.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||||
|
dependencies = [
|
||||||
|
"foldhash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.16.1"
|
version = "0.16.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashlink"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1"
|
||||||
|
dependencies = [
|
||||||
|
"hashbrown 0.15.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
|
@ -884,6 +920,17 @@ version = "0.2.178"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
|
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libsqlite3-sys"
|
||||||
|
version = "0.35.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "133c182a6a2c87864fe97778797e46c7e999672690dc9fa3ee8e241aa4a9c13f"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"pkg-config",
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
|
@ -1140,6 +1187,7 @@ dependencies = [
|
||||||
"dotenv",
|
"dotenv",
|
||||||
"poise",
|
"poise",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
|
"rusqlite",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serenity",
|
"serenity",
|
||||||
|
|
@ -1419,6 +1467,20 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rusqlite"
|
||||||
|
version = "0.37.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "165ca6e57b20e1351573e3729b958bc62f0e48025386970b6e4d29e7a7e71f3f"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"fallible-iterator",
|
||||||
|
"fallible-streaming-iterator",
|
||||||
|
"hashlink",
|
||||||
|
"libsqlite3-sys",
|
||||||
|
"smallvec",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-hash"
|
name = "rustc-hash"
|
||||||
version = "2.1.1"
|
version = "2.1.1"
|
||||||
|
|
|
||||||
|
|
@ -10,4 +10,5 @@ reqwest = "0.12.24"
|
||||||
serde_json = "1.0.145"
|
serde_json = "1.0.145"
|
||||||
serenity = "0.12.5"
|
serenity = "0.12.5"
|
||||||
tokio = { version = "1.21.2", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1.21.2", features = ["macros", "rt-multi-thread"] }
|
||||||
serde = "1.0.228"
|
serde = "1.0.228"
|
||||||
|
rusqlite = { version = "0.37.0", features = ["bundled"] }
|
||||||
9
README.md
Normal file
9
README.md
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
Portfolio roast bot
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
To do:
|
||||||
|
- [ ] Database
|
||||||
|
- [ ] FAQs
|
||||||
|
- [ ] Slash commands
|
||||||
|
- [ ] Portfolio Roast Forum: One tag only
|
||||||
BIN
bot_data.sqlite
Normal file
BIN
bot_data.sqlite
Normal file
Binary file not shown.
|
|
@ -1 +1,2 @@
|
||||||
|
pub mod faq;
|
||||||
pub mod info;
|
pub mod info;
|
||||||
|
|
|
||||||
24
src/commands/faq.rs
Normal file
24
src/commands/faq.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
use crate::{Context, Error};
|
||||||
|
|
||||||
|
#[poise::command(slash_command, subcommands("add", "child2"))]
|
||||||
|
pub async fn faq(_ctx: Context<'_>) -> Result<(), Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A subcommand of `parent`
|
||||||
|
#[poise::command(
|
||||||
|
prefix_command,
|
||||||
|
slash_command,
|
||||||
|
required_permissions = "MANAGE_MESSAGES" // mod only
|
||||||
|
)]
|
||||||
|
pub async fn add(ctx: Context<'_>) -> Result<(), Error> {
|
||||||
|
ctx.say("You invoked the first child command!").await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Another subcommand of `parent`
|
||||||
|
#[poise::command(prefix_command, slash_command)]
|
||||||
|
pub async fn child2(ctx: Context<'_>) -> Result<(), Error> {
|
||||||
|
ctx.say("You invoked the second child command!").await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
1
src/database.rs
Normal file
1
src/database.rs
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod database;
|
||||||
51
src/database/database.rs
Normal file
51
src/database/database.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
// Using SQLite
|
||||||
|
use rusqlite::{Connection, OpenFlags, Result};
|
||||||
|
|
||||||
|
pub fn init_db(filename: &str) -> Result<Connection, rusqlite::Error> {
|
||||||
|
let filepath = Path::new(filename);
|
||||||
|
|
||||||
|
let open_flags = OpenFlags::default();
|
||||||
|
|
||||||
|
let conn = Connection::open_with_flags(filepath, open_flags);
|
||||||
|
|
||||||
|
conn
|
||||||
|
}
|
||||||
|
|
||||||
|
fn table_exists(conn: &Connection, table_name: &str) -> Result<bool> {
|
||||||
|
let exists: bool = conn.query_row(
|
||||||
|
&format!(
|
||||||
|
"SELECT EXISTS(SELECT 1 FROM sqlite_master WHERE type='table' AND name='{}')",
|
||||||
|
table_name
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
|row| row.get(0),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(exists)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_tables(conn: &Connection) -> Result<()> {
|
||||||
|
// FAQ table
|
||||||
|
// ID: Primary Key
|
||||||
|
// FAQ title: string
|
||||||
|
// FAQ description: string
|
||||||
|
let faq_table_exists = table_exists(conn, "faqs").expect("FAQ table exists error");
|
||||||
|
|
||||||
|
if !faq_table_exists {
|
||||||
|
conn.execute(
|
||||||
|
"CREATE TABLE faqs (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
title TEXT NOT NULL,
|
||||||
|
description TEXT NOT NULL
|
||||||
|
)",
|
||||||
|
(),
|
||||||
|
)
|
||||||
|
.expect("FAQ Table Creation error");
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we need to create more tables we'll use this function
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
55
src/main.rs
55
src/main.rs
|
|
@ -1,14 +1,38 @@
|
||||||
use dotenv;
|
use dotenv;
|
||||||
use poise::serenity_prelude as serenity;
|
use poise::serenity_prelude as serenity;
|
||||||
|
use rusqlite::Connection;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
mod commands;
|
mod commands;
|
||||||
|
mod database;
|
||||||
mod events;
|
mod events;
|
||||||
|
use crate::database::database::{init_db, init_tables};
|
||||||
struct Data {}
|
|
||||||
|
|
||||||
// Types used by all command functions
|
// Types used by all command functions
|
||||||
type Error = Box<dyn std::error::Error + Send + Sync>;
|
type Error = Box<dyn std::error::Error + Send + Sync>;
|
||||||
type Context<'a> = poise::Context<'a, Data, Error>;
|
type Context<'a> = poise::Context<'a, Data, Error>;
|
||||||
|
|
||||||
|
pub struct Data {
|
||||||
|
conn: Arc<Mutex<Connection>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Data {
|
||||||
|
// Helper method to safely execute database operations
|
||||||
|
pub async fn execute_db<F, R>(&self, f: F) -> Result<R, Error>
|
||||||
|
where
|
||||||
|
F: FnOnce(&Connection) -> Result<R, rusqlite::Error> + Send + 'static,
|
||||||
|
R: Send + 'static,
|
||||||
|
{
|
||||||
|
let conn = self.conn.clone();
|
||||||
|
tokio::task::spawn_blocking(move || {
|
||||||
|
let conn = conn.blocking_lock();
|
||||||
|
f(&conn)
|
||||||
|
})
|
||||||
|
.await?
|
||||||
|
.map_err(|e| e.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn event_handler(
|
async fn event_handler(
|
||||||
ctx: &serenity::Context,
|
ctx: &serenity::Context,
|
||||||
event: &serenity::FullEvent,
|
event: &serenity::FullEvent,
|
||||||
|
|
@ -24,9 +48,33 @@ async fn event_handler(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn on_error(error: poise::FrameworkError<'_, Data, Error>) {
|
||||||
|
// This is our custom error handler
|
||||||
|
// They are many errors that can occur, so we only handle the ones we want to customize
|
||||||
|
// and forward the rest to the default handler
|
||||||
|
match error {
|
||||||
|
poise::FrameworkError::Setup { error, .. } => panic!("Failed to start bot: {:?}", error),
|
||||||
|
poise::FrameworkError::Command { error, ctx, .. } => {
|
||||||
|
println!("Error in command `{}`: {:?}", ctx.command().name, error,);
|
||||||
|
}
|
||||||
|
error => {
|
||||||
|
if let Err(e) = poise::builtins::on_error(error).await {
|
||||||
|
println!("Error while handling error: {}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
dotenv::dotenv().ok();
|
dotenv::dotenv().ok();
|
||||||
|
|
||||||
|
// SQLite
|
||||||
|
let conn = init_db("bot_data.sqlite").expect("Failed to start database");
|
||||||
|
init_tables(&conn).expect("Failed to init tables");
|
||||||
|
let conn = Arc::new(Mutex::new(conn));
|
||||||
|
|
||||||
|
// Discord bot
|
||||||
let token = std::env::var("DISCORD_TOKEN").expect("missing DISCORD_TOKEN");
|
let token = std::env::var("DISCORD_TOKEN").expect("missing DISCORD_TOKEN");
|
||||||
let intents = serenity::GatewayIntents::non_privileged();
|
let intents = serenity::GatewayIntents::non_privileged();
|
||||||
|
|
||||||
|
|
@ -36,12 +84,13 @@ async fn main() {
|
||||||
event_handler: |ctx, event, framework, data| {
|
event_handler: |ctx, event, framework, data| {
|
||||||
Box::pin(event_handler(ctx, event, framework, data))
|
Box::pin(event_handler(ctx, event, framework, data))
|
||||||
},
|
},
|
||||||
|
on_error: |error| Box::pin(on_error(error)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.setup(|ctx, _ready, framework| {
|
.setup(|ctx, _ready, framework| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
poise::builtins::register_globally(ctx, &framework.options().commands).await?;
|
poise::builtins::register_globally(ctx, &framework.options().commands).await?;
|
||||||
Ok(Data {})
|
Ok(Data { conn })
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue