pub struct Client {
pub data: Arc<RwLock<TypeMap>>,
pub shard_manager: Arc<ShardManager>,
pub ws_url: Arc<Mutex<String>>,
pub cache: Arc<Cache>,
pub http: Arc<Http>,
/* private fields */
}
Expand description
A wrapper for HTTP and gateway connections.
The Client is the way to be able to start sending authenticated requests over the REST API, as
well as initializing a WebSocket connection through Shard
s. Refer to the documentation on
using sharding for more information.
§Event Handlers
Event handlers can be configured. For example, the event handler EventHandler::message
will
be dispatched to whenever a Event::MessageCreate
is received over the connection.
Note that you do not need to manually handle events, as they are handled internally and then dispatched to your event handlers.
§Examples
Creating a Client instance and adding a handler on every message receive, acting as a “ping-pong” bot is simple:
use serenity::model::prelude::*;
use serenity::prelude::*;
use serenity::Client;
struct Handler;
#[serenity::async_trait]
impl EventHandler for Handler {
async fn message(&self, context: Context, msg: Message) {
if msg.content == "!ping" {
let _ = msg.channel_id.say(&context, "Pong!");
}
}
}
let mut client =
Client::builder("my token here", GatewayIntents::default()).event_handler(Handler).await?;
client.start().await?;
Fields§
§data: Arc<RwLock<TypeMap>>
A TypeMap which requires types to be Send + Sync. This is a map that can be safely shared across contexts.
The purpose of the data field is to be accessible and persistent across contexts; that is, data can be modified by one context, and will persist through the future and be accessible through other contexts. This is useful for anything that should “live” through the program: counters, database connections, custom user caches, etc.
In the meaning of a context, this data can be accessed through Context::data
.
§Examples
Create a MessageEventCounter
to track the following events:
use std::collections::HashMap;
use std::env;
use serenity::model::prelude::*;
use serenity::prelude::*;
struct MessageEventCounter;
impl TypeMapKey for MessageEventCounter {
type Value = HashMap<String, u64>;
}
async fn reg<S: Into<String>>(ctx: Context, name: S) {
let mut data = ctx.data.write().await;
let counter = data.get_mut::<MessageEventCounter>().unwrap();
let entry = counter.entry(name.into()).or_insert(0);
*entry += 1;
}
struct Handler;
#[serenity::async_trait]
impl EventHandler for Handler {
async fn message(&self, ctx: Context, _: Message) {
reg(ctx, "MessageCreate").await
}
async fn message_delete(&self, ctx: Context, _: ChannelId, _: MessageId) {
reg(ctx, "MessageDelete").await
}
async fn message_delete_bulk(&self, ctx: Context, _: ChannelId, _: Vec<MessageId>) {
reg(ctx, "MessageDeleteBulk").await
}
#[cfg(feature = "cache")]
async fn message_update(
&self,
ctx: Context,
_old: Option<Message>,
_new: Option<Message>,
_: MessageUpdateEvent,
) {
reg(ctx, "MessageUpdate").await
}
#[cfg(not(feature = "cache"))]
async fn message_update(&self, ctx: Context, _new_data: MessageUpdateEvent) {
reg(ctx, "MessageUpdate").await
}
}
let token = std::env::var("DISCORD_TOKEN")?;
let mut client = Client::builder(&token, GatewayIntents::default()).event_handler(Handler).await?;
{
let mut data = client.data.write().await;
data.insert::<MessageEventCounter>(HashMap::default());
}
client.start().await?;
Refer to example 05 for an example on using the Self::data
field.
shard_manager: Arc<ShardManager>
A HashMap of all shards instantiated by the Client.
The key is the shard ID and the value is the shard itself.
§Examples
If you call client.start_shard(3, 5)
, this HashMap will only
ever contain a single key of 3
, as that’s the only Shard the client is responsible for.
If you call client.start_shards(10)
, this HashMap will contain
keys 0 through 9, one for each shard handled by the client.
Printing the number of shards currently instantiated by the client every 5 seconds:
// Create a clone of the `Arc` containing the shard manager.
let shard_manager = client.shard_manager.clone();
tokio::spawn(async move {
loop {
let count = shard_manager.shards_instantiated().await.len();
println!("Shard count instantiated: {}", count);
tokio::time::sleep(Duration::from_millis(5000)).await;
}
});
Shutting down all connections after one minute of operation:
// Create a clone of the `Arc` containing the shard manager.
let shard_manager = client.shard_manager.clone();
// Create a thread which will sleep for 60 seconds and then have the shard manager
// shutdown.
tokio::spawn(async move {
tokio::time::sleep(Duration::from_secs(60)).await;
shard_manager.shutdown_all().await;
println!("Shutdown shard manager!");
});
ws_url: Arc<Mutex<String>>
URL that the client’s shards will use to connect to the gateway.
This is likely not important for production usage and is, at best, used for debugging.
This is wrapped in an Arc<Mutex<T>>
so all shards will have an updated value available.
cache: Arc<Cache>
The cache for the client.
http: Arc<Http>
An HTTP client.
Implementations§
Source§impl Client
impl Client
pub fn builder(token: impl AsRef<str>, intents: GatewayIntents) -> ClientBuilder
Sourcepub async fn start(&mut self) -> Result<()>
pub async fn start(&mut self) -> Result<()>
Establish the connection and start listening for events.
This will start receiving events in a loop and start dispatching the events to your registered handlers.
Note that this should be used only for users and for bots which are in less than 2500 guilds. If you have a reason for sharding and/or are in more than 2500 guilds, use one of these depending on your use case:
Refer to the Gateway documentation for more information on effectively using sharding.
§Examples
Starting a Client with only 1 shard, out of 1 total:
use serenity::Client;
let token = std::env::var("DISCORD_TOKEN")?;
let mut client = Client::builder(&token, GatewayIntents::default()).await?;
if let Err(why) = client.start().await {
println!("Err with client: {:?}", why);
}
Sourcepub async fn start_autosharded(&mut self) -> Result<()>
pub async fn start_autosharded(&mut self) -> Result<()>
Establish the connection(s) and start listening for events.
This will start receiving events in a loop and start dispatching the events to your registered handlers.
This will retrieve an automatically determined number of shards to use from the API - determined by Discord - and then open a number of shards equivalent to that amount.
Refer to the Gateway documentation for more information on effectively using sharding.
§Examples
Start as many shards as needed using autosharding:
use serenity::Client;
let token = std::env::var("DISCORD_TOKEN")?;
let mut client = Client::builder(&token, GatewayIntents::default()).await?;
if let Err(why) = client.start_autosharded().await {
println!("Err with client: {:?}", why);
}
§Errors
Returns a ClientError::Shutdown
when all shards have shutdown due to an error.
Sourcepub async fn start_shard(&mut self, shard: u32, shards: u32) -> Result<()>
pub async fn start_shard(&mut self, shard: u32, shards: u32) -> Result<()>
Establish a sharded connection and start listening for events.
This will start receiving events and dispatch them to your registered handlers.
This will create a single shard by ID. If using one shard per process, you will need to start other processes with the other shard IDs in some way.
Refer to the Gateway documentation for more information on effectively using sharding.
§Examples
Start shard 3 of 5:
use serenity::Client;
let token = std::env::var("DISCORD_TOKEN")?;
let mut client = Client::builder(&token, GatewayIntents::default()).await?;
if let Err(why) = client.start_shard(3, 5).await {
println!("Err with client: {:?}", why);
}
Start shard 0 of 1 (you may also be interested in Self::start
or
Self::start_autosharded
):
use serenity::Client;
let token = std::env::var("DISCORD_TOKEN")?;
let mut client = Client::builder(&token, GatewayIntents::default()).await?;
if let Err(why) = client.start_shard(0, 1).await {
println!("Err with client: {:?}", why);
}
§Errors
Returns a ClientError::Shutdown
when all shards have shutdown due to an error.
Sourcepub async fn start_shards(&mut self, total_shards: u32) -> Result<()>
pub async fn start_shards(&mut self, total_shards: u32) -> Result<()>
Establish sharded connections and start listening for events.
This will start receiving events and dispatch them to your registered handlers.
This will create and handle all shards within this single process. If you only need to
start a single shard within the process, or a range of shards, use Self::start_shard
or
Self::start_shard_range
, respectively.
Refer to the Gateway documentation for more information on effectively using sharding.
§Examples
Start all of 8 shards:
use serenity::Client;
let token = std::env::var("DISCORD_TOKEN")?;
let mut client = Client::builder(&token, GatewayIntents::default()).await?;
if let Err(why) = client.start_shards(8).await {
println!("Err with client: {:?}", why);
}
§Errors
Returns a ClientError::Shutdown
when all shards have shutdown due to an error.
Sourcepub async fn start_shard_range(
&mut self,
range: Range<u32>,
total_shards: u32,
) -> Result<()>
pub async fn start_shard_range( &mut self, range: Range<u32>, total_shards: u32, ) -> Result<()>
Establish a range of sharded connections and start listening for events.
This will start receiving events and dispatch them to your registered handlers.
This will create and handle all shards within a given range within this single process. If
you only need to start a single shard within the process, or all shards within the process,
use Self::start_shard
or Self::start_shards
, respectively.
Refer to the Gateway documentation for more information on effectively using sharding.
§Examples
For a bot using a total of 10 shards, initialize shards 4 through 7:
use serenity::Client;
let token = std::env::var("DISCORD_TOKEN")?;
let mut client = Client::builder(&token, GatewayIntents::default()).await?;
if let Err(why) = client.start_shard_range(4..7, 10).await {
println!("Err with client: {:?}", why);
}
§Errors
Returns a ClientError::Shutdown
when all shards have shutdown due to an error.