serenity

repository·current·Indexed 26 days ago

https://github.com/serenity-rs/serenity

A high-level Rust library for interacting with the Discord API, providing abstractions for shards, caching, and event handling. Version 0.12.5 requires Rust 1.74 and an async runtime like tokio. It includes a framework for defining commands and groups using attribute macros such as #[command], #[group], and #[help].

Tokens
17.3K
Snippets
21
Records
101
Agent score
90%

What's inside serenity

  1. Install Serenity

    current

    Add serenity and tokio to your Cargo.toml to get started. Serenity requires an async runtime like tokio with macros and rt-multi-thread features enabled.

    [dependencies]
    serenity = "0.12"
    tokio = { version = "1.21.2", features = ["macros", "rt-multi-thread"] }
  2. Overview of Serenity core concepts

    current

    Serenity is a Rust library for interacting with the Discord API. Key concepts include:

    • Client: Use Client::builder to authenticate your bot user.
    • EventHandler: Implement EventHandler to react to Discord events (e.g., EventHandler::message for Event::MessageCreate).
    • Context: Provided to handlers, containing information about the current event and access to the API.
    • Shard: The library handles sharding transparently, managing connections automatically.
    • Cache: An automatically updated cache that reduces unnecessary HTTP requests by searching for local data before querying the Discord API.
  3. Configure Serenity features

    current

    Serenity uses Cargo features to manage dependencies and functionality. You can disable default features to reduce binary size or RAM usage (e.g., disabling cache).

    Default features include:

    • builder, cache, chrono, client, framework, gateway, http, model, standard_framework, utils, rustls_backend.

    Commonly used features:

    • cache: Stores guilds, channels, and users to avoid REST requests. Disable if RAM is limited.
    • collector: Allows awaiting specific events (messages, reactions) with configurable criteria.
    • voice: Enables voice plugin registration. Use Songbird for actual voice connections.
    • simd_json: Enables SIMD accelerated JSON parsing.
    • unstable_discord_api: Enables features of the Discord API that do not have a stable interface.
    • full: Enables all parts of the codebase.
    [dependencies.serenity]
    default-features = false
    features = ["builder", "chrono", "client", "gateway", "http", "model", "utils", "rustls_backend"]
    version = "0.12"
  4. Configure rate limit buckets with BucketBuilder

    current

    Use BucketBuilder to define how commands are rate limited within the StandardFramework. You can specify the scope of the limit (Global, User, Guild, Channel, or Category), the delay between invocations, the number of allowed invocations within a specific time span, and custom actions when a limit is exceeded.

    Key Configuration Methods:

    • new_global(), new_user(), new_guild(), new_channel(), new_category(): Sets the scope of the rate limit.
    • delay(secs: u64): Sets the minimum duration between command invocations.
    • time_span(secs: u64): Sets the window of time for the limit to apply.
    • limit(n: u32): Sets the maximum number of allowed invocations within the time_span.
    • await_ratelimits(amount: u32): If greater than 0, the command invocation will be delayed amount times instead of being cancelled. This is required to trigger delay_action.
    • delay_action(action: DelayHook): Provides a callback function to execute when a user's command is delayed (e.g., sending a custom warning message). This automatically sets await_ratelimits to at least 1.
    • check(check: Check): Adds a middleware function to verify if the command invocation is eligible for the bucket.
    let framework = StandardFramework::new()
        .bucket("example_bucket", BucketBuilder::default()
            .delay_action(|ctx, msg| {
                Box::pin(example_overuse_response(ctx, msg))
            })
            .delay(10) // 10 second delay
            .await_ratelimits(1) // Allow 1 delay action to trigger
        )
        .await
        .group(&GENERAL_GROUP);
  5. Configure the Http client with HttpBuilder

    current

    Use HttpBuilder to customize the underlying HTTP client. This is useful if you need to use a proxy or disable the internal rate limiter (e.g., when delegating rate limiting to a proxy like twilight-http-proxy).

    Key configuration methods:

    • new(token): Creates a new builder. The token is automatically prefixed with "Bot " if not already present.
    • proxy(proxy_url): Sets a proxy URL (e.g., http://127.0.0.1:3000).
    • ratelimiter_disabled(bool): Disables the internal rate limiter. Use this with proxy to delegate rate limiting to an external service.
    • application_id(id): Sets the application ID for interaction-related requests.
    • client(reqwest_client): Provides a custom reqwest::Client.
    • build(): Finalizes the configuration and returns an Http instance.
    # use serenity::http::HttpBuilder;
    # fn run() {
    let http =
        HttpBuilder::new("token").proxy("http://127.0.0.1:3000").ratelimiter_disabled(true).build();
    # }
  6. Create a basic ping-pong bot

    current

    To create a basic bot, implement the EventHandler trait to respond to events (like message) and use Client::builder to initialize the client with your bot token and required GatewayIntents. Use client.start() to begin listening for events.

    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:?}");
        }
    }
  7. Customize HelpOptions for the help command

    current

    The HelpOptions struct allows for deep customization of the help command's output text and behavior. Key fields include:

    • suggestion_text: Text used when suggesting a command (e.g., "Did you mean {}?").
    • no_help_available_text: Text shown when no help is available.
    • usage_label: Label for the usage section.
    • guild_only_text: Label for commands restricted to guilds.
    • dm_only_text: Label for commands restricted to DMs.
    • embed_error_colour: Colour used for error embeds.
    • embed_success_colour: Colour used for success embeds.
    • lacking_role, lacking_permissions, lacking_ownership, lacking_conditions, wrong_channel: HelpBehaviour settings for different restriction types.
  8. Configure environment variables for Serenity bots

    current

    Serenity applications often use a .env file to manage sensitive credentials and configuration via the dotenv crate.

    Key requirements:

    • Environment variables must be separated by newlines.
    • Do not include spaces around the equals sign (=).
    • Use DISCORD_TOKEN to store your bot's Discord token.
    • Use RUST_LOG to control the level of logging (e.g., debug, info, warn, error).
    DISCORD_TOKEN=put your token here
    RUST_LOG=debug
  9. Choose a TLS backend

    current

    Serenity supports two TLS backends. If you disable default features, you must pick one:

    1. rustls_backend (Default): A pure Rust TLS implementation. Works on all platforms.
    2. native_tls_backend: Uses SChannel (Windows), Secure Transport (macOS), or OpenSSL (other platforms).

    Note: If using native_tls_backend on Linux/other non-Apple/Windows platforms, you must have openssl installed on your system.

  10. Handle Discord Voice Gateway Websocket close codes

    current

    When handling voice connection closures, you can use the CloseCode enum to identify why the Discord Voice Gateway Websocket disconnected.

    To determine if your bot should attempt to reconnect or resume the session, use the should_resume() method. This method returns true for CloseCode::VoiceServerCrash and CloseCode::SessionTimeout, and false for other codes (such as CloseCode::Disconnected, which indicates the channel was closed or the user was kicked and should not be reconnected).

  11. Edit voice state in a stage channel

    current

    Modify a user's voice state in a stage channel. The map should contain channel_id (the channel the user is in) and suppress (a boolean to toggle suppression).

    use serenity::http::Http;
    use serenity::json::json;
    use serenity::model::prelude::*;
    
    # async fn run() -> Result<(), Box<dyn std::error::Error>> {
    # let http: Http = unimplemented!();
    let guild_id = GuildId::new(187450744427773963);
    let user_id = UserId::new(150443906511667200);
    let map = json!({
        "channel_id": "826929611849334784",
        "suppress": true,
    });
    
    // Edit state for another user
    http.edit_voice_state(guild_id, user_id, &map).await?;
    # Ok(())
    # }