Major refactor to prepare for database stuff

This commit is contained in:
August 2024-10-05 00:30:56 -04:00
parent bcc0364f61
commit 2967c743d6
Signed by: shibedrill
GPG Key ID: 5FE0CB25945EFAA2
10 changed files with 243 additions and 173 deletions

167
Cargo.lock generated
View File

@ -41,6 +41,12 @@ dependencies = [
"libc",
]
[[package]]
name = "anyhow"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
[[package]]
name = "arrayvec"
version = "0.7.4"
@ -109,19 +115,6 @@ dependencies = [
"generic-array",
]
[[package]]
name = "build-time"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1219c19fc29b7bfd74b7968b420aff5bc951cf517800176e795d6b2300dd382"
dependencies = [
"chrono",
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.59",
]
[[package]]
name = "bumpalo"
version = "3.16.0"
@ -177,6 +170,20 @@ dependencies = [
"serde_json",
]
[[package]]
name = "cargo_metadata"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037"
dependencies = [
"camino",
"cargo-platform",
"semver",
"serde",
"serde_json",
"thiserror",
]
[[package]]
name = "cc"
version = "1.0.94"
@ -337,6 +344,37 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "derive_builder"
version = "0.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd33f37ee6a119146a1781d3356a7c26028f83d779b2e04ecd45fdc75c76877b"
dependencies = [
"derive_builder_macro",
]
[[package]]
name = "derive_builder_core"
version = "0.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7431fa049613920234f22c47fdc33e6cf3ee83067091ea4277a3f8c4587aae38"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.59",
]
[[package]]
name = "derive_builder_macro"
version = "0.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4abae7035bf79b9877b779505d8cf3749285b80c43941eda66604841889451dc"
dependencies = [
"derive_builder_core",
"syn 2.0.59",
]
[[package]]
name = "digest"
version = "0.10.7"
@ -590,6 +628,12 @@ version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hermit-abi"
version = "0.3.9"
@ -915,6 +959,15 @@ dependencies = [
"autocfg",
]
[[package]]
name = "num_threads"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
dependencies = [
"libc",
]
[[package]]
name = "object"
version = "0.32.2"
@ -1142,9 +1195,9 @@ dependencies = [
[[package]]
name = "regex"
version = "1.10.4"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
dependencies = [
"aho-corasick",
"memchr",
@ -1154,9 +1207,9 @@ dependencies = [
[[package]]
name = "regex-automata"
version = "0.4.6"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
dependencies = [
"aho-corasick",
"memchr",
@ -1165,9 +1218,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.8.3"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "reqwest"
@ -1258,16 +1311,6 @@ dependencies = [
"semver",
]
[[package]]
name = "rustc_version_runtime"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dd18cd2bae1820af0b6ad5e54f4a51d0f3fcc53b05f845675074efcc7af071d"
dependencies = [
"rustc_version",
"semver",
]
[[package]]
name = "rustix"
version = "0.38.32"
@ -1343,6 +1386,12 @@ dependencies = [
"untrusted",
]
[[package]]
name = "rustversion"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
[[package]]
name = "ryu"
version = "1.0.17"
@ -1514,19 +1563,20 @@ dependencies = [
[[package]]
name = "shibe-bot"
version = "0.3.4"
version = "0.4.0"
dependencies = [
"build-time",
"anyhow",
"dotenvy",
"log",
"poise",
"pretty_env_logger",
"rand",
"roux",
"rustc_version_runtime",
"serde",
"serde_json",
"structstruck",
"tokio",
"vergen",
]
[[package]]
@ -1536,7 +1586,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8"
dependencies = [
"bytecount",
"cargo_metadata",
"cargo_metadata 0.14.2",
"error-chain",
"glob",
"pulldown-cmark",
@ -1581,6 +1631,18 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "structstruck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a052ec87a2d9bdd3a35f85ec6a07a5ac0816e4190b1cbede9d67cccb47ea66d"
dependencies = [
"heck",
"proc-macro2",
"quote",
"venial",
]
[[package]]
name = "subtle"
version = "2.5.0"
@ -1691,7 +1753,9 @@ checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [
"deranged",
"itoa",
"libc",
"num-conv",
"num_threads",
"powerfmt",
"serde",
"time-core",
@ -1989,6 +2053,43 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "venial"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61584a325b16f97b5b25fcc852eb9550843a251057a5e3e5992d2376f3df4bb2"
dependencies = [
"proc-macro2",
"quote",
]
[[package]]
name = "vergen"
version = "9.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349ed9e45296a581f455bc18039878f409992999bc1d5da12a6800eb18c8752f"
dependencies = [
"anyhow",
"cargo_metadata 0.18.1",
"derive_builder",
"regex",
"rustc_version",
"rustversion",
"time",
"vergen-lib",
]
[[package]]
name = "vergen-lib"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "229eaddb0050920816cf051e619affaf18caa3dd512de8de5839ccbc8e53abb0"
dependencies = [
"anyhow",
"derive_builder",
"rustversion",
]
[[package]]
name = "version_check"
version = "0.9.4"

View File

@ -3,10 +3,14 @@ name = "shibe-bot"
description = "A Discord bot written in Rust, using Poise."
license = "MIT"
readme = "README.md"
version = "0.3.4"
version = "0.4.0"
edition = "2021"
build = "build.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[build-dependencies]
vergen = { version = "9.0.1", features = ["build", "cargo", "rustc"] }
anyhow = "1.0.89"
[dependencies]
dotenvy = "0.15.0"
@ -18,5 +22,4 @@ rand = "0.8.5"
serde = { version = "1.0.210", features = ["serde_derive"] }
serde_json = "1.0.128"
roux = "2.2.13"
rustc_version_runtime = "0.3.0"
build-time = "0.1.3"
structstruck = "0.4.1"

View File

@ -1,4 +1,4 @@
# Shibe Bot 0.3.4
# Shibe Bot 0.4.0
[![Rust](https://github.com/shibedrill/shibe-bot/actions/workflows/rust.yml/badge.svg)](https://github.com/shibedrill/shibe-bot/actions/workflows/rust.yml)
[![GitHub License](https://img.shields.io/github/license/shibedrill/shibe-bot)](LICENSE.txt)

16
build.rs Normal file
View File

@ -0,0 +1,16 @@
use vergen::*;
use anyhow::Error;
fn main() -> Result<(), Error> {
let build = BuildBuilder::all_build()?;
let cargo = CargoBuilder::all_cargo()?;
let rustc = RustcBuilder::all_rustc()?;
Emitter::default()
.add_instructions(&build)?
.add_instructions(&cargo)?
.add_instructions(&rustc)?
.emit()?;
Ok(())
}

View File

@ -1,8 +1,25 @@
use build_time::build_time_local;
use crate::Context;
use crate::Error;
#[poise::command(slash_command)]
pub async fn version(ctx: Context<'_>) -> Result<(), Error> {
ctx.say(format!(
"Bot version: {}\n\
Build:\n\
\tBuild date: {}\n\
\tBuild timestamp: {}\n\
\tTarget triple: {}\n\
\trustc version: {}\n",
env!("CARGO_PKG_VERSION"),
env!("VERGEN_BUILD_DATE"),
env!("VERGEN_BUILD_TIMESTAMP"),
env!("VERGEN_CARGO_TARGET_TRIPLE"),
env!("VERGEN_RUSTC_SEMVER"),
)).await?;
Ok(())
}
/// Update the bot remotely (Requires updater systemd service)
#[poise::command(slash_command, owners_only, hide_in_help)]
pub async fn update(ctx: Context<'_>) -> Result<(), Error> {
@ -19,7 +36,7 @@ pub async fn update(ctx: Context<'_>) -> Result<(), Error> {
Current version: {}\n\
Timestamp of last build: {}",
env!("CARGO_PKG_VERSION"),
build_time_local!()
env!("VERGEN_BUILD_TIMESTAMP")
))
.await?;
info!("Initialized restart service successfully");

View File

@ -4,8 +4,6 @@ use rand::Rng;
use crate::Context;
use crate::Error;
use build_time::build_time_local;
const INVITE_LINK: &str = "https://discord.com/oauth2/authorize?client_id=1030701552941412382&permissions=116736&response_type=code&redirect_uri=https%3A%2F%2Fdiscordapp.com%2Foauth2%2Fauthorize%3F%26client_id%3D1030701552941412382%26scope%3Dbot&scope=guilds+bot";
/// Add this bot to your server
@ -48,84 +46,14 @@ pub async fn info(ctx: Context<'_>) -> Result<(), Error> {
Poise: <https://docs.rs/poise/latest/poise/>\n\
Rust: <https://www.rust-lang.org/>",
env!("CARGO_PKG_VERSION"),
rustc_version_runtime::version(),
build_time_local!()
env!("VERGEN_RUSTC_SEMVER"),
env!("VERGEN_BUILD_TIMESTAMP"),
))
.await?;
info!("Executed command `info` successfully");
Ok(())
}
/// Add channel to the registry
#[poise::command(slash_command, required_permissions = "MANAGE_CHANNELS")]
pub async fn add_channel(
ctx: Context<'_>,
#[description = "Selected channel"] channel: serenity::Channel,
) -> Result<(), Error> {
ctx.defer_ephemeral().await?;
let config = &mut ctx.data().config_manager.lock().await;
let channel_id = { u64::from(channel.id()) };
match config.channels.iter().find(|item| **item == channel_id) {
None => {
config.channels.push(channel_id);
ctx.say(format!(
"Successfully added <#{channel_id}> to the channel registry."
))
.await?;
}
Some(_) => {
ctx.say(format!("Channel <#{channel_id}> is already in registry."))
.await?;
}
}
config.store().expect("Unable to store config");
info!("Executed command `add_channel` successfully");
Ok(())
}
/// Remove channel from the registry
#[poise::command(slash_command, required_permissions = "MANAGE_CHANNELS")]
pub async fn remove_channel(
ctx: Context<'_>,
#[description = "Selected channel"] channel: serenity::Channel,
) -> Result<(), Error> {
ctx.defer_ephemeral().await?;
let config = &mut ctx.data().config_manager.lock().await;
let channel_id = { u64::from(channel.id()) };
match config.channels.iter().position(|item| *item == channel_id) {
None => {
ctx.say(format!(
"Channel <#{channel_id}> was not in the channel registry."
))
.await?;
}
Some(found) => {
config.channels.remove(found);
ctx.say(format!(
"Successfully removed <#{channel_id}> from the channel registry."
))
.await?;
}
}
config.store().expect("Unable to store config");
info!("Executed command `remove_channel` successfully");
Ok(())
}
/// List channels held in the registry
#[poise::command(slash_command, required_permissions = "MANAGE_CHANNELS")]
pub async fn list_channels(ctx: Context<'_>) -> Result<(), Error> {
ctx.defer_ephemeral().await?;
let config = &mut ctx.data().config_manager.lock().await;
ctx.say(format!(
"Current channel IDs in registry: \n{:#?}",
config.channels
))
.await?;
info!("Executed command `list_channels` successfully");
Ok(())
}
/// Roll a dice with a certain amount of sides, 2 sides is a coin toss
#[poise::command(slash_command)]
pub async fn dice(

30
src/definitions.rs Normal file
View File

@ -0,0 +1,30 @@
// Tokio async crap
use poise::serenity_prelude as serenity;
#[allow(unused_imports)]
use crate::settings::*;
// Data passed to every command (shared state)
pub struct Data {
}
// Errors returnable by a command
pub type Error = Box<dyn std::error::Error + Send + Sync>;
// The full context passed to a command
pub type Context<'a> = poise::Context<'a, Data, Error>;
pub async fn event_handler(
_ctx: &serenity::Context,
_event: &serenity::FullEvent,
_framework: poise::FrameworkContext<'_, Data, Error>,
_data: &Data,
) -> Result<(), Error> {
// Future event handling will go here
// Data will contain the database connection
Ok(())
}

View File

@ -1,10 +1,5 @@
#![forbid(unsafe_code)]
// Tokio async crap
use poise::serenity_prelude::FullEvent;
use std::sync::Arc;
use tokio::sync::Mutex;
// For secure credential handling
use dotenvy::dotenv;
@ -16,10 +11,20 @@ extern crate pretty_env_logger;
#[macro_use]
extern crate log;
// For managing config storage
use serde::{Deserialize, Serialize};
// Definitions
mod definitions;
use crate::definitions::*;
use crate::definitions::event_handler as event_handler;
// Settings manager
mod settings;
use crate::settings::Manager;
#[allow(unused_imports)]
use crate::settings::*;
// Schema in preparation for database
mod schema;
#[allow(unused_imports)]
use crate::schema::*;
// Bot commands
mod command;
@ -32,46 +37,8 @@ use crate::command::{
util::*,
};
// Data passed to every command (shared state)
struct Data {
config_manager: Arc<Mutex<Manager<Settings>>>,
}
// Errors returnable by a command
type Error = Box<dyn std::error::Error + Send + Sync>;
// The full context passed to a command
type Context<'a> = poise::Context<'a, Data, Error>;
// The structure making up the configuration
#[derive(Debug, Serialize, Deserialize, Default)]
struct Settings {
channels: Vec<u64>,
}
// Path at which our settings are stored (currently PWD)
const SETTINGS_PATH: &str = "settings.json";
async fn event_handler(
_ctx: &serenity::Context,
event: &serenity::FullEvent,
_framework: poise::FrameworkContext<'_, Data, Error>,
data: &Data,
) -> Result<(), Error> {
if let FullEvent::ChannelDelete {
channel,
messages: _,
} = event
{
info!("Handling event type: ChannelDelete({})", channel.id);
data.config_manager
.lock()
.await
.channels
.retain(|item| *item != u64::from(channel.id));
}
Ok(())
}
//const SETTINGS_PATH: &str = "settings.json";
// Main function for setup
#[tokio::main]
@ -95,15 +62,6 @@ async fn main() {
// Set up some non privileged intents
let intents = serenity::GatewayIntents::non_privileged();
// Configure persistent options
let config_manager: Arc<Mutex<Manager<Settings>>> = Arc::new(Mutex::new(
Manager::load(SETTINGS_PATH).unwrap_or(Manager::manage(SETTINGS_PATH, Settings::default())),
));
match config_manager.lock().await.store() {
Ok(_) => info!("Stored config successfully"),
Err(e) => error!("Failed to store config: {}", e),
};
// Set up framework
let framework = poise::Framework::builder()
.options(poise::FrameworkOptions {
@ -114,9 +72,6 @@ async fn main() {
// Util
age(),
info(),
add_channel(),
remove_channel(),
list_channels(),
invite(),
dice(),
// Dev
@ -141,7 +96,7 @@ async fn main() {
Box::pin(async move {
poise::builtins::register_globally(ctx, &framework.options().commands).await?;
// Shared data has to go here!!!
Ok(Data { config_manager })
Ok(Data {})
})
})
.build();

19
src/schema.rs Normal file
View File

@ -0,0 +1,19 @@
use structstruck;
use poise::serenity_prelude::*;
structstruck::strike! {
#[allow(dead_code)]
pub struct ReactionRole {
role: Role,
message: Message,
reaction: ReactionType,
variant:
#[allow(dead_code)]
enum ReactionRoleVariant {
Standard,
PermaAdd,
PermaRemove,
Reverse,
}
}
}

View File

@ -10,6 +10,7 @@ pub struct Manager<T: Default + Serialize + for<'a> Deserialize<'a>> {
path: String,
}
#[allow(dead_code)]
impl<T: Default + Serialize + for<'a> Deserialize<'a>> Manager<T> {
/// Instantiate new self if the path contains a valid serialization of
/// the settings structure.