Struct twilight_gateway::Shard

source ·
pub struct Shard { /* private fields */ }
Expand description

Gateway API client responsible for up to 2500 guilds.

Shards are responsible for maintaining the gateway connection by processing events relevant to the operation of shards—such as requests from the gateway to re-connect or invalidate a session—and then to pass them on to the user.

Shards start out disconnected, but will on the first call to next_message try to reconnect to the gateway. next_message must then be repeatedly called in order for the shard to maintain its connection and update its internal state. Note that the next_event method internally calls next_message.

Shards go through an identify queue that ratelimits the amount of concurrent identifies (across all shards) per 5 seconds. Exceeding this limit invalidates the shard’s session and it is therefore very important to reuse the same queue when running multiple shards. Note that shards must be identified before they start receiving dispatch events and are able to send Commands.

Sharding

A shard may not be connected to more than 2500 guilds, so large bots must split themselves across multiple shards. See the Discord Docs/Sharding, ShardId, and stream documentation for more info.

Sending shard commands in different tasks

Because shards should not be used across multiple tasks it’s not always easy to directly send gateway commands over a shard. As a convenience method, Shard::sender can be used to receive an MPSC channel sender which, in addition to being cheaply cloned, also only sends queued up commands when the shard is identified and not ratelimited. Multiple shards’ senders can, for example, be collected into an Arc<Vec<MessageSender>> and be shared across all event handler tasks.

Examples

Create and start a shard and print new and deleted messages:

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

// Use the value of the "DISCORD_TOKEN" environment variable as the bot's
// token. Of course, this value may be passed into the program however is
// preferred.
let token = env::var("DISCORD_TOKEN")?;
let event_types = EventTypeFlags::MESSAGE_CREATE | EventTypeFlags::MESSAGE_DELETE;

let config = Config::builder(token, Intents::GUILD_MESSAGES)
    .event_types(event_types)
    .build();
let mut shard = Shard::with_config(ShardId::ONE, config);

// Create a loop of only new messages and deleted messages.

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

            if source.is_fatal() {
                break;
            }

            continue;
        }
    };

    match event {
        Event::MessageCreate(message) => {
            println!("message received with content: {}", message.content);
        }
        Event::MessageDelete(message) => {
            println!("message with ID {} deleted", message.id);
        }
        _ => {}
    }
}

Implementations§

source§

impl Shard

source

pub fn new(id: ShardId, token: String, intents: Intents) -> Self

Create a new shard with the default configuration.

source

pub fn with_config(shard_id: ShardId, config: Config) -> Self

Create a new shard with the provided configuration.

source

pub const fn config(&self) -> &Config

Immutable reference to the configuration used to instantiate this shard.

source

pub const fn id(&self) -> ShardId

ID of the shard.

source

pub const fn inflater(&self) -> &Inflater

Available on crate features zlib-stock or zlib-simd only.

Zlib decompressor statistics.

Reset when reconnecting to the gateway.

source

pub const fn status(&self) -> &ConnectionStatus

Connection status of the shard.

source

pub const fn latency(&self) -> &Latency

Shard latency statistics, including average latency and recent heartbeat latency times.

Reset when reconnecting to the gateway.

source

pub const fn ratelimiter(&self) -> Option<&CommandRatelimiter>

Statistics about the number of available commands and when the command ratelimiter will refresh.

This won’t be present if ratelimiting was disabled via ConfigBuilder::ratelimit_messages or if the shard is disconnected.

source

pub const fn session(&self) -> Option<&Session>

Immutable reference to the active gateway session.

An active session may not be present if the shard had its session invalidated and has not yet reconnected.

source

pub async fn next_event(&mut self) -> Result<Event, ReceiveMessageError>

Wait for the next Discord event from the gateway.

Errors

Returns a ReceiveMessageErrorType::Compression error type if the message payload failed to decompress.

Returns a ReceiveMessageErrorType::Deserializing error type if the message payload failed to deserialize.

Returns a ReceiveMessageErrorType::FatallyClosed error type if the shard was closed due to a fatal error, such as invalid authorization.

Returns a ReceiveMessageErrorType::Process error type if the shard failed to internally process a received event.

Returns a ReceiveMessageErrorType::Reconnect error type if the shard failed to reconnect to the gateway. This isn’t a fatal error and can be retried.

Returns a ReceiveMessageErrorType::SendingMessage error type if the shard failed to send a message to the gateway, such as a heartbeat.

source

