From 6946ddc9f1c8b358fceddb9d23ae78076bbe6abb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Czy=C5=BC?= Date: Sat, 10 Feb 2024 18:52:35 +0100 Subject: [PATCH] codebase migration to poise --- Cargo.lock | 77 +++++++++++++++++ Cargo.toml | 1 + src/commands/kashi/kashi.rs | 14 ++-- src/commands/tools/ping.rs | 21 +++-- src/main.rs | 163 ++++++++++++++++++++++++------------ 5 files changed, 206 insertions(+), 70 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 50079af..db60f44 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -340,6 +340,41 @@ dependencies = [ "zeroize", ] +[[package]] +name = "darling" +version = "0.20.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc5d6b04b3fd0ba9926f945895de7d806260a2d7431ba82e7edaecb043c4c6b8" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04e48a959bcd5c761246f5d090ebc2fbf7b9cd527a492b07a67510c108f1e7e3" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.48", +] + +[[package]] +name = "darling_macro" +version = "0.20.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1545d67a2149e1d93b7e5c7752dce5a7426eb5d1357ddcfd89336b94444f77" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.48", +] + [[package]] name = "dashmap" version = "5.5.3" @@ -785,6 +820,12 @@ dependencies = [ "cc", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.5.0" @@ -896,6 +937,7 @@ version = "0.3.0" dependencies = [ "dotenv", "openssl", + "poise", "regex", "reqwest", "serenity", @@ -1247,6 +1289,35 @@ dependencies = [ "pnet_base", ] +[[package]] +name = "poise" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1819d5a45e3590ef33754abce46432570c54a120798bdbf893112b4211fa09a6" +dependencies = [ + "async-trait", + "derivative", + "futures-util", + "parking_lot", + "poise_macros", + "regex", + "serenity", + "tokio", + "tracing", +] + +[[package]] +name = "poise_macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fa2c123c961e78315cd3deac7663177f12be4460f5440dbf62a7ed37b1effea" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "poly1305" version = "0.8.0" @@ -1976,6 +2047,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "subtle" version = "2.5.0" diff --git a/Cargo.toml b/Cargo.toml index 04a48d7..11c90ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] dotenv = "0.15.0" openssl = { version = "0.10.63", features = ["vendored"] } +poise = "0.6.1" regex = "1.10.3" reqwest = "0.11.23" serenity = { version = "0.12.0", features = ["cache", "framework", "standard_framework", "voice"] } diff --git a/src/commands/kashi/kashi.rs b/src/commands/kashi/kashi.rs index 746bffb..5719546 100644 --- a/src/commands/kashi/kashi.rs +++ b/src/commands/kashi/kashi.rs @@ -1,10 +1,10 @@ -use serenity::{all::Message, client::Context, framework::standard::{macros::command, CommandResult}}; +use crate::{Context, Error}; -use crate::commands::misc::check_msg; - -#[command] -async fn kashi(ctx: &Context, msg: &Message) -> CommandResult { - check_msg(msg.reply(ctx, "Kashi lyrics platform integration").await); +#[poise::command(prefix_command, slash_command)] +pub async fn kashi(ctx: Context<'_>) -> Result<(), Error> { + + let response = format!("Kashi platform is currently under construction!"); + ctx.say(response).await?; Ok(()) -} \ No newline at end of file +} diff --git a/src/commands/tools/ping.rs b/src/commands/tools/ping.rs index b378806..ed8deb5 100644 --- a/src/commands/tools/ping.rs +++ b/src/commands/tools/ping.rs @@ -1,17 +1,16 @@ +use crate::{Context, Error}; use std::time::SystemTime; -use serenity::{all::Message, client::Context, framework::standard::{macros::command, CommandResult}}; +#[poise::command(prefix_command, slash_command)] +pub async fn ping(ctx: Context<'_>) -> Result<(), Error> { + let system_now = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap().as_millis() as i64; -use crate::commands::misc::check_msg; + let message_now = ctx.created_at().timestamp_millis(); -#[command] -async fn ping(ctx: &Context, msg: &Message) -> CommandResult { - let system_now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_millis() as i64; - let message_now = msg.timestamp.timestamp_millis(); - - // println!("System Time: {} ||| Message Time: {}", system_now, message_now); - - check_msg(msg.reply(ctx, format!("Pong! (latency: {} ms)", system_now - message_now)).await); + let response = format!("Pong! (latency: {} ms)", system_now - message_now); + ctx.say(response).await?; Ok(()) -} \ No newline at end of file +} diff --git a/src/main.rs b/src/main.rs index 0b12fb4..575860f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,27 +1,13 @@ -use serenity::gateway::ActivityData; -use serenity::model::prelude::Message; use songbird::SerenityInit; -use reqwest::Client as HttpClient; - -use serenity::client::Context; - -use serenity::{ - async_trait, - client::{Client, EventHandler}, - framework::{ - standard::{macros::group, macros::hook, Configuration}, - StandardFramework, - }, - model::gateway::Ready, - prelude::GatewayIntents, -}; - -use tracing::info; +use poise::serenity_prelude::{self as serenity, ActivityData}; +use std::sync::Arc; +use std::time::Duration; +use tracing::{info, warn, error}; mod commands; -// music management commands +// commands: music use crate::commands::music::deafen::*; use crate::commands::music::join::*; use crate::commands::music::leave::*; @@ -34,57 +20,130 @@ use crate::commands::music::loopcurrent::*; use crate::commands::music::pause::*; use crate::commands::music::resume::*; -// tools +// commands: tools use crate::commands::tools::ping::*; -// kashi +// commands: kashi use crate::commands::kashi::kashi::*; -struct Handler; +type Error = Box; +type Context<'a> = poise::Context<'a, Data, Error>; -#[async_trait] -impl EventHandler for Handler { - async fn ready(&self, ctx: Context, ready: Ready) { - info!("{} [{}] connected successfully!", ready.user.name, ready.user.id); - let prefix = std::env::var("PREFIX").expect("Environment variable `PREFIX` not found!"); - ctx.set_activity(Some(ActivityData::listening(prefix + "help"))); +pub struct Data; + +async fn on_error(error: poise::FrameworkError<'_, Data, Error>) { + match error { + poise::FrameworkError::Setup { error, .. } => panic!("Failed to start bot {:?}", error), + poise::FrameworkError::Command { error, ctx, .. } => { + warn!("Error in command `{}`: {:?}", ctx.command().name, error); + } + error => { + if let Err(e) = poise::builtins::on_error(error).await { + error!("Error while handling error: {}", e) + } + } } } -#[hook] -async fn before(_: &Context, msg: &Message, command_name: &str) -> bool { - info!( - "Received command [{}] from user [{}]", - command_name, msg.author.name - ); - true +// this is for debug only +#[poise::command(prefix_command)] +pub async fn register(ctx: Context<'_>) -> Result<(), Error> { + poise::builtins::register_application_commands_buttons(ctx).await?; + Ok(()) } -#[group] -#[commands( - join, deafen, leave, mute, play, ping, kashi, queue, stop, skip, loopcurrent, pause, resume -)] -struct General; - #[tokio::main] async fn main() { - dotenv::dotenv().expect("Failed to load .env file."); + // logger and dotenv initialization tracing_subscriber::fmt::init(); + dotenv::dotenv().expect("Failed to load .env file."); - let token = - std::env::var("DISCORD_TOKEN").expect("Environment variable `DISCORD_TOKEN` not found!"); + let token = std::env::var("DISCORD_TOKEN").expect("Environment variable `DISCORD_TOKEN` not found!"); let prefix = std::env::var("PREFIX").expect("Environment variable `PREFIX` not found!"); - let framework = StandardFramework::new().before(before).group(&GENERAL_GROUP); - framework.configure(Configuration::new().prefix(prefix)); + let commands = vec![ + // commands: music + deafen(), + join(), + leave(), + loopcurrent(), + mute(), + pause(), + play(), + queue(), + resume(), + skip(), + stop(), + // commands: tools + ping(), + // commands: kashi + kashi(), + // commands: debug + register(), + ]; - let intents = GatewayIntents::non_privileged() | GatewayIntents::MESSAGE_CONTENT; + let options = poise::FrameworkOptions { + commands, + prefix_options: poise::PrefixFrameworkOptions { + prefix: Some(prefix.to_string().into()), + edit_tracker: Some(Arc::new(poise::EditTracker::for_timespan( + Duration::from_secs(3600), + ))), + additional_prefixes: vec![], + ..Default::default() + }, - let mut client = Client::builder(&token, intents) + on_error: |error| Box::pin(on_error(error)), + + pre_command: |ctx| { + Box::pin(async move { + info!("Executing command {}...", ctx.command().qualified_name); + }) + }, + + post_command: |ctx| { + Box::pin(async move { + info!("Executed command {}!", ctx.command().qualified_name); + }) + }, + + command_check: Some(|ctx| { + Box::pin(async move { + if ctx.author().id == 123456789 { + return Ok(false); + } + Ok(true) + }) + }), + + skip_checks_for_owners: false, + event_handler: |_ctx, event, _framework, _data| { + Box::pin(async move { + info!("Got an event in event handler: {:?}", event.snake_case_name()); + Ok(()) + }) + }, + ..Default::default() + }; + + let framework = poise::Framework::builder() + .setup(move |ctx, ready, _framework| { + Box::pin(async move { + info!("{} [{}] connected successfully!", ready.user.name, ready.user.id); + ctx.set_activity(Some(ActivityData::listening(prefix + "help"))); + // poise::builtins::register_globally(ctx, &framework.options().commands).await?; + + Ok(Data {}) + }) + }) + .options(options) + .build(); + + let intents = serenity::GatewayIntents::non_privileged() | serenity::GatewayIntents::MESSAGE_CONTENT; + + let mut client = serenity::ClientBuilder::new(token, intents) .framework(framework) .register_songbird() - .event_handler(Handler) - .type_map_insert::(HttpClient::new()) .await .expect("Error creating client"); @@ -92,9 +151,9 @@ async fn main() { let _ = client .start() .await - .map_err(|why| println!("Client ended: {:?}", why)); + .map_err(|why| error!("Client ended: {:?}", why)); }); let _signal_err = tokio::signal::ctrl_c().await; - println!("Recieved Ctrl-C, shutting down."); + warn!("Recieved Ctrl-C, shutting down."); }