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
Command
s.
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
impl Shard
sourcepub fn new(id: ShardId, token: String, intents: Intents) -> Self
pub fn new(id: ShardId, token: String, intents: Intents) -> Self
Create a new shard with the default configuration.
sourcepub fn with_config(shard_id: ShardId, config: Config) -> Self
pub fn with_config(shard_id: ShardId, config: Config) -> Self
Create a new shard with the provided configuration.
sourcepub const fn config(&self) -> &Config
pub const fn config(&self) -> &Config
Immutable reference to the configuration used to instantiate this shard.
sourcepub const fn inflater(&self) -> &Inflater
Available on crate features zlib-stock
or zlib-simd
only.
pub const fn inflater(&self) -> &Inflater
zlib-stock
or zlib-simd
only.Zlib decompressor statistics.
Reset when reconnecting to the gateway.
sourcepub const fn status(&self) -> &ConnectionStatus
pub const fn status(&self) -> &ConnectionStatus
Connection status of the shard.
sourcepub const fn latency(&self) -> &Latency
pub const fn latency(&self) -> &Latency
Shard latency statistics, including average latency and recent heartbeat latency times.
Reset when reconnecting to the gateway.
sourcepub const fn ratelimiter(&self) -> Option<&CommandRatelimiter>
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.
sourcepub const fn session(&self) -> Option<&Session>
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.
sourcepub async fn next_event(&mut self) -> Result<Event, ReceiveMessageError>
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.
sourcepub async fn next_message(&mut self) -> Result<Message, ReceiveMessageError>
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.
sourcepub async fn command(&mut self, command: &impl Command) -> Result<(), SendError>
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.
sourcepub async fn send(&mut self, json: String) -> Result<(), SendError>
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.
sourcepub fn sender(&self) -> MessageSender
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.
sourcepub async fn close(
&mut self,
close_frame: CloseFrame<'static>
) -> Result<Option<Session>, SendError>
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.