diff --git a/Cargo.lock b/Cargo.lock index 9a0b079..62d1adc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1093,6 +1093,7 @@ dependencies = [ "fercord_storage", "interim", "poise", + "rand", "rstest", "serde", "serde_json", @@ -3551,9 +3552,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", @@ -3572,9 +3573,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", diff --git a/fercord_bot/CHANGELOG.md b/fercord_bot/CHANGELOG.md index 26131f9..abfb82e 100644 --- a/fercord_bot/CHANGELOG.md +++ b/fercord_bot/CHANGELOG.md @@ -6,6 +6,8 @@ ### Added - feat: `/reminder` not also accepts `[day|tomorrow] at [hour][am|pm]` inputs. +- feat: `/roll` command to roll dice (up to 255d255) +- feat: `@bot register` prefix-command to register slash commands ## [0.3.5] - 2024-12-02 - chore: Update dependencies diff --git a/fercord_bot/Cargo.toml b/fercord_bot/Cargo.toml index 87fd07c..7014cb7 100644 --- a/fercord_bot/Cargo.toml +++ b/fercord_bot/Cargo.toml @@ -21,13 +21,14 @@ poise = { workspace = true} serde = { workspace = true} serde_json = { workspace = true} tracing = { workspace = true } -tracing-subscriber = {version = "0.3", features = ["default", "env-filter"]} chrono = { workspace = true } chrono-tz = { workspace = true } interim = { workspace = true } uuid = { workspace = true } tokio = { workspace = true } anyhow = { workspace = true } +tracing-subscriber = {version = "0.3", features = ["default", "env-filter"]} +rand = "0.8" [dev-dependencies] diff --git a/fercord_bot/src/discord/commands.rs b/fercord_bot/src/discord/commands.rs index d4cdd19..965dd97 100644 --- a/fercord_bot/src/discord/commands.rs +++ b/fercord_bot/src/discord/commands.rs @@ -1,21 +1,32 @@ -use anyhow::{anyhow, Result}; +use std::num::NonZeroU8; + +use anyhow::{anyhow, Result, Context as AnyhowContext}; use chrono::{DateTime, Utc}; use chrono_tz::{Tz, TZ_VARIANTS}; use interim::{parse_date_string, Dialect}; use poise::serenity_prelude as serenity; use tracing::{debug, event, field, trace_span, warn, Level}; +use rand::prelude::*; -use fercord_storage::prelude::{ - db::Repository, - model::{guild_timezone::GuildTimezone, reminder::Reminder}, - *, -}; - +use fercord_storage::prelude::{*, guild_timezone::GuildTimezone}; use crate::discord::Context; const FROM_NOW: &str = "from now"; const AT: &str = "at"; +/// Register slash commands +#[poise::command(prefix_command)] +pub async fn register(ctx: Context<'_>) -> Result<()> { + let span = trace_span!( + "fercord.discord.register", + ); + let _enter = span.enter(); + + poise::builtins::register_application_commands_buttons(ctx).await.context("Error registering slash commands")?; + + Ok(()) +} + /// Set the timezone for this server (used by time related commands). #[poise::command(slash_command)] pub async fn timezone( @@ -75,6 +86,41 @@ pub async fn timezone( } } +/// Roll dice +/// +/// * count: The amount of dice to roll +/// * sides: the sides on the dice +#[poise::command(slash_command)] +pub async fn roll(ctx: Context<'_>, + #[description = "How many dice do you want to roll?"] #[min = 1] #[max = 255] count: NonZeroU8, + #[description = "How many sides does the dice have?"] #[min = 2] #[max = 255] sides: NonZeroU8, +) -> Result<()> { + let span = trace_span!( + "fercord.discord.roll", + guild_id = field::Empty, + die_command = "{count}d{sides}" + ); + let _enter = span.enter(); + event!(Level::TRACE, "Received roll command for {count}d{sides}"); + let guild_id = ctx.guild_id().context("Error retrieving guild id")?; + span.record("guild_id", field::debug(&guild_id)); + + ctx.defer_ephemeral().await?; + + let mut rng = rand::thread_rng(); + + let mut rolls: Vec = Vec::with_capacity(count.get() as usize); + rolls.resize(count.get().into(), Default::default()); + rolls.fill_with(move || rng.gen_range(1..=(sides.get() as usize))); + + let roll_total = rolls.into_iter().sum::(); + event!(Level::TRACE, "Rolled {count}d{sides} for a total value of {roll_total}"); + + ctx.say(format!("You rolled {count}d{sides} for a total value of {roll_total}")).await?; + + Ok(()) +} + /// Create a reminder /// /// * when: When to remind you diff --git a/fercord_bot/src/main.rs b/fercord_bot/src/main.rs index 83f97ca..76cc467 100755 --- a/fercord_bot/src/main.rs +++ b/fercord_bot/src/main.rs @@ -1,4 +1,6 @@ use anyhow::Context; +use discord::commands::register; +use discord::commands::roll; use poise::serenity_prelude::{self as serenity, ActivityData}; use tracing::*; @@ -42,11 +44,11 @@ async fn main() -> anyhow::Result<()> { let db_pool = db::setup(config.database_url.as_ref()) .await - .with_context(|| "Error setting up database connection")?; + .context("Error setting up database connection")?; // KV Setup event!(Level::DEBUG, "Connecting to KV Store"); - let kv_client = KVClient::new(&config).with_context(|| "Error building redis client")?; + let kv_client = KVClient::new(&config).context("Error building redis client")?; // Discord setup event!(Level::DEBUG, "Discord client setup"); @@ -54,7 +56,7 @@ async fn main() -> anyhow::Result<()> { let discord_config = config.clone(); let framework = poise::Framework::builder() .options(poise::FrameworkOptions { - commands: vec![reminder(), timezone()], + commands: vec![reminder(), timezone(), roll(), register()], ..Default::default() }) .setup(|ctx, _ready, framework| { @@ -64,7 +66,7 @@ async fn main() -> anyhow::Result<()> { Box::pin(async move { poise::builtins::register_globally(ctx, &framework.options().commands) .await - .with_context(|| "Error creating Discord client")?; + .context("Error creating Discord client")?; Ok(ServerData { kv_client, diff --git a/fercord_storage/CHANGELOG.md b/fercord_storage/CHANGELOG.md index 64dc5bd..09c5d87 100644 --- a/fercord_storage/CHANGELOG.md +++ b/fercord_storage/CHANGELOG.md @@ -3,6 +3,8 @@ ## [Unreleased] - ReleaseDate +## Changed +- prelude now includes a lot more types ## [0.3.5] - 2024-12-02 - chore: Update dependencies diff --git a/fercord_storage/src/lib.rs b/fercord_storage/src/lib.rs index c7aff4f..e183ce5 100755 --- a/fercord_storage/src/lib.rs +++ b/fercord_storage/src/lib.rs @@ -15,7 +15,7 @@ pub mod db; pub mod prelude { pub use sqlx_oldapi::any::AnyPool; - pub use crate::db; + pub use crate::db::{self, *}; pub use crate::kv::{Identifiable, KVClient, KVIdentity}; - pub use crate::model; + pub use crate::model::{self, *}; } diff --git a/fercord_storage/src/model/mod.rs b/fercord_storage/src/model/mod.rs index d8d71ce..2d2de20 100755 --- a/fercord_storage/src/model/mod.rs +++ b/fercord_storage/src/model/mod.rs @@ -5,3 +5,6 @@ pub mod reminder; /// Store guild timezones as setting data pub mod guild_timezone; + +pub use reminder::*; +pub use guild_timezone::*; \ No newline at end of file