From b32a966872fde6c01c7ea8e0b3cd7cbf118f31f5 Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Wed, 24 Jan 2024 16:42:59 +0100 Subject: [PATCH] chore: update serenity examples after 0.37 --- examples/poise.mdx | 26 ++++--- examples/serenity-todo.mdx | 155 +++++++++++++++++++------------------ examples/serenity.mdx | 6 +- 3 files changed, 95 insertions(+), 92 deletions(-) diff --git a/examples/poise.mdx b/examples/poise.mdx index 405ad39..849ad51 100644 --- a/examples/poise.mdx +++ b/examples/poise.mdx @@ -14,9 +14,9 @@ This example shows how to build a Poise bot with Shuttle that responds to the `/ ```rust src/main.rs use anyhow::Context as _; -use poise::serenity_prelude as serenity; +use poise::serenity_prelude::{ClientBuilder, GatewayIntents}; use shuttle_secrets::SecretStore; -use shuttle_poise::ShuttlePoise; +use shuttle_serenity::ShuttleSerenity; struct Data {} // User data, which is stored and accessible in all command invocations type Error = Box; @@ -30,7 +30,7 @@ async fn hello(ctx: Context<'_>) -> Result<(), Error> { } #[shuttle_runtime::main] -async fn poise(#[shuttle_secrets::Secrets] secret_store: SecretStore) -> ShuttlePoise { +async fn main(#[shuttle_secrets::Secrets] secret_store: SecretStore) -> ShuttleSerenity { // Get the discord token set in `Secrets.toml` let discord_token = secret_store .get("DISCORD_TOKEN") @@ -41,19 +41,20 @@ async fn poise(#[shuttle_secrets::Secrets] secret_store: SecretStore) -> Shuttle commands: vec![hello()], ..Default::default() }) - .token(discord_token) - .intents(serenity::GatewayIntents::non_privileged()) .setup(|ctx, _ready, framework| { Box::pin(async move { poise::builtins::register_globally(ctx, &framework.options().commands).await?; Ok(Data {}) }) }) - .build() + .build(); + + let client = ClientBuilder::new(discord_token, GatewayIntents::non_privileged()) + .framework(framework) .await .map_err(shuttle_runtime::CustomError::new)?; - Ok(framework.into()) + Ok(client.into()) } ``` @@ -63,19 +64,20 @@ DISCORD_TOKEN = 'the contents of your discord token' ```toml Cargo.toml [package] -name = "hello-world" +name = "hello-world-poise-bot" version = "0.1.0" edition = "2021" publish = false [dependencies] -anyhow = "1.0.71" -poise = "0.5.5" -shuttle-poise = "0.37.0" +anyhow = "1.0.68" +poise = "0.6.1" shuttle-runtime = "0.37.0" shuttle-secrets = "0.37.0" +# Since poise is a serenity command framework, it can run on Shuttle with shuttle-serenity +shuttle-serenity = "0.37.0" tracing = "0.1.37" -tokio = "1.28.2" +tokio = "1.26.0" ``` diff --git a/examples/serenity-todo.mdx b/examples/serenity-todo.mdx index 252745a..a0ef024 100644 --- a/examples/serenity-todo.mdx +++ b/examples/serenity-todo.mdx @@ -28,12 +28,13 @@ For this example we also need a `GuildId`. For more information please refer to the [Discord docs](https://discord.com/developers/docs/getting-started) as well as the [Serenity repo](https://github.com/serenity-rs/serenity) for more examples. -```Rust src/main.rs +```rust src/main.rs use anyhow::Context as _; use serenity::async_trait; -use serenity::model::application::command::CommandOptionType; -use serenity::model::application::interaction::application_command::CommandDataOptionValue; -use serenity::model::application::interaction::{Interaction, InteractionResponseType}; +use serenity::builder::{ + CreateCommand, CreateCommandOption, CreateInteractionResponse, CreateInteractionResponseMessage, +}; +use serenity::model::application::{CommandDataOptionValue, CommandOptionType, Interaction}; use serenity::model::gateway::Ready; use serenity::model::id::GuildId; use serenity::prelude::*; @@ -51,54 +52,52 @@ struct Bot { #[async_trait] impl EventHandler for Bot { async fn interaction_create(&self, ctx: Context, interaction: Interaction) { - let user_id: i64 = interaction - .clone() - .application_command() - .unwrap() - .user - .id - .into(); - - if let Interaction::ApplicationCommand(command) = interaction { + if let Interaction::Command(command) = interaction { info!("Received command interaction: {:#?}", command); + let user_id: i64 = command.user.id.into(); + let content = match command.data.name.as_str() { "todo" => { - let command = command.data.options.get(0).expect("Expected command"); + let command = command.data.options.first().expect("Expected command"); - // if the todo subcommand has a CommandOption the command is either `add` or `complete` - if let Some(subcommand) = command.options.get(0) { - match subcommand.resolved.as_ref().expect("Valid subcommand") { - CommandDataOptionValue::String(note) => { + match command.name.as_str() { + "add" => match &command.value { + CommandDataOptionValue::SubCommand(opts) => { + let note = opts.first().unwrap().value.as_str().unwrap(); db::add(&self.database, note, user_id).await.unwrap() } - CommandDataOptionValue::Integer(index) => { - db::complete(&self.database, index, user_id) + _ => "Command not implemented".to_string(), + }, + "complete" => match &command.value { + CommandDataOptionValue::SubCommand(opts) => { + let index = opts.first().unwrap().value.as_i64().unwrap(); + db::complete(&self.database, &index, user_id) .await .unwrap_or_else(|_| { "Please submit a valid index from your todo list" .to_string() }) } - _ => "Please enter a valid todo".to_string(), - } - // if the todo subcommand doesn't have a CommandOption the command is `list` - } else { - db::list(&self.database, user_id).await.unwrap() + _ => "Command not implemented".to_string(), + }, + "list" => db::list(&self.database, user_id).await.unwrap(), + _ => "Command not implemented".to_string(), } } _ => "Command not implemented".to_string(), }; if let Err(why) = command - .create_interaction_response(&ctx.http, |response| { - response - .kind(InteractionResponseType::ChannelMessageWithSource) - .interaction_response_data(|message| message.content(content)) - }) + .create_response( + &ctx.http, + CreateInteractionResponse::Message( + CreateInteractionResponseMessage::new().content(content), + ), + ) .await { - error!("Cannot respond to slash command: {}", why); + error!("Cannot respond to slash command: {why}"); } } } @@ -106,51 +105,53 @@ impl EventHandler for Bot { async fn ready(&self, ctx: Context, ready: Ready) { info!("{} is connected!", ready.user.name); - let guild_id = GuildId(self.guild_id.parse().unwrap()); + let guild_id = GuildId::new(self.guild_id.parse().unwrap()); - let _ = GuildId::set_application_commands(&guild_id, &ctx.http, |commands| { - commands.create_application_command(|command| { - command - .name("todo") + let _ = guild_id + .set_commands( + &ctx.http, + vec![CreateCommand::new("todo") .description("Add, list and complete todos") - .create_option(|option| { - option - .name("add") - .description("Add a new todo") - .kind(CommandOptionType::SubCommand) - .create_sub_option(|option| { - option - .name("note") - .description("The todo note to add") - .kind(CommandOptionType::String) - .min_length(2) - .max_length(100) - .required(true) - }) - }) - .create_option(|option| { - option - .name("complete") - .description("The todo to complete") - .kind(CommandOptionType::SubCommand) - .create_sub_option(|option| { - option - .name("index") - .description("The index of the todo to complete") - .kind(CommandOptionType::Integer) - .min_int_value(1) - .required(true) - }) - }) - .create_option(|option| { - option - .name("list") - .description("List your todos") - .kind(CommandOptionType::SubCommand) - }) - }) - }) - .await; + .add_option( + CreateCommandOption::new( + CommandOptionType::SubCommand, + "add", + "Add a new todo", + ) + .add_sub_option( + CreateCommandOption::new( + CommandOptionType::String, + "note", + "The todo note to add", + ) + .min_length(2) + .max_length(100) + .required(true), + ), + ) + .add_option( + CreateCommandOption::new( + CommandOptionType::SubCommand, + "complete", + "The todo to complete", + ) + .add_sub_option( + CreateCommandOption::new( + CommandOptionType::Integer, + "index", + "The index of the todo to complete", + ) + .min_int_value(1) + .required(true), + ), + ) + .add_option(CreateCommandOption::new( + CommandOptionType::SubCommand, + "list", + "List your todos", + ))], + ) + .await; } } @@ -260,17 +261,17 @@ GUILD_ID = "123456789" ```toml Cargo.toml [package] -name = "serenity-postgres" +name = "postgres-serenity-bot" version = "0.1.0" edition = "2021" [dependencies] anyhow = "1.0.66" serde = "1.0.148" -serenity = { version = "0.11.5", default-features = false, features = ["client", "gateway", "rustls_backend", "model"] } +serenity = { version = "0.12.0", default-features = false, features = ["client", "gateway", "rustls_backend", "model"] } +shuttle-runtime = "0.37.0" shuttle-secrets = "0.37.0" shuttle-serenity = "0.37.0" -shuttle-runtime = "0.37.0" shuttle-shared-db = { version = "0.37.0", features = ["postgres", "sqlx"] } sqlx = "0.7.1" tokio = "1.26.0" diff --git a/examples/serenity.mdx b/examples/serenity.mdx index 4f88d50..4592349 100644 --- a/examples/serenity.mdx +++ b/examples/serenity.mdx @@ -84,16 +84,16 @@ DISCORD_TOKEN = 'the contents of your discord token' ```toml Cargo.toml [package] -name = "hello-world" +name = "hello-world-serenity-bot" version = "0.1.0" edition = "2021" [dependencies] anyhow = "1.0.66" -shuttle-serenity = "0.37.0" +serenity = { version = "0.12.0", default-features = false, features = ["client", "gateway", "rustls_backend", "model"] } shuttle-runtime = "0.37.0" -serenity = { version = "0.11.5", default-features = false, features = ["client", "gateway", "rustls_backend", "model"] } shuttle-secrets = "0.37.0" +shuttle-serenity = "0.37.0" tokio = "1.26.0" tracing = "0.1.37" ```