Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 18 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,37 +43,45 @@ docs.
A basic ping-pong bot looks like:

```rust
use std::env;
use std::sync::Arc;

use serenity::async_trait;
use serenity::model::channel::Message;
use serenity::gateway::client::FullEvent;
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:?}");
}
async fn dispatch(&self, ctx: &Context, event: &FullEvent) {
match event {
FullEvent::Message {
new_message, ..
} => {
if new_message.content == "!ping" {
if let Err(why) = new_message.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");
let token =
Token::from_env("DISCORD_TOKEN").expect("Expected a valid 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)
let mut client = Client::builder(token, intents)
.event_handler(Arc::new(Handler))
.await
.expect("Error creating client");

Expand Down
8 changes: 6 additions & 2 deletions examples/e01_basic_ping_bot/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::sync::Arc;

use serenity::async_trait;
use serenity::gateway::client::FullEvent;
use serenity::prelude::*;
Expand Down Expand Up @@ -54,8 +56,10 @@ async fn main() {

// Create a new instance of the Client, logging in as a bot. This will automatically prepend
// your bot token with "Bot ", which is a requirement by Discord for bot users.
let mut client =
Client::builder(token, intents).event_handler(Handler).await.expect("Err creating client");
let mut client = Client::builder(token, intents)
.event_handler(Arc::new(Handler))
.await
.expect("Err creating client");

// Finally, start a single shard, and start listening to events.
//
Expand Down
8 changes: 6 additions & 2 deletions examples/e02_transparent_guild_sharding/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#![expect(clippy::collapsible_if)]
use std::sync::Arc;

use serenity::async_trait;
use serenity::gateway::client::FullEvent;
use serenity::prelude::*;
Expand Down Expand Up @@ -51,8 +53,10 @@ async fn main() {
let intents = GatewayIntents::GUILD_MESSAGES
| GatewayIntents::DIRECT_MESSAGES
| GatewayIntents::MESSAGE_CONTENT;
let mut client =
Client::builder(token, intents).event_handler(Handler).await.expect("Err creating client");
let mut client = Client::builder(token, intents)
.event_handler(Arc::new(Handler))
.await
.expect("Err creating client");

// The total number of shards to use. The "current shard number" of a shard - that is, the
// shard it is assigned to - is indexed at 0, while the total shard count is indexed at 1.
Expand Down
8 changes: 6 additions & 2 deletions examples/e03_struct_utilities/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::sync::Arc;

use serenity::async_trait;
use serenity::builder::CreateMessage;
use serenity::gateway::client::FullEvent;
Expand Down Expand Up @@ -47,8 +49,10 @@ async fn main() {
let intents = GatewayIntents::GUILD_MESSAGES
| GatewayIntents::DIRECT_MESSAGES
| GatewayIntents::MESSAGE_CONTENT;
let mut client =
Client::builder(token, intents).event_handler(Handler).await.expect("Err creating client");
let mut client = Client::builder(token, intents)
.event_handler(Arc::new(Handler))
.await
.expect("Err creating client");

if let Err(why) = client.start().await {
println!("Client error: {why:?}");
Expand Down
8 changes: 6 additions & 2 deletions examples/e04_message_builder/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::sync::Arc;

use serenity::async_trait;
use serenity::gateway::client::FullEvent;
use serenity::prelude::*;
Expand Down Expand Up @@ -56,8 +58,10 @@ async fn main() {
let intents = GatewayIntents::GUILD_MESSAGES
| GatewayIntents::DIRECT_MESSAGES
| GatewayIntents::MESSAGE_CONTENT;
let mut client =
Client::builder(token, intents).event_handler(Handler).await.expect("Err creating client");
let mut client = Client::builder(token, intents)
.event_handler(Arc::new(Handler))
.await
.expect("Err creating client");

if let Err(why) = client.start().await {
println!("Client error: {why:?}");
Expand Down
3 changes: 2 additions & 1 deletion examples/e05_sample_bot_structure/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod commands;

use std::env;
use std::sync::Arc;

use serenity::async_trait;
use serenity::builder::{CreateInteractionResponse, CreateInteractionResponseMessage};
Expand Down Expand Up @@ -94,7 +95,7 @@ async fn main() {

// Build our client.
let mut client = Client::builder(token, GatewayIntents::empty())
.event_handler(Handler)
.event_handler(Arc::new(Handler))
.await
.expect("Error creating client");

Expand Down
8 changes: 6 additions & 2 deletions examples/e06_env_logging/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::sync::Arc;

use serenity::async_trait;
use serenity::prelude::*;
use tracing::{debug, error, info, instrument};
Expand Down Expand Up @@ -50,8 +52,10 @@ async fn main() {
| GatewayIntents::DIRECT_MESSAGES
| GatewayIntents::MESSAGE_CONTENT;

let mut client =
Client::builder(token, intents).event_handler(Handler).await.expect("Err creating client");
let mut client = Client::builder(token, intents)
.event_handler(Arc::new(Handler))
.await
.expect("Err creating client");

if let Err(why) = client.start().await {
error!("Client error: {:?}", why);
Expand Down
7 changes: 5 additions & 2 deletions examples/e07_shard_manager/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
//! Note that it may take a minute or more for a latency to be recorded or to update, depending on
//! how often Discord tells the client to send a heartbeat.
#![expect(clippy::collapsible_if)]
use std::sync::Arc;
use std::time::Duration;

use serenity::async_trait;
Expand Down Expand Up @@ -54,8 +55,10 @@ async fn main() {
let intents = GatewayIntents::GUILD_MESSAGES
| GatewayIntents::DIRECT_MESSAGES
| GatewayIntents::MESSAGE_CONTENT;
let mut client =
Client::builder(token, intents).event_handler(Handler).await.expect("Err creating client");
let mut client = Client::builder(token, intents)
.event_handler(Arc::new(Handler))
.await
.expect("Err creating client");

// Here we get a DashMap of of the shards' status that we move into a new thread.
let runners = client.shard_manager.runners.clone();
Expand Down
8 changes: 6 additions & 2 deletions examples/e08_create_message_builder/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::sync::Arc;

use serenity::async_trait;
use serenity::builder::{CreateAttachment, CreateEmbed, CreateEmbedFooter, CreateMessage};
use serenity::gateway::client::FullEvent;
Expand Down Expand Up @@ -62,8 +64,10 @@ async fn main() {
let intents = GatewayIntents::GUILD_MESSAGES
| GatewayIntents::DIRECT_MESSAGES
| GatewayIntents::MESSAGE_CONTENT;
let mut client =
Client::builder(token, intents).event_handler(Handler).await.expect("Err creating client");
let mut client = Client::builder(token, intents)
.event_handler(Arc::new(Handler))
.await
.expect("Err creating client");

if let Err(why) = client.start().await {
println!("Client error: {why:?}");
Expand Down
7 changes: 5 additions & 2 deletions examples/e09_collectors/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! This example will showcase the beauty of collectors. They allow to await messages or reactions
//! from a user in the middle of a control flow, one being a command.
use std::collections::HashSet;
use std::sync::Arc;
use std::time::Duration;

use serenity::async_trait;
Expand Down Expand Up @@ -163,8 +164,10 @@ async fn main() {
| GatewayIntents::MESSAGE_CONTENT
| GatewayIntents::GUILD_MESSAGE_REACTIONS;

let mut client =
Client::builder(token, intents).event_handler(Handler).await.expect("Err creating client");
let mut client = Client::builder(token, intents)
.event_handler(Arc::new(Handler))
.await
.expect("Err creating client");

if let Err(why) = client.start().await {
println!("Client error: {why:?}");
Expand Down
4 changes: 3 additions & 1 deletion examples/e10_gateway_intents/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::sync::Arc;

use serenity::async_trait;
use serenity::prelude::*;

Expand Down Expand Up @@ -41,7 +43,7 @@ async fn main() {
GatewayIntents::GUILDS | GatewayIntents::GUILD_MESSAGES | GatewayIntents::MESSAGE_CONTENT;
// Build our client.
let mut client = Client::builder(token, intents)
.event_handler(Handler)
.event_handler(Arc::new(Handler))
.await
.expect("Error creating client");

Expand Down
2 changes: 1 addition & 1 deletion examples/e11_global_data/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ async fn main() {
// guarantee that Context::data will not panic if the same type is given, as providing the
// incorrect type will lead to a compiler error, rather than a runtime panic.
.data::<UserData>(Arc::new(data))
.event_handler(Handler)
.event_handler(Arc::new( Handler))
.await
.expect("Err creating client");

Expand Down
5 changes: 3 additions & 2 deletions examples/e12_parallel_loops/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![expect(clippy::collapsible_if)]
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;

Expand Down Expand Up @@ -117,9 +118,9 @@ async fn main() {
| GatewayIntents::GUILDS
| GatewayIntents::MESSAGE_CONTENT;
let mut client = Client::builder(token, intents)
.event_handler(Handler {
.event_handler(Arc::new(Handler {
is_loop_running: AtomicBool::new(false),
})
}))
.await
.expect("Error creating client");

Expand Down
5 changes: 3 additions & 2 deletions examples/e13_sqlite_database/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// It is recommended that you read the README file, it is very important to this example.
// This example will help us to use a sqlite database with our bot.
use std::fmt::Write as _;
use std::sync::Arc;

use serenity::async_trait;
use serenity::model::prelude::*;
Expand Down Expand Up @@ -106,9 +107,9 @@ async fn main() {
// Run migrations, which updates the database's schema to the latest version.
sqlx::migrate!("./migrations").run(&database).await.expect("Couldn't run database migrations");

let bot = Bot {
let bot = Arc::new(Bot {
database,
};
});

let intents = GatewayIntents::GUILD_MESSAGES
| GatewayIntents::DIRECT_MESSAGES
Expand Down
3 changes: 2 additions & 1 deletion examples/e14_message_components/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::borrow::Cow;
use std::sync::Arc;
use std::time::Duration;

use dotenv::dotenv;
Expand Down Expand Up @@ -170,7 +171,7 @@ async fn main() {
| GatewayIntents::DIRECT_MESSAGES
| GatewayIntents::MESSAGE_CONTENT;
let mut client = Client::builder(token, intents)
.event_handler(Handler)
.event_handler(Arc::new(Handler))
.await
.expect("Error creating client");

Expand Down
4 changes: 3 additions & 1 deletion examples/testing/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::borrow::Cow;
use std::sync::Arc;

use serenity::async_trait;
use serenity::builder::*;
Expand Down Expand Up @@ -430,6 +431,7 @@ async fn main() {
Token::from_env("DISCORD_TOKEN").expect("Expected a valid token in the environment");
let intents = GatewayIntents::non_privileged() | GatewayIntents::MESSAGE_CONTENT;

let mut client = Client::builder(token, intents).event_handler(Handler).await.unwrap();
let mut client =
Client::builder(token, intents).event_handler(Arc::new(Handler)).await.unwrap();
client.start().await.unwrap();
}
47 changes: 18 additions & 29 deletions src/gateway/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,10 @@ impl ClientBuilder {
/// *Info*: If a reference to the framework is required for manual dispatch, you can implement
/// [`Framework`] on [`Arc<YourFrameworkType>`] instead of `YourFrameworkType`.
#[cfg(feature = "framework")]
pub fn framework<F>(mut self, framework: F) -> Self
where
F: Framework + 'static,
{
self.framework = Some(Box::new(framework));
pub fn framework(mut self, framework: Box<dyn Framework>) -> Self {
// This `Box` is converted to an `Arc` after `init` is called. The init step requires a
// mutable reference, and therefore accepting an `Arc` here would be misleading at best.
self.framework = Some(framework);

self
}
Expand Down Expand Up @@ -188,11 +187,8 @@ impl ClientBuilder {
/// Sets the voice gateway handler to be used. It will receive voice events sent over the
/// gateway and then consider - based on its settings - whether to dispatch a command.
#[cfg(feature = "voice")]
pub fn voice_manager<V>(mut self, voice_manager: impl Into<Arc<V>>) -> Self
where
V: VoiceGatewayManager + 'static,
{
self.voice_manager = Some(voice_manager.into());
pub fn voice_manager(mut self, voice_manager: Arc<dyn VoiceGatewayManager>) -> Self {
self.voice_manager = Some(voice_manager);
self
}

Expand Down Expand Up @@ -235,35 +231,28 @@ impl ClientBuilder {
self.intents
}

/// Adds an event handler with multiple methods for each possible event.
pub fn event_handler<H>(mut self, event_handler: impl Into<Arc<H>>) -> Self
where
H: EventHandler + 'static,
{
self.event_handler = Some(event_handler.into());
/// Sets the event handler where all received gateway events will be dispatched.
pub fn event_handler(mut self, event_handler: Arc<dyn EventHandler>) -> Self {
self.event_handler = Some(event_handler);
self
}

/// Gets the added event handlers. See [`Self::event_handler`] for more info.
/// Gets the added event handler. See [`Self::event_handler`] for more info.
#[must_use]
pub fn get_event_handler(&self) -> Option<&Arc<dyn EventHandler>> {
self.event_handler.as_ref()
pub fn get_event_handler(&self) -> Option<Arc<dyn EventHandler>> {
self.event_handler.clone()
}

/// Adds an event handler with a single method where all received gateway events will be
/// dispatched.
pub fn raw_event_handler<H>(mut self, raw_event_handler: impl Into<Arc<H>>) -> Self
where
H: RawEventHandler + 'static,
{
self.raw_event_handler = Some(raw_event_handler.into());
/// Sets the raw event handler where all received gateway events will be dispatched.
pub fn raw_event_handler(mut self, raw_event_handler: Arc<dyn RawEventHandler>) -> Self {
self.raw_event_handler = Some(raw_event_handler);
self
}

/// Gets the added raw event handlers. See [`Self::raw_event_handler`] for more info.
/// Gets the added raw event handler. See [`Self::raw_event_handler`] for more info.
#[must_use]
pub fn get_raw_event_handler(&self) -> Option<&Arc<dyn RawEventHandler>> {
self.raw_event_handler.as_ref()
pub fn get_raw_event_handler(&self) -> Option<Arc<dyn RawEventHandler>> {
self.raw_event_handler.clone()
}

/// Sets the initial activity.
Expand Down