twilight-gateway 0.15.0-rc.2

Discord Gateway implementation for the Twilight ecosystem.
Documentation

twilight-gateway

codecov badge discord badge github badge license badge rust badge

twilight-gateway is an implementation of Discord's sharding gateway sessions. This is responsible for receiving stateful events in real-time from Discord and sending some stateful information.

The primary type is the Shard, a stateful interface to maintain a Websocket connection to Discord's gateway. Much of its functionality can be configured, and it's used to receive deserialized gateway event payloads or raw Websocket messages, useful for load balancing and microservices.

Using the stream module, shards can be easily managed in groups.

Features

  • simd-json: use simd-json instead of serde_json for deserializing events
  • TLS (mutually exclusive)
    • native: platform's native TLS implementation via native-tls equivalents
    • rustls-native-roots (default): rustls using native root certificates
    • rustls-webpki-roots: rustls using webpki-roots for root certificates, useful for scratch containers
  • twilight-http (default): enable the stream::create_recommended function
  • Zlib (mutually exclusive)
    • zlib-stock (default): [flate2]'s stock zlib implementation
    • zlib-ng: use zlib-ng for zlib, may have better performance

Examples

Start a shard and loop over guild and voice state events:

use std::env;
use twilight_gateway::{Intents, Shard, ShardId};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Initialize the tracing subscriber.
    tracing_subscriber::fmt::init();

    let token = env::var("DISCORD_TOKEN")?;
    let intents = Intents::GUILDS | Intents::GUILD_VOICE_STATES;

    // Initialize the first and only shard in use by a bot.
    let mut shard = Shard::new(ShardId::ONE, token, intents);

    tracing::info!("started shard");

    loop {
        let event = match shard.next_event().await {
            Ok(event) => event,
            Err(source) => {
                tracing::warn!(?source, "error receiving event");

                // If the error is fatal, as may be the case for invalid
                // authentication or intents, then break out of the loop to
                // avoid constantly attempting to reconnect.
                if source.is_fatal() {
                    break;
                }

                continue;
            },
        };

        tracing::debug!(?event, "received event");
    }

    Ok(())
}

Create the recommended number of shards and stream over their events:

use futures::StreamExt;
use std::{collections::HashMap, env, sync::Arc};
use twilight_gateway::{
    queue::LocalQueue,
    stream::{self, ShardEventStream},
    Config, Intents,
};
use twilight_http::Client;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    tracing_subscriber::fmt::init();

    let token = env::var("DISCORD_TOKEN")?;
    let client = Client::new(token.clone());

    let queue = Arc::new(LocalQueue::new());
    // Callback to create a config for each shard, useful for when not all shards
    // have the same configuration, such as for per-shard presences.
    let config_callback = |_| {
        Config::builder(token.clone(), Intents::GUILDS)
            .queue(queue.clone())
            .build()
    };

    let mut shards = stream::create_recommended(&client, config_callback)
        .await?
        .collect::<Vec<_>>();

    let mut stream = ShardEventStream::new(shards.iter_mut());

    loop {
        let (shard, event) = match stream.next().await {
            Some((shard, Ok(event))) => (shard, event),
            Some((_, Err(source))) => {
                tracing::warn!(?source, "error receiving event");

                if source.is_fatal() {
                    break;
                }

                continue;
            },
            None => break,
        };

        tracing::debug!(?event, shard = ?shard.id(), "received event");
    }

    Ok(())
}

There are a few additional examples located in the repository.