### Basic Ping Bot Example Source: https://github.com/serenity-rs/serenity/blob/current/examples/README.md A bare minimum Serenity application. This is a good starting point for new users. ```rust fn main() { // TODO: Add example code here } ``` -------------------------------- ### Create and connect a bot client with Serenity Source: https://context7.com/serenity-rs/serenity/llms.txt This example demonstrates how to create a Serenity client, handle basic events like receiving messages and bot readiness, and start the bot. Ensure the DISCORD_TOKEN environment variable is set and the necessary gateway intents are enabled. ```rust use std::env; use serenity::async_trait; use serenity::model::channel::Message; use serenity::model::gateway::Ready; use serenity::prelude::*; struct Handler; #[async_trait] impl EventHandler for Handler { async fn message(&self, ctx: Context, msg: Message) { if msg.content == "!ping" { if let Err(why) = msg.channel_id.say(&ctx.http, "Pong!").await { println!("Error sending message: {why:?}"); } } } async fn ready(&self, _: Context, ready: Ready) { println!("{} is connected!", ready.user.name); } } #[tokio::main] async fn main() { let token = env::var("DISCORD_TOKEN").expect("Expected DISCORD_TOKEN in environment"); // Declare exactly which gateway events your bot needs (required since Discord API v10). let intents = GatewayIntents::GUILD_MESSAGES | GatewayIntents::DIRECT_MESSAGES | GatewayIntents::MESSAGE_CONTENT; // privileged – enable in the developer portal let mut client = Client::builder(&token, intents) .event_handler(Handler) .await .expect("Error creating client"); // Start a single shard; automatically reconnects with exponential back-off. if let Err(why) = client.start().await { println!("Client error: {why:?}"); } } ``` -------------------------------- ### Start Multiple Shards for Large Discord Bots Source: https://context7.com/serenity-rs/serenity/llms.txt For bots in over 2500 guilds, Discord requires sharding. This example demonstrates starting a specific number of shards or using autosharding. It also includes a background task to monitor shard status and latency. ```rust use serenity::prelude::*; use std::env; use std::time::Duration; use tokio::time::sleep; #[tokio::main] async fn main() { let token = env::var("DISCORD_TOKEN").unwrap(); let intents = GatewayIntents::GUILD_MESSAGES | GatewayIntents::MESSAGE_CONTENT; let mut client = Client::builder(&token, intents) .await .expect("Error creating client"); // Clone the shard manager to inspect shards in a background task. let manager = client.shard_manager.clone(); tokio::spawn(async move { loop { sleep(Duration::from_secs(30)).await; let runners = manager.runners.lock().await; for (id, runner) in runners.iter() { println!("Shard {id}: stage={:?} latency={:?}", runner.stage, runner.latency); } } }); // Start 2 shards (Discord requires at least ~5s between shard logins). if let Err(why) = client.start_shards(2).await { eprintln!("Client error: {why:?}"); } // Alternatively: // client.start_autosharded().await?; // Discord decides shard count // client.start_shard(0, 4).await?; // shard 0 out of 4 (for multi-process setups) // client.start_shard_range(0..2, 4).await?; // shards 0–1 out of 4 } ``` -------------------------------- ### StandardFramework Prefix Commands Example Source: https://context7.com/serenity-rs/serenity/llms.txt This example shows how to set up a bot with prefix-based commands using Serenity's StandardFramework. It includes command definitions, a hook, and the main client initialization. Note that StandardFramework is deprecated. ```rust #![allow(deprecated)] use serenity::async_trait; use serenity::framework::standard::macros::{command, group, hook}; use serenity::framework::standard::{Args, CommandResult, Configuration, StandardFramework}; use serenity::model::channel::Message; use serenity::prelude::*; #[group] #[commands(ping, multiply)] struct General; #[hook] async fn before(ctx: &Context, msg: &Message, cmd: &str) -> bool { println!("Running `{cmd}` invoked by `{}`", msg.author.tag()); true // returning false cancels the command } #[command] async fn ping(ctx: &Context, msg: &Message) -> CommandResult { msg.reply(ctx, "Pong!").await?; Ok(()) } #[command] async fn multiply(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult { let a = args.single::()?; let b = args.single::()?; msg.reply(ctx, format!("{a} × {b} = {}", a * b)).await?; Ok(()) } #[tokio::main] async fn main() { let token = std::env::var("DISCORD_TOKEN").unwrap(); let framework = StandardFramework::new().before(before).group(&GENERAL_GROUP); framework.configure(Configuration::new().prefix("~")); let intents = GatewayIntents::GUILD_MESSAGES | GatewayIntents::DIRECT_MESSAGES | GatewayIntents::MESSAGE_CONTENT; let mut client = Client::builder(&token, intents) .framework(framework) .await .unwrap(); client.start().await.unwrap(); } ``` -------------------------------- ### Run Discord Bot Example with SQLite Source: https://github.com/serenity-rs/serenity/blob/current/examples/e16_sqlite_database/README.md Compile and run the Discord bot example. Note the workaround for a SQLx bug requiring the full path to DATABASE_URL during compilation. The DISCORD_TOKEN is also required. ```sh # Note: due to a bug in SQLx (https://github.com/launchbadge/sqlx/issues/3099), you have to provide the full path to `DATABASE_URL` when compiling. # Once the bug is fixed, you can omit `DATABASE_URL=...` and let SQLx read the `.env` file. DATABASE_URL=sqlite:examples/e16_sqlite_database/database.sqlite DISCORD_TOKEN=... cargo run ``` -------------------------------- ### Add Documentation Comment Example Source: https://github.com/serenity-rs/serenity/blob/current/CONTRIBUTING.md Example of a documentation comment in Rust, demonstrating how to categorize information using '#' and create intra-doc links. ```rust /// # Error /// /// This function will return an error if the user could not be found in the cache. ``` -------------------------------- ### Basic Ping-Pong Bot with Serenity Source: https://github.com/serenity-rs/serenity/blob/current/README.md A simple example of a Discord bot that responds to a "!ping" command with "Pong!". It demonstrates setting up the client, defining an event handler for message creation, and starting the bot. Ensure the DISCORD_TOKEN environment variable is set. ```rust use std::env; use serenity::async_trait; use serenity::model::channel::Message; use serenity::prelude::*; struct Handler; #[async_trait] impl EventHandler for Handler { async fn message(&self, ctx: Context, msg: Message) { if msg.content == "!ping" { if let Err(why) = msg.channel_id.say(&ctx.http, "Pong!").await { println!("Error sending message: {why:?}"); } } } } #[tokio::main] async fn main() { // Login with a bot token from the environment let token = env::var("DISCORD_TOKEN").expect("Expected a token in the environment"); // Set gateway intents, which decides what events the bot will be notified about let intents = GatewayIntents::GUILD_MESSAGES | GatewayIntents::DIRECT_MESSAGES | GatewayIntents::MESSAGE_CONTENT; // Create a new instance of the Client, logging in as a bot. let mut client = Client::builder(&token, intents).event_handler(Handler).await.expect("Err creating client"); // Start listening for events by starting a single shard if let Err(why) = client.start().await { println!("Client error: {why:?}"); } } ``` -------------------------------- ### Enable Serenity Features in Cargo.toml Source: https://github.com/serenity-rs/serenity/blob/current/README.md Configure Serenity features by specifying them in your Cargo.toml file. This example shows how to enable specific features like 'pick', 'your', 'feature', 'names', and 'here'. ```toml [dependencies.serenity] default-features = false features = ["pick", "your", "feature", "names", "here"] version = "0.12" ``` -------------------------------- ### Manage Shared State with TypeMap in Serenity Source: https://context7.com/serenity-rs/serenity/llms.txt Use TypeMap to store and access global data across your Serenity bot's handlers and commands. Define a key type implementing TypeMapKey, insert data before starting the client, and retrieve it using `ctx.data.read().await.get::()`. ```rust use std::collections::HashMap; use std::sync::Arc; use serenity::prelude::*; // --- Define keys --- struct HitCounter; impl TypeMapKey for HitCounter { type Value = Arc>>; } // --- Populate before starting --- // Assuming `client` is an instance of serenity::Client // { // let mut data = client.data.write().await; // data.insert::(Arc::new(RwLock::new(HashMap::new()))); // } // --- Read inside any EventHandler or framework command --- async fn message(ctx: &serenity::client::Context, msg: serenity::model::channel::Message) { // Clone the Arc so we don't hold the outer lock. let counter_lock = { let data = ctx.data.read().await; data.get::().expect("HitCounter missing").clone() }; // Write to the inner map. { let mut counter = counter_lock.write().await; *counter.entry(msg.author.name.clone()).or_insert(0) += 1; } let count = counter_lock.read().await; let hits = count.get(&msg.author.name).copied().unwrap_or(0); let _ = msg.reply(&ctx, format!("You have sent {hits} messages!")).await; } ``` -------------------------------- ### Run All Tests with All Features Source: https://github.com/serenity-rs/serenity/blob/current/CONTRIBUTING.md Execute all tests for the project, including all available features. This command is useful for ensuring comprehensive test coverage. ```bash cargo test --features full ``` -------------------------------- ### Configure DATABASE_URL for SQLite Source: https://github.com/serenity-rs/serenity/blob/current/examples/e16_sqlite_database/README.md Set the DATABASE_URL environment variable to specify the SQLite database file. SQLx automatically detects and reads this from a .env file. ```rust DATABASE_URL=sqlite:database.sqlite ``` -------------------------------- ### Format Code with Rustfmt Source: https://github.com/serenity-rs/serenity/blob/current/CONTRIBUTING.md Format all code within the project using the rustfmt tool. This command ensures adherence to the project's code style guidelines. ```bash cargo fmt --all ``` -------------------------------- ### Send Message with Select Menu and Handle Interaction Source: https://context7.com/serenity-rs/serenity/llms.txt Demonstrates sending a message with a select menu and awaiting a single interaction. Includes a timeout and updates the message upon interaction. Requires `serenity::builder`, `serenity::model::prelude::*`, `serenity::prelude::*`, and `std::time::Duration`. ```rust use serenity::builder::{ CreateButton, CreateInteractionResponse, CreateInteractionResponseMessage, CreateMessage, CreateSelectMenu, CreateSelectMenuKind, CreateSelectMenuOption, }; use serenity::model::prelude::*; use serenity::prelude::*; use std::time::Duration; // Inside EventHandler::message: async fn message(&self, ctx: Context, msg: Message) { if msg.content != "vote" { return; } // Send a message with a select menu. let sent = msg .channel_id .send_message(&ctx, CreateMessage::new() .content("Pick your language:") .select_menu( CreateSelectMenu::new("lang_select", CreateSelectMenuKind::String { options: vec![ CreateSelectMenuOption::new("Rust 🦀", "rust"), CreateSelectMenuOption::new("Go 🐹", "go"), CreateSelectMenuOption::new("TypeScript 🟦", "ts"), ], }) .placeholder("Select a language") .custom_id("lang_select"), ), ) .await .unwrap(); // Await one interaction (60-second window). if let Some(interaction) = sent .await_component_interaction(&ctx.shard) .timeout(Duration::from_secs(60)) .await { let chosen = match &interaction.data.kind { ComponentInteractionDataKind::StringSelect { values } => values[0].clone(), _ => "unknown".to_string(), }; // Acknowledge and update the message. interaction .create_response(&ctx, CreateInteractionResponse::UpdateMessage( CreateInteractionResponseMessage::default() .content(format!("You chose **{chosen}**!")) // Follow up with confirm/cancel buttons. .button(CreateButton::new("confirm").label("Confirm ✅")) .button(CreateButton::new("cancel").label("Cancel ❌")), )) .await .unwrap(); } sent.delete(&ctx).await.unwrap(); } ``` -------------------------------- ### Configure a Low-Level HTTP Client in Serenity Source: https://context7.com/serenity-rs/serenity/llms.txt Use `HttpBuilder` to create a standalone `Http` instance for custom configurations like using a specific `reqwest::Client`, a rate-limit proxy, or disabling the built-in rate limiter. This is useful when you need direct REST API access without a full `Client`. ```rust use serenity::http::HttpBuilder; use serenity::model::id::ApplicationId; // Example: disable the local rate limiter and delegate to a proxy. let http = HttpBuilder::new(std::env::var("DISCORD_TOKEN").unwrap()) .application_id(ApplicationId::new(123456789012345678)) .proxy("http://127.0.0.1:3000") .ratelimiter_disabled(true) .build(); // Use the Http instance directly for REST calls without a full Client. let current_user = http.get_current_user().await?; println!("Logged in as {}", current_user.name); let channel_id = serenity::model::id::ChannelId::new(987654321098765432); channel_id.say(&http, "Hello from a standalone HTTP client!").await?; ``` -------------------------------- ### Serenity Project Dependencies Source: https://github.com/serenity-rs/serenity/blob/current/README.md Add these dependencies to your Cargo.toml file to use the Serenity library and Tokio runtime for asynchronous operations. ```toml [dependencies] serenity = "0.12" tokio = { version = "1.21.2", features = ["macros", "rt-multi-thread"] } ``` -------------------------------- ### Register and Handle Slash Commands in Serenity Rust Source: https://context7.com/serenity-rs/serenity/llms.txt This snippet demonstrates registering guild-scoped and global slash commands, and handling incoming interactions. Guild commands propagate instantly, useful for development, while global commands have a longer propagation delay. Ensure your bot has the necessary intents and token configured. ```rust use serenity::async_trait; use serenity::builder::{ CreateCommand, CreateCommandOption, CreateInteractionResponse, CreateInteractionResponseMessage, }; use serenity::model::application::{Command, CommandOptionType, Interaction, ResolvedValue}; use serenity::model::gateway::Ready; use serenity::model::id::GuildId; use serenity::prelude::*; use std::env; struct Handler; #[async_trait] impl EventHandler for Handler { async fn ready(&self, ctx: Context, ready: Ready) { println!("{} connected", ready.user.name); let guild_id = GuildId::new( env::var("GUILD_ID").unwrap().parse::().unwrap(), ); // Register guild-scoped commands (instant propagation, good for dev). guild_id .set_commands(&ctx.http, vec![ CreateCommand::new("ping").description("Replies with Pong!"), CreateCommand::new("greet") .description("Greet a user") .add_option( CreateCommandOption::new(CommandOptionType::User, "user", "Who to greet") .required(true), ), ]) .await .unwrap(); // Register a global command (up to 1h propagation delay). Command::create_global_command( &ctx.http, CreateCommand::new("status").description("Show bot status"), ) .await .unwrap(); } async fn interaction_create(&self, ctx: Context, interaction: Interaction) { let Interaction::Command(cmd) = interaction else { return }; let reply_text = match cmd.data.name.as_str() { "ping" => "Pong!".to_string(), "greet" => { if let Some(opt) = cmd.data.options().first() { if let ResolvedValue::User(user, _) = opt.value { format!("Hello, {}!", user.name) } else { "Could not resolve user.".to_string() } } else { "No user provided.".to_string() } }, _ => "Unknown command.".to_string(), }; let response = CreateInteractionResponse::Message( CreateInteractionResponseMessage::new().content(reply_text), ); if let Err(e) = cmd.create_response(&ctx.http, response).await { eprintln!("Failed to respond: {e}"); } } } #[tokio::main] async fn main() { let token = env::var("DISCORD_TOKEN").unwrap(); let mut client = Client::builder(token, GatewayIntents::empty()) .event_handler(Handler) .await .unwrap(); client.start().await.unwrap(); } ``` -------------------------------- ### CreateEmbed Source: https://context7.com/serenity-rs/serenity/llms.txt Build rich Discord embeds using the `CreateEmbed` fluent builder. This allows for customization of title, description, color, author, footer, images, thumbnails, fields, and timestamps. ```APIDOC ## `CreateEmbed` — Build rich Discord embeds `CreateEmbed` uses a fluent builder to compose the full embed object: title, description, colour, author, footer, image, thumbnail, fields, and timestamp. Embed total character count must stay under 6000. ```rust use serenity::builder::{CreateEmbed, CreateEmbedAuthor, CreateEmbedFooter, CreateMessage}; use serenity::model::id::ChannelId; use serenity::model::Timestamp; let timestamp: Timestamp = "2024-01-15T12:00:00Z".parse().unwrap(); let embed = CreateEmbed::new() .title("Server Status") .url("https://status.example.com") .description("All systems operational.") .colour(0x00_FF_00_u32) // green .author(CreateEmbedAuthor::new("StatusBot").icon_url("https://example.com/bot.png")) .field("Uptime", "99.9%", true) .field("Region", "us-east-1", true) .field("Last Incident", "None in 30 days", false) .thumbnail("https://example.com/thumb.png") .image("https://example.com/graph.png") .footer(CreateEmbedFooter::new("Updated every 5 minutes").icon_url("https://example.com/icon.png")) .timestamp(timestamp); channel_id .send_message(&http, CreateMessage::new().embed(embed)) .await?; ``` ``` -------------------------------- ### Serenity with Specific Features Enabled Source: https://github.com/serenity-rs/serenity/blob/current/README.md This configuration enables all default features except for the 'cache' feature. Ensure 'default-features' is set to false when manually listing features. ```toml [dependencies.serenity] default-features = false features = [ "builder", "chrono", "client", "framework", "gateway", "http", "model", "standard_framework", "utils", "rustls_backend", ] version = "0.12" ``` -------------------------------- ### Opt into specific Serenity features Source: https://context7.com/serenity-rs/serenity/llms.txt Customize your Serenity dependency by disabling default features and explicitly enabling only the features your bot requires. This can help reduce compile times and binary size. ```toml [dependencies.serenity] version = "0.12" default-features = false features = [ "builder", "cache", "client", "gateway", "http", "model", "rustls_backend", ] ``` -------------------------------- ### Build Embeds with CreateEmbed in Rust Source: https://context7.com/serenity-rs/serenity/llms.txt Compose rich Discord embeds using the `CreateEmbed` builder. Supports title, description, color, author, footer, image, thumbnail, fields, and timestamp. The total character count for an embed must not exceed 6000. ```rust use serenity::builder::{CreateEmbed, CreateEmbedAuthor, CreateEmbedFooter, CreateMessage}; use serenity::model::id::ChannelId; use serenity::model::Timestamp; let timestamp: Timestamp = "2024-01-15T12:00:00Z".parse().unwrap(); let embed = CreateEmbed::new() .title("Server Status") .url("https://status.example.com") .description("All systems operational.") .colour(0x00_FF_00_u32) // green .author(CreateEmbedAuthor::new("StatusBot").icon_url("https://example.com/bot.png")) .field("Uptime", "99.9%", true) .field("Region", "us-east-1", true) .field("Last Incident", "None in 30 days", false) .thumbnail("https://example.com/thumb.png") .image("https://example.com/graph.png") .footer(CreateEmbedFooter::new("Updated every 5 minutes").icon_url("https://example.com/icon.png")) .timestamp(timestamp); channel_id .send_message(&http, CreateMessage::new().embed(embed)) .await?; ``` -------------------------------- ### Send Messages with ChannelId in Rust Source: https://context7.com/serenity-rs/serenity/llms.txt Use `ChannelId::say` for plain text messages and `ChannelId::send_message` with `CreateMessage` for richer messages including embeds, files, and components. Requires an `http` client instance. ```rust use serenity::builder::{CreateAttachment, CreateMessage}; use serenity::model::id::ChannelId; // Assume `http` is Arc from ctx.http or a standalone Http instance. // Simplest case: plain text channel_id.say(&http, "Hello, world!").await?; // Rich message: text + TTS + auto-added reactions let msg = channel_id .send_message(&http, CreateMessage::new() .content("Vote below!") .tts(false) .reactions(["👍", "👎"]) ) .await?; println!("Sent message id={}", msg.id); // Message with a file attachment let attachment = CreateAttachment::path("./image.png").await?; channel_id .send_message(&http, CreateMessage::new() .content("Here is the image") .add_file(attachment) ) .await?; ``` -------------------------------- ### EventHandler Trait Source: https://context7.com/serenity-rs/serenity/llms.txt Implement the `EventHandler` trait to react to specific Discord gateway events. You only need to implement the methods for events you care about; unimplemented methods are no-ops. ```APIDOC ## `EventHandler` trait — React to Discord gateway events `EventHandler` is an async trait with one optional method per Discord event. Implement only the methods you care about; every unimplemented method is a no-op by default. The handler receives a `Context` (which carries `ctx.http`, `ctx.cache`, and `ctx.shard`) together with the typed event payload. ```rust use serenity::async_trait; use serenity::model::prelude::*; use serenity::prelude::*; struct Handler; #[async_trait] impl EventHandler for Handler { // Fired once per shard when the READY payload arrives. async fn ready(&self, _ctx: Context, ready: Ready) { println!("Logged in as {} (id={})", ready.user.name, ready.user.id); } // Fired for every new message the bot can see (requires MESSAGE_CONTENT intent for content). async fn message(&self, ctx: Context, msg: Message) { println!("[#{}] {}: {}", msg.channel_id, msg.author.name, msg.content); } // Fired when a guild member joins. async fn guild_member_addition(&self, ctx: Context, new_member: Member) { let channel_id = ChannelId::new(123456789012345678); let _ = channel_id .say(&ctx.http, format!("Welcome, {}!", new_member.user.name)) .await; } // Fired for every slash command / button / select-menu / modal interaction. async fn interaction_create(&self, ctx: Context, interaction: Interaction) { if let Interaction::Command(cmd) = interaction { println!("Slash command: {}", cmd.data.name); } } // Fired when an HTTP rate limit is hit. async fn ratelimit(&self, data: serenity::http::RatelimitInfo) { println!("Rate limited on route {:?} – retry after {:?}", data.route, data.timeout); } } ``` ``` -------------------------------- ### Await Single User Reply Source: https://context7.com/serenity-rs/serenity/llms.txt Waits for a single reply from the original message author with a specified timeout. Requires `serenity::collector::MessageCollector`, `serenity::futures::stream::StreamExt`, and `std::time::Duration`. ```rust use serenity::collector::MessageCollector; use serenity::futures::stream::StreamExt; use std::time::Duration; // Inside a command or event handler that has access to ctx and msg: // 1. Await a single reply from the original message author (10s timeout). let collector = msg.author.await_reply(&ctx.shard).timeout(Duration::from_secs(10)); if let Some(reply) = collector.await { msg.reply(&ctx, format!("You said: {}", reply.content)).await?; } else { msg.reply(&ctx, "Timed out waiting for a reply.").await?; } ``` -------------------------------- ### RawEventHandler Trait Source: https://context7.com/serenity-rs/serenity/llms.txt Implement the `RawEventHandler` trait to receive every gateway event as raw JSON before it is parsed. This is useful for logging, metrics, or forwarding events to external systems. ```APIDOC ## `RawEventHandler` — Receive every gateway event as raw JSON `RawEventHandler` provides a single `raw_event` method that fires for every incoming gateway event before any parsing occurs. Use this for logging, metrics, or forwarding to an external message bus. ```rust use serenity::async_trait; use serenity::model::event::Event; use serenity::prelude::*; use std::env; struct RawHandler; #[async_trait] impl RawEventHandler for RawHandler { async fn raw_event(&self, _ctx: Context, event: Event) { // event is the fully-parsed Event enum; use its Debug impl to log or match on variants. println!("Raw event: {:?}", event); } } #[tokio::main] async fn main() { let token = env::var("DISCORD_TOKEN").unwrap(); let mut client = Client::builder(&token, GatewayIntents::non_privileged()) .raw_event_handler(RawHandler) .await .unwrap(); client.start().await.unwrap(); } ``` ``` -------------------------------- ### ChannelId::send_message / ChannelId::say Source: https://context7.com/serenity-rs/serenity/llms.txt Send messages to a Discord channel. `ChannelId::say` is optimized for plain text, while `ChannelId::send_message` allows for rich content like embeds, files, and components using the `CreateMessage` builder. ```APIDOC ## `ChannelId::send_message` / `ChannelId::say` — Send messages `ChannelId::say` is the fastest path for plain text. `ChannelId::send_message` accepts a `CreateMessage` builder to attach embeds, files, components, reactions, and more. ```rust use serenity::builder::{CreateAttachment, CreateMessage}; use serenity::model::id::ChannelId; // Assume `http` is Arc from ctx.http or a standalone Http instance. // Simplest case: plain text channel_id.say(&http, "Hello, world!").await?; // Rich message: text + TTS + auto-added reactions let msg = channel_id .send_message(&http, CreateMessage::new() .content("Vote below!") .tts(false) .reactions(["👍", "👎"]) ) .await?; println!("Sent message id={}", msg.id); // Message with a file attachment let attachment = CreateAttachment::path("./image.png").await?; channel_id .send_message(&http, CreateMessage::new() .content("Here is the image") .add_file(attachment) ) .await?; ``` ``` -------------------------------- ### Configure Git to Ignore Revisions Source: https://github.com/serenity-rs/serenity/blob/current/CONTRIBUTING.md Configure Git to ignore specific revisions when using `git blame`. This is useful for excluding noisy commits from the blame output. ```bash git config blame.ignoreRevsFile .git-blame-ignore-revs ``` -------------------------------- ### Implement EventHandler Trait in Rust Source: https://context7.com/serenity-rs/serenity/llms.txt Implement the `EventHandler` trait to react to specific Discord events. Only implement methods for events you need; unimplemented methods are no-ops. The handler receives a `Context` and the typed event payload. ```rust use serenity::async_trait; use serenity::model::prelude::*; use serenity::prelude::*; struct Handler; #[async_trait] impl EventHandler for Handler { // Fired once per shard when the READY payload arrives. async fn ready(&self, _ctx: Context, ready: Ready) { println!("Logged in as {} (id={})", ready.user.name, ready.user.id); } // Fired for every new message the bot can see (requires MESSAGE_CONTENT intent for content). async fn message(&self, ctx: Context, msg: Message) { println!("[#{}] {}: {}", msg.channel_id, msg.author.name, msg.content); } // Fired when a guild member joins. async fn guild_member_addition(&self, ctx: Context, new_member: Member) { let channel_id = ChannelId::new(123456789012345678); let _ = channel_id .say(&ctx.http, format!("Welcome, {}!", new_member.user.name)) .await; } // Fired for every slash command / button / select-menu / modal interaction. async fn interaction_create(&self, ctx: Context, interaction: Interaction) { if let Interaction::Command(cmd) = interaction { println!("Slash command: {}", cmd.data.name); } } // Fired when an HTTP rate limit is hit. async fn ratelimit(&self, data: serenity::http::RatelimitInfo) { println!("Rate limited on route {:?} – retry after {:?}", data.route, data.timeout); } } ``` -------------------------------- ### Implement RawEventHandler Trait in Rust Source: https://context7.com/serenity-rs/serenity/llms.txt Use `RawEventHandler` to receive every gateway event as raw JSON before parsing. This is useful for logging, metrics, or forwarding events to an external message bus. The `raw_event` method receives the `Context` and the parsed `Event` enum. ```rust use serenity::async_trait; use serenity::model::event::Event; use serenity::prelude::*; use std::env; struct RawHandler; #[async_trait] impl RawEventHandler for RawHandler { async fn raw_event(&self, _ctx: Context, event: Event) { // event is the fully-parsed Event enum; use its Debug impl to log or match on variants. println!("Raw event: {:?}", event); } } #[tokio::main] async fn main() { let token = env::var("DISCORD_TOKEN").unwrap(); let mut client = Client::builder(&token, GatewayIntents::non_privileged()) .raw_event_handler(RawHandler) .await .unwrap(); client.start().await.unwrap(); } ``` -------------------------------- ### Await Single Reaction on Message Source: https://context7.com/serenity-rs/serenity/llms.txt Waits for a single reaction on a specific message from a particular author within a timeout. Requires `serenity::collector::MessageCollector`, `serenity::futures::stream::StreamExt`, and `std::time::Duration`. ```rust use serenity::collector::MessageCollector; use serenity::futures::stream::StreamExt; use std::time::Duration; // Inside a command or event handler that has access to ctx and msg: // 2. Await a single reaction on a specific message. let react_msg = msg.reply(&ctx, "React with 👍 or 👎").await?; if let Some(reaction) = react_msg .await_reaction(&ctx.shard) .timeout(Duration::from_secs(30)) .author_id(msg.author.id) .await { msg.reply(&ctx, format!("You reacted with {}", reaction.emoji.as_data())).await?; } ``` -------------------------------- ### Collect Stream of Messages Source: https://context7.com/serenity-rs/serenity/llms.txt Collects a stream of up to a specified number of messages from a particular author in a channel within a timeout. Requires `serenity::collector::MessageCollector`, `serenity::futures::stream::StreamExt`, and `std::time::Duration`. ```rust use serenity::collector::MessageCollector; use serenity::futures::stream::StreamExt; use std::time::Duration; // Inside a command or event handler that has access to ctx and msg: // 3. Collect a stream of up to 5 messages from the user in 30 seconds. let stream = MessageCollector::new(&ctx.shard) .author_id(msg.author.id) .channel_id(msg.channel_id) .timeout(Duration::from_secs(30)) .stream() .take(5); let collected: Vec<_> = stream.collect().await; msg.reply(&ctx, format!("Collected {} messages.", collected.len())).await?; ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.