pub async fn next_message(&mut self) -> Result<Message, ReceiveMessageError>

Wait for the next raw message from the websocket connection.

Errors

Returns a ReceiveMessageErrorType::Compression error type if the message payload failed to decompress.

Returns a ReceiveMessageErrorType::FatallyClosed error type if the shard was closed due to a fatal error, such as invalid authorization.

Returns a ReceiveMessageErrorType::Process error type if the shard failed to internally process a received event.

Returns a ReceiveMessageErrorType::Reconnect error type if the shard failed to reconnect to the gateway. This isn’t a fatal error and can be retried.

Returns a ReceiveMessageErrorType::SendingMessage error type if the shard failed to send a message to the gateway, such as a heartbeat.

source

pub async fn command(&mut self, command: &impl Command) -> Result<(), SendError>

Send a command over the gateway.

Serializes the command and then calls send.

Examples

Request members whose names start with “tw” in a guild:

use std::env;
use twilight_gateway::{ConnectionStatus, Intents, Shard, ShardId};
use twilight_model::{gateway::payload::outgoing::RequestGuildMembers, id::Id};

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

let mut shard = Shard::new(ShardId::ONE, token, intents);

// Discord only allows sending the `RequestGuildMembers` command after
// the shard is identified.
while !shard.status().is_identified() {
    // Ignore these messages.
    shard.next_message().await?;
}

// Query members whose names start with "tw" and limit the results to 10
// members.
let request = RequestGuildMembers::builder(Id::new(1)).query("tw", Some(10));

// Send the request over the shard.
shard.command(&request).await?;
Errors

Returns a SendErrorType::Sending error type if the command could not be sent over the websocket. This indicates the shard is either currently restarting or closed and will restart.

Returns a SendErrorType::Serializing error type if the provided command failed to serialize.

source

pub async fn send(&mut self, json: String) -> Result<(), SendError>

Send a JSON encoded gateway event.

A permit from the shard’s ratelimiter is first awaited (if ratelimiting is enabled) before sending the event.

Errors

Returns a SendErrorType::Sending error type if the event could not be sent over the websocket. This indicates the shard is either currently restarting or closed and will restart.

source

pub fn sender(&self) -> MessageSender

Retrieve a channel to send outgoing gateway events over the shard to the gateway.

This is primarily useful for sending to other tasks and threads where the shard won’t be available.

source

pub async fn close(
&mut self,
close_frame: CloseFrame<'static>
) -> Result<Option<Session>, SendError>

Send a Websocket close frame indicating whether to also invalidate the shard’s session.

Returns the shard’s session if the close frame code is not 1000 or 1001, which invalidates the session and shows the application’s bot as offline. Otherwise Discord will not invalidate the shard’s session and will continue to show the application’s bot as online until its presence times out.

Sets status to ConnectionStatus::Disconnected with the close_code from the close_frame.

To read all remaining events, continue calling Shard::next_message until it returns the response close message or a ReceiveMessageErrorType::Io error type.

You do not need to call this method upon receiving a close message, Twilight automatically responds for you.

Example

Close the gateway connection but process already received messages:

use twilight_gateway::{error::ReceiveMessageErrorType, CloseFrame, Message};

shard.close(CloseFrame::NORMAL).await?;

loop {
    match shard.next_message().await {
        Ok(Message::Close(_)) => {
            // We've now received a close message response from the
            // Gateway.
            // Further calls to `next_message` would cause a reconnect.
            break;
        }
        Ok(Message::Text(_)) => unimplemented!("handle message"),
        Err(source) if matches!(source.kind(), ReceiveMessageErrorType::Io) => break,
        Err(source) => tracing::warn!(?source, "error receiving message"),
    }
}
Errors

Returns a SendErrorType::Sending error type if the close frame could not be sent over the websocket. This indicates the shard is either currently restarting or closed and will restart.

Trait Implementations§

source§

impl Debug for Shard

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl !RefUnwindSafe for Shard

§

impl Send for Shard

§

impl Sync for Shard

§

impl Unpin for Shard

§

impl !UnwindSafe for Shard

Blanket Implementations§

source§

impl<T> Any for Twhere
T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere
T: ?Sized,

const: unstable · source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere
T: ?Sized,

const: unstable · source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

const: unstable · source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for Twhere
U: From<T>,

const: unstable · source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T, U> TryFrom<U> for Twhere
U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
const: unstable · source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere
U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
const: unstable · source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for Twhere
V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>where
S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more