From 8a569e0f4568dbf9fdc9b4abbfbafa72c46edaee Mon Sep 17 00:00:00 2001 From: Michael Krasnitski Date: Fri, 16 Aug 2024 17:25:01 -0400 Subject: [PATCH 1/3] Merge `client` feature/module into `gateway` --- .github/workflows/ci.yml | 6 ++-- Cargo.toml | 17 +++------ build.rs | 9 ++--- examples/e01_basic_ping_bot/Cargo.toml | 2 +- .../e02_transparent_guild_sharding/Cargo.toml | 2 +- examples/e03_struct_utilities/Cargo.toml | 2 +- examples/e04_message_builder/Cargo.toml | 2 +- examples/e05_sample_bot_structure/Cargo.toml | 2 +- examples/e06_env_logging/Cargo.toml | 2 +- examples/e07_shard_manager/Cargo.toml | 2 +- .../e08_create_message_builder/Cargo.toml | 2 +- examples/e09_collectors/Cargo.toml | 2 +- examples/e10_gateway_intents/Cargo.toml | 2 +- examples/e12_parallel_loops/Cargo.toml | 2 +- examples/e13_sqlite_database/Cargo.toml | 2 +- examples/e14_message_components/Cargo.toml | 2 +- examples/e15_webhook/Cargo.toml | 2 +- examples/testing/Cargo.toml | 2 +- src/cache/mod.rs | 5 ++- src/client/error.rs | 25 ------------- src/error.rs | 14 -------- src/framework/mod.rs | 6 ++-- src/gateway/bridge/shard_manager.rs | 12 ++++--- src/gateway/bridge/shard_queuer.rs | 13 ++++--- src/gateway/bridge/shard_runner.rs | 12 +++++-- src/{ => gateway}/client/context.rs | 25 +------------ src/{ => gateway}/client/dispatch.rs | 2 +- src/{ => gateway}/client/event_handler.rs | 8 ++--- src/{ => gateway}/client/mod.rs | 36 ++++--------------- src/gateway/mod.rs | 2 ++ src/gateway/ws.rs | 35 ++++-------------- src/http/client.rs | 4 +-- src/http/mod.rs | 6 ++-- src/lib.rs | 15 +++----- src/model/application/command.rs | 2 +- src/model/application/command_interaction.rs | 2 +- .../application/component_interaction.rs | 2 +- src/model/channel/attachment.rs | 2 +- src/model/error.rs | 2 +- src/model/event.rs | 30 ++++++++-------- src/model/guild/mod.rs | 2 +- src/model/guild/partial_guild.rs | 2 +- src/model/user.rs | 4 +-- src/prelude.rs | 6 +--- src/utils/argument_convert/message.rs | 4 +-- src/utils/content_safe.rs | 4 +-- src/utils/mod.rs | 4 +-- src/utils/quick_modal.rs | 2 +- 48 files changed, 118 insertions(+), 232 deletions(-) delete mode 100644 src/client/error.rs rename src/{ => gateway}/client/context.rs (94%) rename src/{ => gateway}/client/dispatch.rs (99%) rename src/{ => gateway}/client/event_handler.rs (99%) rename src/{ => gateway}/client/mod.rs (95%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5bfc75bb629..1ad5feb3254 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,9 +37,9 @@ jobs: - name: no default features features: " " - name: no cache - features: builder client framework gateway model http utils rustls_backend + features: framework rustls_backend - name: no gateway - features: model http rustls_backend + features: model rustls_backend - name: chrono features: chrono - name: unstable API + typesize @@ -204,7 +204,7 @@ jobs: - name: Build docs run: | - cargo doc --no-deps --features collector,voice,unstable + cargo doc --no-deps --features full,unstable env: RUSTDOCFLAGS: -D rustdoc::broken_intra_doc_links diff --git a/Cargo.toml b/Cargo.toml index 1ea2782ecc9..0b843a40f24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,15 +68,9 @@ default_native_tls = ["default_no_backend", "native_tls_backend"] # Serenity requires a backend, this picks all default features without a backend. default_no_backend = [ - "builder", "cache", "chrono", - "client", "framework", - "gateway", - "model", - "http", - "utils", ] # Enables builder structs to configure Discord HTTP requests. Without this feature, you have to @@ -87,14 +81,11 @@ builder = ["tokio/fs"] cache = ["fxhash", "dashmap"] # Enables collectors, a utility feature that lets you await interaction events in code with # zero setup, without needing to setup an InteractionCreate event listener. -collector = ["gateway", "model"] -# Wraps the gateway and http functionality into a single interface -# TODO: should this require "gateway"? -client = ["http"] +collector = ["gateway"] # Enables the Framework trait which is an abstraction for old-style text commands. -framework = ["client", "model", "utils"] +framework = ["gateway"] # Enables gateway support, which allows bots to listen for Discord events. -gateway = ["flate2"] +gateway = ["model", "flate2"] # Enables HTTP, which enables bots to execute actions on Discord. http = ["dashmap", "mime_guess", "percent-encoding"] # Enables wrapper methods around HTTP requests on model types. @@ -108,7 +99,7 @@ voice_model = ["serenity-voice-model"] unstable = [] # Enables some utility functions that can be useful for bot creators. utils = [] -voice = ["client", "model"] +voice = ["gateway"] # Enables unstable tokio features to give explicit names to internally spawned tokio tasks tokio_task_builder = ["tokio/tracing"] interactions_endpoint = ["ed25519-dalek"] diff --git a/build.rs b/build.rs index 725dd621ce6..0b97e08c250 100644 --- a/build.rs +++ b/build.rs @@ -1,10 +1,7 @@ -#[cfg(all( - any(feature = "http", feature = "gateway"), - not(any(feature = "rustls_backend", feature = "native_tls_backend")) -))] +#[cfg(all(feature = "http", not(any(feature = "rustls_backend", feature = "native_tls_backend"))))] compile_error!( - "You have the `http` or `gateway` feature enabled, either the `rustls_backend` or \ - `native_tls_backend` feature must be selected to let Serenity use `http` or `gateway`.\n\ + "You have the `http` feature enabled; either the `rustls_backend` or `native_tls_backend` \ + feature must be enabled to let Serenity make requests over the network.\n\ - `rustls_backend` uses Rustls, a pure Rust TLS-implemenation.\n\ - `native_tls_backend` uses SChannel on Windows, Secure Transport on macOS, and OpenSSL on \ other platforms.\n\ diff --git a/examples/e01_basic_ping_bot/Cargo.toml b/examples/e01_basic_ping_bot/Cargo.toml index 7f9cb61751b..211146c8ae6 100644 --- a/examples/e01_basic_ping_bot/Cargo.toml +++ b/examples/e01_basic_ping_bot/Cargo.toml @@ -5,5 +5,5 @@ authors = ["my name "] edition = "2018" [dependencies] -serenity = { path = "../../", default-features = false, features = ["client", "gateway", "rustls_backend", "model"] } +serenity = { path = "../../", default-features = false, features = ["gateway", "model", "rustls_backend"] } tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } diff --git a/examples/e02_transparent_guild_sharding/Cargo.toml b/examples/e02_transparent_guild_sharding/Cargo.toml index d1fab7917da..eec0c2aff9d 100644 --- a/examples/e02_transparent_guild_sharding/Cargo.toml +++ b/examples/e02_transparent_guild_sharding/Cargo.toml @@ -5,5 +5,5 @@ authors = ["my name "] edition = "2018" [dependencies] -serenity = { path = "../../", default-features = false, features = ["client", "gateway", "rustls_backend", "model"] } +serenity = { path = "../../", default-features = false, features = ["gateway", "model", "rustls_backend"] } tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } diff --git a/examples/e03_struct_utilities/Cargo.toml b/examples/e03_struct_utilities/Cargo.toml index bcb28fbf983..80548cee27f 100644 --- a/examples/e03_struct_utilities/Cargo.toml +++ b/examples/e03_struct_utilities/Cargo.toml @@ -5,5 +5,5 @@ authors = ["my name "] edition = "2018" [dependencies] -serenity = { path = "../../", default-features = false, features = ["client", "gateway", "rustls_backend", "model"] } +serenity = { path = "../../", default-features = false, features = ["gateway", "model", "rustls_backend"] } tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } diff --git a/examples/e04_message_builder/Cargo.toml b/examples/e04_message_builder/Cargo.toml index 0e36abf0b3d..144b1d0f155 100644 --- a/examples/e04_message_builder/Cargo.toml +++ b/examples/e04_message_builder/Cargo.toml @@ -5,5 +5,5 @@ authors = ["my name "] edition = "2018" [dependencies] -serenity = { path = "../../", default-features = false, features = ["client", "gateway", "rustls_backend", "model"] } +serenity = { path = "../../", default-features = false, features = ["gateway", "model", "rustls_backend"] } tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } diff --git a/examples/e05_sample_bot_structure/Cargo.toml b/examples/e05_sample_bot_structure/Cargo.toml index 97bd625dc00..40c5ec191fe 100644 --- a/examples/e05_sample_bot_structure/Cargo.toml +++ b/examples/e05_sample_bot_structure/Cargo.toml @@ -5,5 +5,5 @@ authors = ["my name "] edition = "2021" [dependencies] -serenity = { path = "../../", default-features = false, features = ["client", "gateway", "rustls_backend", "model", "collector"] } +serenity = { path = "../../", default-features = false, features = ["collector", "rustls_backend"] } tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } diff --git a/examples/e06_env_logging/Cargo.toml b/examples/e06_env_logging/Cargo.toml index 48f48964b69..b06835d181b 100644 --- a/examples/e06_env_logging/Cargo.toml +++ b/examples/e06_env_logging/Cargo.toml @@ -10,5 +10,5 @@ tracing-subscriber = "0.3" tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } [dependencies.serenity] -features = ["client", "rustls_backend"] +features = ["gateway", "rustls_backend"] path = "../../" diff --git a/examples/e07_shard_manager/Cargo.toml b/examples/e07_shard_manager/Cargo.toml index 8c6e041f79e..211277318ac 100644 --- a/examples/e07_shard_manager/Cargo.toml +++ b/examples/e07_shard_manager/Cargo.toml @@ -9,5 +9,5 @@ tokio = { version = "1.0", features = ["macros", "rt-multi-thread", "time"] } [dependencies.serenity] default-features = false -features = ["client", "gateway", "rustls_backend", "model"] +features = ["gateway", "model", "rustls_backend"] path = "../../" diff --git a/examples/e08_create_message_builder/Cargo.toml b/examples/e08_create_message_builder/Cargo.toml index 272acf60660..8e1cc2b35a0 100644 --- a/examples/e08_create_message_builder/Cargo.toml +++ b/examples/e08_create_message_builder/Cargo.toml @@ -5,5 +5,5 @@ authors = ["my name "] edition = "2018" [dependencies] -serenity = { path = "../../", default-features = false, features = ["client", "gateway", "rustls_backend", "model", "chrono"] } +serenity = { path = "../../", default-features = false, features = ["gateway", "model", "chrono", "rustls_backend"] } tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } diff --git a/examples/e09_collectors/Cargo.toml b/examples/e09_collectors/Cargo.toml index edae1438640..ab5603e689c 100644 --- a/examples/e09_collectors/Cargo.toml +++ b/examples/e09_collectors/Cargo.toml @@ -5,7 +5,7 @@ authors = ["my name "] edition = "2018" [dependencies.serenity] -features = ["framework", "rustls_backend", "collector"] +features = ["collector", "framework", "rustls_backend"] path = "../../" [dependencies] diff --git a/examples/e10_gateway_intents/Cargo.toml b/examples/e10_gateway_intents/Cargo.toml index 2801bc6a2ff..e92adcc6830 100644 --- a/examples/e10_gateway_intents/Cargo.toml +++ b/examples/e10_gateway_intents/Cargo.toml @@ -5,5 +5,5 @@ authors = ["my name "] edition = "2018" [dependencies] -serenity = { path = "../../", default-features = false, features = ["client", "gateway", "rustls_backend", "model"] } +serenity = { path = "../../", default-features = false, features = ["gateway", "model", "rustls_backend"] } tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } diff --git a/examples/e12_parallel_loops/Cargo.toml b/examples/e12_parallel_loops/Cargo.toml index fca117aa19e..7ad44ca6472 100644 --- a/examples/e12_parallel_loops/Cargo.toml +++ b/examples/e12_parallel_loops/Cargo.toml @@ -5,7 +5,7 @@ authors = ["my name "] edition = "2018" [dependencies] -serenity = { path = "../../", default-features = false, features = ["client", "gateway", "rustls_backend", "model", "cache"] } +serenity = { path = "../../", default-features = false, features = ["gateway", "model", "cache", "rustls_backend"] } tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } sys-info = "0.9" chrono = { version = "0.4", default-features = false, features = ["clock"] } diff --git a/examples/e13_sqlite_database/Cargo.toml b/examples/e13_sqlite_database/Cargo.toml index 5e62110b920..9cf3e53320f 100644 --- a/examples/e13_sqlite_database/Cargo.toml +++ b/examples/e13_sqlite_database/Cargo.toml @@ -5,6 +5,6 @@ authors = ["my name "] edition = "2018" [dependencies] -serenity = { path = "../../", default-features = false, features = ["client", "gateway", "rustls_backend", "model"] } +serenity = { path = "../../", default-features = false, features = ["gateway", "model", "rustls_backend"] } tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "sqlite"] } diff --git a/examples/e14_message_components/Cargo.toml b/examples/e14_message_components/Cargo.toml index 2c92496f6ea..f4882f23e52 100644 --- a/examples/e14_message_components/Cargo.toml +++ b/examples/e14_message_components/Cargo.toml @@ -5,6 +5,6 @@ authors = ["my name "] edition = "2018" [dependencies] -serenity = { path = "../../", default-features = false, features = ["client", "gateway", "rustls_backend", "model", "collector"] } +serenity = { path = "../../", default-features = false, features = ["gateway", "model", "collector", "rustls_backend"] } tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } dotenv = { version = "0.15.0" } diff --git a/examples/e15_webhook/Cargo.toml b/examples/e15_webhook/Cargo.toml index 8b47ff98c58..b3e9f9c8346 100644 --- a/examples/e15_webhook/Cargo.toml +++ b/examples/e15_webhook/Cargo.toml @@ -5,5 +5,5 @@ authors = ["my name "] edition = "2018" [dependencies] -serenity = { path = "../../", default-features = false, features = ["rustls_backend", "model"] } +serenity = { path = "../../", default-features = false, features = ["model", "rustls_backend"] } tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } diff --git a/examples/testing/Cargo.toml b/examples/testing/Cargo.toml index dbea94e6ba6..de539355513 100644 --- a/examples/testing/Cargo.toml +++ b/examples/testing/Cargo.toml @@ -5,6 +5,6 @@ authors = ["my name "] edition = "2018" [dependencies] -serenity = { path = "../../", default-features = false, features = ["client", "gateway", "rustls_backend", "model", "cache", "collector"] } +serenity = { path = "../../", default-features = false, features = ["gateway", "model", "cache", "collector", "rustls_backend"] } tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } env_logger = "0.10.0" diff --git a/src/cache/mod.rs b/src/cache/mod.rs index 8477682aed4..ca409faddba 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -268,7 +268,6 @@ impl Cache { /// struct Handler; /// /// #[serenity::async_trait] - /// # #[cfg(feature = "client")] /// impl EventHandler for Handler { /// async fn cache_ready(&self, ctx: Context, _: Vec) { /// println!("{} unknown members", ctx.cache.unknown_members()); @@ -319,7 +318,7 @@ impl Cache { /// } /// ``` /// - /// [`Context`]: crate::client::Context + /// [`Context`]: crate::gateway::Context /// [`Shard`]: crate::gateway::Shard pub fn guilds(&self) -> Vec { let unavailable_guilds = self.unavailable_guilds(); @@ -405,7 +404,7 @@ impl Cache { /// # } /// ``` /// - /// [`EventHandler::message`]: crate::client::EventHandler::message + /// [`EventHandler::message`]: crate::gateway::EventHandler::message pub fn message(&self, channel_id: ChannelId, message_id: MessageId) -> Option> { #[cfg(feature = "temp_cache")] if let Some(message) = self.temp_messages.get(&message_id) { diff --git a/src/client/error.rs b/src/client/error.rs deleted file mode 100644 index 33da36de381..00000000000 --- a/src/client/error.rs +++ /dev/null @@ -1,25 +0,0 @@ -use std::error::Error as StdError; -use std::fmt; - -/// An error returned from the [`Client`]. -/// -/// This is always wrapped within the library's generic [`Error::Client`] variant. -/// -/// [`Client`]: super::Client -/// [`Error::Client`]: crate::Error::Client -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -#[non_exhaustive] -pub enum Error { - /// When a shard has completely failed to reboot after resume and/or reconnect attempts. - ShardBootFailure, -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::ShardBootFailure => f.write_str("Failed to (re-)boot a shard"), - } - } -} - -impl StdError for Error {} diff --git a/src/error.rs b/src/error.rs index eded864a826..5f944606a07 100644 --- a/src/error.rs +++ b/src/error.rs @@ -7,8 +7,6 @@ use reqwest::{header::InvalidHeaderValue, Error as ReqwestError}; #[cfg(feature = "gateway")] use tokio_tungstenite::tungstenite::error::Error as TungsteniteError; -#[cfg(feature = "client")] -use crate::client::ClientError; #[cfg(feature = "gateway")] use crate::gateway::GatewayError; #[cfg(feature = "http")] @@ -24,9 +22,6 @@ use crate::model::ModelError; pub type Result = StdResult; /// A common error enum returned by most of the library's functionality within a custom [`Result`]. -/// -/// The most common error types, the [`ClientError`] and [`GatewayError`] enums, are both wrapped -/// around this in the form of the [`Self::Client`] and [`Self::Gateway`] variants. #[derive(Debug)] #[non_exhaustive] pub enum Error { @@ -38,11 +33,6 @@ pub enum Error { /// /// [`model`]: crate::model Model(ModelError), - /// A [client] error. - /// - /// [client]: crate::client - #[cfg(feature = "client")] - Client(ClientError), /// An error from the [`gateway`] module. /// /// [`gateway`]: crate::gateway @@ -117,8 +107,6 @@ impl fmt::Display for Error { Self::Io(inner) => fmt::Display::fmt(&inner, f), Self::Json(inner) => fmt::Display::fmt(&inner, f), Self::Model(inner) => fmt::Display::fmt(&inner, f), - #[cfg(feature = "client")] - Self::Client(inner) => fmt::Display::fmt(&inner, f), #[cfg(feature = "gateway")] Self::Gateway(inner) => fmt::Display::fmt(&inner, f), #[cfg(feature = "http")] @@ -136,8 +124,6 @@ impl StdError for Error { Self::Io(inner) => Some(inner), Self::Json(inner) => Some(inner), Self::Model(inner) => Some(inner), - #[cfg(feature = "client")] - Self::Client(inner) => Some(inner), #[cfg(feature = "gateway")] Self::Gateway(inner) => Some(inner), #[cfg(feature = "http")] diff --git a/src/framework/mod.rs b/src/framework/mod.rs index 94a4a705ef8..afbe140a1a3 100644 --- a/src/framework/mod.rs +++ b/src/framework/mod.rs @@ -2,18 +2,18 @@ //! //! This is used in combination with [`ClientBuilder::framework`]. //! -//! [`ClientBuilder::framework`]: crate::client::ClientBuilder::framework +//! [`ClientBuilder::framework`]: crate::gateway::ClientBuilder::framework use async_trait::async_trait; -use crate::client::{Client, Context, FullEvent}; +use crate::gateway::{Client, Context, FullEvent}; /// A trait for defining your own framework for serenity to use. /// /// Should you implement this trait, or define a `message` handler, depends on you. However, using /// this will benefit you by abstracting the [`EventHandler`] away. /// -/// [`EventHandler`]: crate::client::EventHandler +/// [`EventHandler`]: crate::gateway::EventHandler #[async_trait] pub trait Framework: Send + Sync { /// Called directly after the `Client` is created. diff --git a/src/gateway/bridge/shard_manager.rs b/src/gateway/bridge/shard_manager.rs index 0064f5cb428..80e3c5eb368 100644 --- a/src/gateway/bridge/shard_manager.rs +++ b/src/gateway/bridge/shard_manager.rs @@ -16,10 +16,9 @@ use super::VoiceGatewayManager; use super::{ShardId, ShardQueue, ShardQueuer, ShardQueuerMessage, ShardRunnerInfo}; #[cfg(feature = "cache")] use crate::cache::Cache; -use crate::client::InternalEventHandler; #[cfg(feature = "framework")] use crate::framework::Framework; -use crate::gateway::{ConnectionStage, GatewayError, PresenceData}; +use crate::gateway::{ConnectionStage, GatewayError, InternalEventHandler, PresenceData}; use crate::http::Http; use crate::internal::prelude::*; use crate::internal::tokio::spawn_named; @@ -49,8 +48,13 @@ use crate::model::gateway::GatewayIntents; /// use std::env; /// use std::sync::{Arc, OnceLock}; /// -/// use serenity::client::{EventHandler, InternalEventHandler, RawEventHandler}; -/// use serenity::gateway::{ShardManager, ShardManagerOptions}; +/// use serenity::gateway::{ +/// EventHandler, +/// InternalEventHandler, +/// RawEventHandler, +/// ShardManager, +/// ShardManagerOptions, +/// }; /// use serenity::http::Http; /// use serenity::model::gateway::GatewayIntents; /// use serenity::prelude::*; diff --git a/src/gateway/bridge/shard_queuer.rs b/src/gateway/bridge/shard_queuer.rs index 7d8e2d98d3c..054ec0d86c2 100644 --- a/src/gateway/bridge/shard_queuer.rs +++ b/src/gateway/bridge/shard_queuer.rs @@ -23,10 +23,15 @@ use super::{ }; #[cfg(feature = "cache")] use crate::cache::Cache; -use crate::client::InternalEventHandler; #[cfg(feature = "framework")] use crate::framework::Framework; -use crate::gateway::{ConnectionStage, PresenceData, Shard, ShardRunnerMessage}; +use crate::gateway::{ + ConnectionStage, + InternalEventHandler, + PresenceData, + Shard, + ShardRunnerMessage, +}; use crate::http::Http; use crate::internal::prelude::*; use crate::internal::tokio::spawn_named; @@ -45,8 +50,8 @@ pub struct ShardQueuer { pub data: Arc, /// A reference to [`EventHandler`] or [`RawEventHandler`]. /// - /// [`EventHandler`]: crate::client::EventHandler - /// [`RawEventHandler`]: crate::client::RawEventHandler + /// [`EventHandler`]: crate::gateway::EventHandler + /// [`RawEventHandler`]: crate::gateway::RawEventHandler pub event_handler: Option, /// A copy of the framework #[cfg(feature = "framework")] diff --git a/src/gateway/bridge/shard_runner.rs b/src/gateway/bridge/shard_runner.rs index b5ead15a5f1..f0dbaabaa89 100644 --- a/src/gateway/bridge/shard_runner.rs +++ b/src/gateway/bridge/shard_runner.rs @@ -15,11 +15,17 @@ use super::VoiceGatewayManager; use super::{ShardId, ShardManager, ShardRunnerMessage}; #[cfg(feature = "cache")] use crate::cache::Cache; -use crate::client::dispatch::dispatch_model; -use crate::client::{Context, InternalEventHandler}; #[cfg(feature = "framework")] use crate::framework::Framework; -use crate::gateway::{GatewayError, ReconnectType, Shard, ShardAction}; +use crate::gateway::dispatch::dispatch_model; +use crate::gateway::{ + Context, + GatewayError, + InternalEventHandler, + ReconnectType, + Shard, + ShardAction, +}; use crate::http::Http; use crate::internal::prelude::*; use crate::internal::tokio::spawn_named; diff --git a/src/client/context.rs b/src/gateway/client/context.rs similarity index 94% rename from src/client/context.rs rename to src/gateway/client/context.rs index cf1611cea64..22fd3a70778 100644 --- a/src/client/context.rs +++ b/src/gateway/client/context.rs @@ -3,9 +3,7 @@ use std::sync::Arc; #[cfg(feature = "cache")] pub use crate::cache::Cache; -use crate::gateway::ActivityData; -#[cfg(feature = "gateway")] -use crate::gateway::{ShardMessenger, ShardRunner}; +use crate::gateway::{ActivityData, ShardMessenger, ShardRunner}; use crate::http::Http; use crate::model::prelude::*; @@ -51,7 +49,6 @@ impl fmt::Debug for Context { impl Context { /// Create a new Context to be passed to an event handler. - #[cfg(feature = "gateway")] pub(crate) fn new( data: Arc, runner: &ShardRunner, @@ -69,19 +66,6 @@ impl Context { } } - #[cfg(all(not(feature = "cache"), not(feature = "gateway")))] - pub fn easy( - data: Arc, - shard_id: ShardId, - http: Arc, - ) -> Context { - Context { - shard_id, - data, - http, - } - } - /// A container for a data type that can be used across contexts. /// /// The purpose of the data field is to be accessible and persistent across contexts; that is, @@ -123,7 +107,6 @@ impl Context { /// ``` /// /// [`Online`]: OnlineStatus::Online - #[cfg(feature = "gateway")] pub fn online(&self) { self.shard.set_status(OnlineStatus::Online); } @@ -151,7 +134,6 @@ impl Context { /// ``` /// /// [`Idle`]: OnlineStatus::Idle - #[cfg(feature = "gateway")] pub fn idle(&self) { self.shard.set_status(OnlineStatus::Idle); } @@ -179,7 +161,6 @@ impl Context { /// ``` /// /// [`DoNotDisturb`]: OnlineStatus::DoNotDisturb - #[cfg(feature = "gateway")] pub fn dnd(&self) { self.shard.set_status(OnlineStatus::DoNotDisturb); } @@ -207,7 +188,6 @@ impl Context { /// ``` /// /// [`Invisible`]: OnlineStatus::Invisible - #[cfg(feature = "gateway")] pub fn invisible(&self) { self.shard.set_status(OnlineStatus::Invisible); } @@ -239,7 +219,6 @@ impl Context { /// /// [`Event::Resumed`]: crate::model::event::Event::Resumed /// [`Online`]: OnlineStatus::Online - #[cfg(feature = "gateway")] pub fn reset_presence(&self) { self.shard.set_presence(None, OnlineStatus::Online); } @@ -268,7 +247,6 @@ impl Context { /// } /// } /// ``` - #[cfg(feature = "gateway")] pub fn set_activity(&self, activity: Option) { self.shard.set_activity(activity); } @@ -317,7 +295,6 @@ impl Context { /// /// [`DoNotDisturb`]: OnlineStatus::DoNotDisturb /// [`Idle`]: OnlineStatus::Idle - #[cfg(feature = "gateway")] pub fn set_presence(&self, activity: Option, status: OnlineStatus) { self.shard.set_presence(activity, status); } diff --git a/src/client/dispatch.rs b/src/gateway/client/dispatch.rs similarity index 99% rename from src/client/dispatch.rs rename to src/gateway/client/dispatch.rs index 578299b473f..bf6aabd2b86 100644 --- a/src/client/dispatch.rs +++ b/src/gateway/client/dispatch.rs @@ -1,6 +1,6 @@ +#[cfg(feature = "framework")] use std::sync::Arc; -#[cfg(feature = "gateway")] use super::event_handler::InternalEventHandler; use super::{Context, FullEvent}; #[cfg(feature = "cache")] diff --git a/src/client/event_handler.rs b/src/gateway/client/event_handler.rs similarity index 99% rename from src/client/event_handler.rs rename to src/gateway/client/event_handler.rs index ef622d391bd..3330ef1135f 100644 --- a/src/client/event_handler.rs +++ b/src/gateway/client/event_handler.rs @@ -45,9 +45,9 @@ macro_rules! event_handler { /// complexity of the filter code low to avoid unnecessarily blocking /// your bot. fn filter_event(&self, context: &Context, event: &Event) -> bool { - // Suppress unused argument warnings - #[allow(dropping_references, dropping_copy_types)] - drop(( context, event )); + // Suppress unused argument warnings + #[allow(dropping_references, dropping_copy_types)] + drop((context, event)); true } } @@ -71,7 +71,7 @@ macro_rules! event_handler { /// Returns the name of this event as a snake case string /// /// ```rust,no_run - /// # use serenity::client::{Context, FullEvent}; + /// # use serenity::gateway::{Context, FullEvent}; /// # fn _foo(ctx: Context, event: FullEvent) { /// if let FullEvent::Message { .. } = &event { /// assert_eq!(event.snake_case_name(), "message"); diff --git a/src/client/mod.rs b/src/gateway/client/mod.rs similarity index 95% rename from src/client/mod.rs rename to src/gateway/client/mod.rs index 9d4c5c83afd..b38a32656d9 100644 --- a/src/client/mod.rs +++ b/src/gateway/client/mod.rs @@ -1,24 +1,11 @@ -//! The Client contains information about a single bot's token, as well as event handlers. -//! Dispatching events to configured handlers and starting the shards' connections are handled -//! directly via the client. In addition, the `http` module and `Cache` are also automatically -//! handled by the Client module for you. +//! The [`Client`] contains information about a bot's token, as well as event handlers. Dispatching +//! events to handlers and starting sharded gateway connections is handled directly by the client. +//! In addition, the client automatically handles caching via the [`Cache`] struct. //! -//! A [`Context`] is provided for every handler. -//! -//! The `http` module is the lower-level method of interacting with the Discord REST API. -//! Realistically, there should be little reason to use this yourself, as the Context will do this -//! for you. A possible use case of using the `http` module is if you do not have a Cache, for -//! purposes such as low memory requirements. -//! -//! Click [here][Client examples] for an example on how to use a `Client`. -//! -//! [Client examples]: Client#examples +//! Click [here][Client#examples] for an example on how to use a [`Client`]. mod context; -#[cfg(feature = "gateway")] pub(crate) mod dispatch; -mod error; -#[cfg(feature = "gateway")] mod event_handler; use std::future::IntoFuture; @@ -34,26 +21,19 @@ use futures::StreamExt as _; use tracing::debug; pub use self::context::Context; -pub use self::error::Error as ClientError; -#[cfg(feature = "gateway")] pub use self::event_handler::{EventHandler, FullEvent, InternalEventHandler, RawEventHandler}; -#[cfg(feature = "gateway")] -use super::gateway::GatewayError; #[cfg(feature = "cache")] -pub use crate::cache::Cache; +use crate::cache::Cache; #[cfg(feature = "cache")] use crate::cache::Settings as CacheSettings; #[cfg(feature = "framework")] use crate::framework::Framework; #[cfg(feature = "voice")] use crate::gateway::VoiceGatewayManager; -use crate::gateway::{ActivityData, PresenceData}; -#[cfg(feature = "gateway")] -use crate::gateway::{ShardManager, ShardManagerOptions}; +use crate::gateway::{ActivityData, GatewayError, PresenceData, ShardManager, ShardManagerOptions}; use crate::http::Http; use crate::internal::prelude::*; use crate::internal::tokio::spawn_named; -#[cfg(feature = "gateway")] use crate::model::gateway::GatewayIntents; use crate::model::id::ApplicationId; #[cfg(feature = "voice")] @@ -62,7 +42,6 @@ use crate::model::user::OnlineStatus; use crate::utils::check_shard_total; /// A builder implementing [`IntoFuture`] building a [`Client`] to interact with Discord. -#[cfg(feature = "gateway")] #[must_use = "Builders do nothing unless they are awaited"] pub struct ClientBuilder { data: Option>, @@ -79,7 +58,6 @@ pub struct ClientBuilder { presence: PresenceData, } -#[cfg(feature = "gateway")] impl ClientBuilder { /// Construct a new builder to call methods on for the client construction. The `token` will /// automatically be prefixed "Bot " if not already. @@ -280,7 +258,6 @@ impl ClientBuilder { } } -#[cfg(feature = "gateway")] impl IntoFuture for ClientBuilder { type Output = Result; @@ -423,7 +400,6 @@ impl IntoFuture for ClientBuilder { /// [`Shard`]: crate::gateway::Shard /// [`Event::MessageCreate`]: crate::model::event::Event::MessageCreate /// [sharding docs]: crate::gateway#sharding -#[cfg(feature = "gateway")] pub struct Client { data: Arc, /// A HashMap of all shards instantiated by the Client. diff --git a/src/gateway/mod.rs b/src/gateway/mod.rs index 792292b7709..a3dbc611419 100644 --- a/src/gateway/mod.rs +++ b/src/gateway/mod.rs @@ -40,6 +40,7 @@ //! [docs]: https://discordapp.com/developers/docs/topics/gateway#sharding mod bridge; +pub mod client; mod error; mod shard; mod ws; @@ -51,6 +52,7 @@ use reqwest::IntoUrl; use reqwest::Url; pub use self::bridge::*; +pub use self::client::*; pub use self::error::Error as GatewayError; pub use self::shard::Shard; pub use self::ws::WsClient; diff --git a/src/gateway/ws.rs b/src/gateway/ws.rs index d479d8b6962..0917e568828 100644 --- a/src/gateway/ws.rs +++ b/src/gateway/ws.rs @@ -1,41 +1,24 @@ use std::env::consts; -#[cfg(feature = "client")] use std::io::Read; use std::time::SystemTime; -#[cfg(feature = "client")] use flate2::read::ZlibDecoder; -use futures::SinkExt; -#[cfg(feature = "client")] -use futures::StreamExt; -#[cfg(feature = "client")] +use futures::{SinkExt, StreamExt}; use small_fixed_array::FixedString; use tokio::net::TcpStream; -#[cfg(feature = "client")] use tokio::time::{timeout, Duration}; -#[cfg(feature = "client")] -use tokio_tungstenite::tungstenite::protocol::CloseFrame; -use tokio_tungstenite::tungstenite::protocol::WebSocketConfig; -#[cfg(feature = "client")] -use tokio_tungstenite::tungstenite::Error as WsError; -use tokio_tungstenite::tungstenite::Message; +use tokio_tungstenite::tungstenite::protocol::{CloseFrame, WebSocketConfig}; +use tokio_tungstenite::tungstenite::{Error as WsError, Message}; use tokio_tungstenite::{connect_async_with_config, MaybeTlsStream, WebSocketStream}; -#[cfg(feature = "client")] -use tracing::warn; -use tracing::{debug, trace}; +use tracing::{debug, trace, warn}; use url::Url; -use super::{ActivityData, ChunkGuildFilter, PresenceData}; +use super::{ActivityData, ChunkGuildFilter, GatewayError, PresenceData}; use crate::constants::{self, Opcode}; -#[cfg(feature = "client")] -use crate::gateway::GatewayError; -#[cfg(feature = "client")] use crate::model::event::GatewayEvent; use crate::model::gateway::{GatewayIntents, ShardInfo}; use crate::model::id::{GuildId, UserId}; -#[cfg(feature = "client")] -use crate::Error; -use crate::Result; +use crate::{Error, Result}; #[derive(Serialize)] struct IdentifyProperties { @@ -94,9 +77,7 @@ struct WebSocketMessage<'a> { pub struct WsClient(WebSocketStream>); -#[cfg(feature = "client")] const TIMEOUT: Duration = Duration::from_millis(500); -#[cfg(feature = "client")] const DECOMPRESSION_MULTIPLIER: usize = 3; impl WsClient { @@ -111,7 +92,6 @@ impl WsClient { Ok(Self(stream)) } - #[cfg(feature = "client")] pub(crate) async fn recv_json(&mut self) -> Result> { let message = match timeout(TIMEOUT, self.0.next()).await { Ok(Some(Ok(msg))) => msg, @@ -166,20 +146,17 @@ impl WsClient { } /// Delegate to `StreamExt::next` - #[cfg(feature = "client")] pub(crate) async fn next(&mut self) -> Option> { self.0.next().await } /// Delegate to `SinkExt::send` - #[cfg(feature = "client")] pub(crate) async fn send(&mut self, message: Message) -> Result<()> { self.0.send(message).await?; Ok(()) } /// Delegate to `WebSocketStream::close` - #[cfg(feature = "client")] pub(crate) async fn close(&mut self, msg: Option>) -> Result<()> { self.0.close(msg).await?; Ok(()) diff --git a/src/http/client.rs b/src/http/client.rs index 4e58f00ca4b..710a9d7e46d 100644 --- a/src/http/client.rs +++ b/src/http/client.rs @@ -530,7 +530,7 @@ impl Http { /// /// See [`Context::create_application_emoji`] for required fields. /// - /// [`Context::create_application_emoji`]: crate::client::Context::create_application_emoji + /// [`Context::create_application_emoji`]: crate::gateway::Context::create_application_emoji pub async fn create_application_emoji(&self, map: &impl serde::Serialize) -> Result { self.fire(Request { body: Some(to_vec(map)?), @@ -1506,7 +1506,7 @@ impl Http { /// /// See [`Context::edit_application_emoji`] for required fields. /// - /// [`Context::edit_application_emoji`]: crate::client::Context::edit_application_emoji + /// [`Context::edit_application_emoji`]: crate::gateway::Context::edit_application_emoji pub async fn edit_application_emoji( &self, emoji_id: EmojiId, diff --git a/src/http/mod.rs b/src/http/mod.rs index 5484634ff73..28838c75d3d 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs @@ -41,8 +41,8 @@ pub use self::routing::*; pub use self::typing::*; #[cfg(feature = "cache")] use crate::cache::Cache; -#[cfg(feature = "client")] -use crate::client::Context; +#[cfg(feature = "gateway")] +use crate::gateway::Context; use crate::model::prelude::*; /// This trait will be required by functions that need [`Http`] and can optionally use a [`Cache`] @@ -94,7 +94,7 @@ where } } -#[cfg(feature = "client")] +#[cfg(feature = "gateway")] impl CacheHttp for Context { fn http(&self) -> &Http { &self.http diff --git a/src/lib.rs b/src/lib.rs index f23e812d39b..3db5d4f5a6a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,14 +37,14 @@ //! ``` //! //! [`Cache`]: crate::cache::Cache -//! [`Context`]: crate::client::Context -//! [`EventHandler::message`]: crate::client::EventHandler::message +//! [`Context`]: crate::gateway::Context +//! [`EventHandler::message`]: crate::gateway::EventHandler::message //! [`Event`]: crate::model::event::Event //! [`Event::MessageCreate`]: crate::model::event::Event::MessageCreate //! [`Shard`]: crate::gateway::Shard //! [`examples`]: https://github.com/serenity-rs/serenity/blob/current/examples //! [cache docs]: crate::cache -//! [client's module-level documentation]: crate::client +//! [client's module-level documentation]: crate::gateway::client //! [docs]: https://discord.com/developers/docs/intro //! [examples]: https://github.com/serenity-rs/serenity/tree/current/examples //! [gateway docs]: crate::gateway @@ -91,8 +91,6 @@ pub mod prelude; pub mod builder; #[cfg(feature = "cache")] pub mod cache; -#[cfg(feature = "client")] -pub mod client; #[cfg(feature = "collector")] pub mod collector; #[cfg(feature = "framework")] @@ -108,9 +106,9 @@ pub mod utils; mod error; -#[cfg(all(feature = "client", feature = "gateway"))] -pub use crate::client::Client; pub use crate::error::{Error, Result}; +#[cfg(feature = "gateway")] +pub use crate::gateway::Client; /// Special module that re-exports most public items from this crate. /// @@ -122,9 +120,6 @@ pub mod all { #[cfg(feature = "cache")] #[doc(no_inline)] pub use crate::cache::*; - #[cfg(feature = "client")] - #[doc(no_inline)] - pub use crate::client::*; #[cfg(feature = "collector")] #[doc(no_inline)] pub use crate::collector::*; diff --git a/src/model/application/command.rs b/src/model/application/command.rs index 78ecdc3b9bb..5832e9747a6 100644 --- a/src/model/application/command.rs +++ b/src/model/application/command.rs @@ -153,7 +153,7 @@ impl Command { /// /// See [`CreateCommand::execute`] for a list of possible errors. /// - /// [`InteractionCreate`]: crate::client::EventHandler::interaction_create + /// [`InteractionCreate`]: crate::gateway::EventHandler::interaction_create pub async fn create_global_command(http: &Http, builder: CreateCommand<'_>) -> Result { builder.execute(http, None, None).await } diff --git a/src/model/application/command_interaction.rs b/src/model/application/command_interaction.rs index 8232542e01a..77db8ef55f7 100644 --- a/src/model/application/command_interaction.rs +++ b/src/model/application/command_interaction.rs @@ -14,7 +14,7 @@ use crate::builder::{ EditInteractionResponse, }; #[cfg(feature = "collector")] -use crate::client::Context; +use crate::gateway::Context; #[cfg(feature = "model")] use crate::http::Http; use crate::internal::prelude::*; diff --git a/src/model/application/component_interaction.rs b/src/model/application/component_interaction.rs index ca10be8472b..b086c02007a 100644 --- a/src/model/application/component_interaction.rs +++ b/src/model/application/component_interaction.rs @@ -10,7 +10,7 @@ use crate::builder::{ EditInteractionResponse, }; #[cfg(feature = "collector")] -use crate::client::Context; +use crate::gateway::Context; #[cfg(feature = "model")] use crate::http::Http; use crate::internal::prelude::*; diff --git a/src/model/channel/attachment.rs b/src/model/channel/attachment.rs index 2655e53cf40..396da8e53c7 100644 --- a/src/model/channel/attachment.rs +++ b/src/model/channel/attachment.rs @@ -103,7 +103,7 @@ impl Attachment { /// # struct Handler; /// /// #[serenity::async_trait] - /// # #[cfg(feature = "client")] + /// # #[cfg(feature = "gateway")] /// impl EventHandler for Handler { /// async fn message(&self, context: Context, message: Message) { /// for attachment in message.attachments { diff --git a/src/model/error.rs b/src/model/error.rs index d8ab25d8d31..9bbaf3f78d4 100644 --- a/src/model/error.rs +++ b/src/model/error.rs @@ -111,8 +111,8 @@ impl fmt::Display for Minimum { /// /// # struct Handler; /// +/// # #[cfg(feature = "gateway")] /// #[serenity::async_trait] -/// #[cfg(feature = "client")] /// impl EventHandler for Handler { /// async fn guild_ban_removal(&self, ctx: Context, guild_id: GuildId, user: User) { /// match guild_id.ban(&ctx.http, user.id, 8, Some("No unbanning people!")).await { diff --git a/src/model/event.rs b/src/model/event.rs index 2b0b1ae2a38..a3510c730f6 100644 --- a/src/model/event.rs +++ b/src/model/event.rs @@ -1139,7 +1139,7 @@ pub enum Event { /// Fires the [`EventHandler::command_permissions_update`] event. /// /// [`Command`]: crate::model::application::Command - /// [`EventHandler::command_permissions_update`]: crate::client::EventHandler::command_permissions_update + /// [`EventHandler::command_permissions_update`]: crate::gateway::EventHandler::command_permissions_update #[serde(rename = "APPLICATION_COMMAND_PERMISSIONS_UPDATE")] CommandPermissionsUpdate(CommandPermissionsUpdateEvent), /// A [`Rule`] was created. @@ -1147,7 +1147,7 @@ pub enum Event { /// Fires the [`EventHandler::auto_moderation_rule_create`] event. /// /// [`EventHandler::auto_moderation_rule_create`]: - /// crate::client::EventHandler::auto_moderation_rule_create + /// crate::gateway::EventHandler::auto_moderation_rule_create #[serde(rename = "AUTO_MODERATION_RULE_CREATE")] AutoModRuleCreate(AutoModRuleCreateEvent), /// A [`Rule`] has been updated. @@ -1155,7 +1155,7 @@ pub enum Event { /// Fires the [`EventHandler::auto_moderation_rule_update`] event. /// /// [`EventHandler::auto_moderation_rule_update`]: - /// crate::client::EventHandler::auto_moderation_rule_update + /// crate::gateway::EventHandler::auto_moderation_rule_update #[serde(rename = "AUTO_MODERATION_RULE_UPDATE")] AutoModRuleUpdate(AutoModRuleUpdateEvent), /// A [`Rule`] was deleted. @@ -1163,7 +1163,7 @@ pub enum Event { /// Fires the [`EventHandler::auto_moderation_rule_delete`] event. /// /// [`EventHandler::auto_moderation_rule_delete`]: - /// crate::client::EventHandler::auto_moderation_rule_delete + /// crate::gateway::EventHandler::auto_moderation_rule_delete #[serde(rename = "AUTO_MODERATION_RULE_DELETE")] AutoModRuleDelete(AutoModRuleDeleteEvent), /// A [`Rule`] was triggered and an action was executed. @@ -1171,32 +1171,32 @@ pub enum Event { /// Fires the [`EventHandler::auto_moderation_action_execution`] event. /// /// [`EventHandler::auto_moderation_action_execution`]: - /// crate::client::EventHandler::auto_moderation_action_execution + /// crate::gateway::EventHandler::auto_moderation_action_execution #[serde(rename = "AUTO_MODERATION_ACTION_EXECUTION")] AutoModActionExecution(AutoModActionExecutionEvent), /// A [`Channel`] was created. /// /// Fires the [`EventHandler::channel_create`] event. /// - /// [`EventHandler::channel_create`]: crate::client::EventHandler::channel_create + /// [`EventHandler::channel_create`]: crate::gateway::EventHandler::channel_create ChannelCreate(ChannelCreateEvent), /// A [`Channel`] has been deleted. /// /// Fires the [`EventHandler::channel_delete`] event. /// - /// [`EventHandler::channel_delete`]: crate::client::EventHandler::channel_delete + /// [`EventHandler::channel_delete`]: crate::gateway::EventHandler::channel_delete ChannelDelete(ChannelDeleteEvent), /// The pins for a [`Channel`] have been updated. /// /// Fires the [`EventHandler::channel_pins_update`] event. /// - /// [`EventHandler::channel_pins_update`]: crate::client::EventHandler::channel_pins_update + /// [`EventHandler::channel_pins_update`]: crate::gateway::EventHandler::channel_pins_update ChannelPinsUpdate(ChannelPinsUpdateEvent), /// A [`Channel`] has been updated. /// /// Fires the [`EventHandler::channel_update`] event. /// - /// [`EventHandler::channel_update`]: crate::client::EventHandler::channel_update + /// [`EventHandler::channel_update`]: crate::gateway::EventHandler::channel_update ChannelUpdate(ChannelUpdateEvent), GuildAuditLogEntryCreate(GuildAuditLogEntryCreateEvent), GuildBanAdd(GuildBanAddEvent), @@ -1220,13 +1220,13 @@ pub enum Event { /// /// Fires the [`EventHandler::invite_create`] event handler. /// - /// [`EventHandler::invite_create`]: crate::client::EventHandler::invite_create + /// [`EventHandler::invite_create`]: crate::gateway::EventHandler::invite_create InviteCreate(InviteCreateEvent), /// An [`Invite`] was deleted. /// /// Fires the [`EventHandler::invite_delete`] event handler. /// - /// [`EventHandler::invite_delete`]: crate::client::EventHandler::invite_delete + /// [`EventHandler::invite_delete`]: crate::gateway::EventHandler::invite_delete InviteDelete(InviteDeleteEvent), MessageCreate(MessageCreateEvent), MessageDelete(MessageDeleteEvent), @@ -1239,28 +1239,28 @@ pub enum Event { /// /// Fires the [`EventHandler::reaction_add`] event handler. /// - /// [`EventHandler::reaction_add`]: crate::client::EventHandler::reaction_add + /// [`EventHandler::reaction_add`]: crate::gateway::EventHandler::reaction_add #[serde(rename = "MESSAGE_REACTION_ADD")] ReactionAdd(ReactionAddEvent), /// A reaction was removed to a message. /// /// Fires the [`EventHandler::reaction_remove`] event handler. /// - /// [`EventHandler::reaction_remove`]: crate::client::EventHandler::reaction_remove + /// [`EventHandler::reaction_remove`]: crate::gateway::EventHandler::reaction_remove #[serde(rename = "MESSAGE_REACTION_REMOVE")] ReactionRemove(ReactionRemoveEvent), /// A request was issued to remove all [`Reaction`]s from a [`Message`]. /// /// Fires the [`EventHandler::reaction_remove_all`] event handler. /// - /// [`EventHandler::reaction_remove_all`]: crate::client::EventHandler::reaction_remove_all + /// [`EventHandler::reaction_remove_all`]: crate::gateway::EventHandler::reaction_remove_all #[serde(rename = "MESSAGE_REACTION_REMOVE_ALL")] ReactionRemoveAll(ReactionRemoveAllEvent), /// Sent when a bot removes all instances of a given emoji from the reactions of a message. /// /// Fires the [`EventHandler::reaction_remove_emoji`] event handler. /// - /// [`EventHandler::reaction_remove_emoji`]: crate::client::EventHandler::reaction_remove_emoji + /// [`EventHandler::reaction_remove_emoji`]: crate::gateway::EventHandler::reaction_remove_emoji #[serde(rename = "MESSAGE_REACTION_REMOVE_EMOJI")] ReactionRemoveEmoji(ReactionRemoveEmojiEvent), /// The first event in a connection, containing the initial ready cache. diff --git a/src/model/guild/mod.rs b/src/model/guild/mod.rs index 0a59b4c2bfb..26c9d3e2dc8 100644 --- a/src/model/guild/mod.rs +++ b/src/model/guild/mod.rs @@ -2102,8 +2102,8 @@ impl Guild { /// # use serenity::prelude::*; /// # struct Handler; /// + /// # #[cfg(all(feature = "cache", feature = "gateway"))] /// #[serenity::async_trait] - /// #[cfg(all(feature = "cache", feature = "client"))] /// impl EventHandler for Handler { /// async fn message(&self, ctx: Context, msg: Message) { /// if let Some(guild_id) = msg.guild_id { diff --git a/src/model/guild/partial_guild.rs b/src/model/guild/partial_guild.rs index 703e3736015..937a0943c58 100644 --- a/src/model/guild/partial_guild.rs +++ b/src/model/guild/partial_guild.rs @@ -1310,8 +1310,8 @@ impl PartialGuild { /// # use serenity::prelude::*; /// # struct Handler; /// + /// # #[cfg(all(feature = "cache", feature = "gateway"))] /// #[serenity::async_trait] - /// #[cfg(all(feature = "cache", feature = "client"))] /// impl EventHandler for Handler { /// async fn message(&self, ctx: Context, msg: Message) { /// if let Some(guild_id) = msg.guild_id { diff --git a/src/model/user.rs b/src/model/user.rs index cdeffc0c64d..b82b1f98baf 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -520,7 +520,7 @@ impl User { /// # struct Handler; /// /// #[serenity::async_trait] - /// # #[cfg(feature = "client")] + /// # #[cfg(feature = "gateway")] /// impl EventHandler for Handler { /// async fn message(&self, context: Context, msg: Message) { /// if msg.content == "!mytag" { @@ -654,7 +654,7 @@ impl UserId { /// use serenity::builder::CreateMessage; /// /// #[serenity::async_trait] - /// # #[cfg(feature = "client")] + /// # #[cfg(feature = "gateway")] /// impl EventHandler for Handler { /// async fn message(&self, ctx: Context, msg: Message) { /// if msg.content == "~help" { diff --git a/src/prelude.rs b/src/prelude.rs index e3221a439f9..3d8e72730b9 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -15,13 +15,9 @@ pub use tokio::sync::{Mutex, RwLock}; -#[cfg(feature = "client")] -pub use crate::client::Context; -#[cfg(all(feature = "client", feature = "gateway"))] -pub use crate::client::{Client, ClientError, EventHandler, RawEventHandler}; pub use crate::error::Error as SerenityError; #[cfg(feature = "gateway")] -pub use crate::gateway::GatewayError; +pub use crate::gateway::{Client, Context, EventHandler, GatewayError, RawEventHandler}; #[cfg(feature = "http")] pub use crate::http::CacheHttp; #[cfg(feature = "http")] diff --git a/src/utils/argument_convert/message.rs b/src/utils/argument_convert/message.rs index 6b74acc8650..6023402a39d 100644 --- a/src/utils/argument_convert/message.rs +++ b/src/utils/argument_convert/message.rs @@ -59,11 +59,11 @@ impl ArgumentConvert for Message { let extract_from_message_id = || Some((channel_id?, s.parse().ok()?)); let extract_from_message_url = || { - let (_guild_id, channel_id, message_id) = crate::utils::parse_message_url(s)?; + let (_guild_id, channel_id, message_id) = super::parse_message_url(s)?; Some((channel_id, message_id)) }; - let (channel_id, message_id) = crate::utils::parse_message_id_pair(s) + let (channel_id, message_id) = super::parse_message_id_pair(s) .or_else(extract_from_message_id) .or_else(extract_from_message_url) .ok_or(MessageParseError::Malformed)?; diff --git a/src/utils/content_safe.rs b/src/utils/content_safe.rs index a09f4fcab5a..26227845888 100644 --- a/src/utils/content_safe.rs +++ b/src/utils/content_safe.rs @@ -64,7 +64,7 @@ impl Default for ContentSafeOptions { /// Sanitise an `@everyone` mention. /// /// ```rust -/// # let cache = serenity::client::Cache::default(); +/// # let cache = serenity::cache::Cache::default(); /// # let guild = serenity::model::guild::Guild::default(); /// use serenity::utils::{content_safe, ContentSafeOptions}; /// @@ -77,7 +77,7 @@ impl Default for ContentSafeOptions { /// Filtering out mentions from a message. /// /// ```rust -/// use serenity::client::Cache; +/// use serenity::cache::Cache; /// use serenity::model::channel::Message; /// use serenity::utils::{content_safe, ContentSafeOptions}; /// diff --git a/src/utils/mod.rs b/src/utils/mod.rs index edaaab905e3..bfef7567aa1 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,7 +1,7 @@ //! A set of utilities to help with common use cases that are not required to fully use the //! library. -#[cfg(feature = "client")] +#[cfg(feature = "gateway")] mod argument_convert; #[cfg(feature = "cache")] mod content_safe; @@ -15,7 +15,7 @@ pub mod token; use std::num::NonZeroU16; -#[cfg(feature = "client")] +#[cfg(feature = "gateway")] pub use argument_convert::*; #[cfg(feature = "cache")] pub use content_safe::*; diff --git a/src/utils/quick_modal.rs b/src/utils/quick_modal.rs index af22eb3e6c5..da581fe6dea 100644 --- a/src/utils/quick_modal.rs +++ b/src/utils/quick_modal.rs @@ -1,8 +1,8 @@ use std::borrow::Cow; use crate::builder::{CreateActionRow, CreateInputText, CreateInteractionResponse, CreateModal}; -use crate::client::Context; use crate::collector::ModalInteractionCollector; +use crate::gateway::Context; use crate::internal::prelude::*; use crate::model::prelude::*; From e9d1f85c2a0e49b3cfdb740cdfe807f411ca40e5 Mon Sep 17 00:00:00 2001 From: Michael Krasnitski Date: Sat, 17 Aug 2024 03:22:06 -0400 Subject: [PATCH 2/3] Rearrange gateway `bridge` module into `sharding` and spruce up docs --- src/gateway/bridge/event.rs | 20 -- src/gateway/bridge/mod.rs | 114 ---------- src/gateway/bridge/shard_runner_message.rs | 53 ----- src/gateway/client/mod.rs | 20 +- src/gateway/mod.rs | 144 ++---------- src/gateway/{shard.rs => sharding/mod.rs} | 208 ++++++++++++++++-- .../{bridge => sharding}/shard_manager.rs | 4 +- .../{bridge => sharding}/shard_messenger.rs | 0 .../{bridge => sharding}/shard_queuer.rs | 18 +- .../{bridge => sharding}/shard_runner.rs | 66 +++++- src/gateway/{bridge => }/voice.rs | 0 11 files changed, 293 insertions(+), 354 deletions(-) delete mode 100644 src/gateway/bridge/event.rs delete mode 100644 src/gateway/bridge/mod.rs delete mode 100644 src/gateway/bridge/shard_runner_message.rs rename src/gateway/{shard.rs => sharding/mod.rs} (79%) rename src/gateway/{bridge => sharding}/shard_manager.rs (99%) rename src/gateway/{bridge => sharding}/shard_messenger.rs (100%) rename src/gateway/{bridge => sharding}/shard_queuer.rs (96%) rename src/gateway/{bridge => sharding}/shard_runner.rs (89%) rename src/gateway/{bridge => }/voice.rs (100%) diff --git a/src/gateway/bridge/event.rs b/src/gateway/bridge/event.rs deleted file mode 100644 index 0ee307c091d..00000000000 --- a/src/gateway/bridge/event.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! A collection of events created by the client, not a part of the Discord API itself. - -use crate::gateway::ConnectionStage; -use crate::model::id::ShardId; - -/// An event denoting that a shard's connection stage was changed. -/// -/// # Examples -/// -/// This might happen when a shard changes from [`ConnectionStage::Identifying`] to -/// [`ConnectionStage::Connected`]. -#[derive(Clone, Debug)] -pub struct ShardStageUpdateEvent { - /// The new connection stage. - pub new: ConnectionStage, - /// The old connection stage. - pub old: ConnectionStage, - /// The ID of the shard that had its connection stage change. - pub shard_id: ShardId, -} diff --git a/src/gateway/bridge/mod.rs b/src/gateway/bridge/mod.rs deleted file mode 100644 index f5b2bbe845c..00000000000 --- a/src/gateway/bridge/mod.rs +++ /dev/null @@ -1,114 +0,0 @@ -//! The client gateway bridge is support essential for the [`client`] module. -//! -//! This is made available for user use if one wishes to be lower-level or avoid the higher -//! functionality of the [`Client`]. -//! -//! Of interest are three pieces: -//! -//! ### [`ShardManager`] -//! -//! The shard manager is responsible for being a clean interface between the user and the shard -//! runners, providing essential functions such as [`ShardManager::shutdown`] to shutdown a shard -//! and [`ShardManager::restart`] to restart a shard. -//! -//! If you are using the `Client`, this is likely the only piece of interest to you. Refer to [its -//! documentation][`ShardManager`] for more information. -//! -//! ### [`ShardQueuer`] -//! -//! The shard queuer is a light wrapper around an mpsc receiver that receives -//! [`ShardQueuerMessage`]s. It should be run in its own thread so it can receive messages to -//! start shards in a queue. -//! -//! Refer to [its documentation][`ShardQueuer`] for more information. -//! -//! ### [`ShardRunner`] -//! -//! The shard runner is responsible for actually running a shard and communicating with its -//! respective WebSocket client. -//! -//! It is performs all actions such as sending a presence update over the client and, with the help -//! of the [`Shard`], will be able to determine what to do. This is, for example, whether to -//! reconnect, resume, or identify with the gateway. -//! -//! ### In Conclusion -//! -//! For almost every - if not every - use case, you only need to _possibly_ be concerned about the -//! [`ShardManager`] in this module. -//! -//! [`client`]: crate::client -//! [`Client`]: crate::Client -//! [`Shard`]: crate::gateway::Shard - -mod event; -mod shard_manager; -mod shard_messenger; -mod shard_queuer; -mod shard_runner; -mod shard_runner_message; -#[cfg(feature = "voice")] -mod voice; - -use std::fmt; -use std::num::NonZeroU16; -use std::sync::Arc; -use std::time::Duration as StdDuration; - -pub use self::event::ShardStageUpdateEvent; -pub use self::shard_manager::{ShardManager, ShardManagerOptions}; -pub use self::shard_messenger::ShardMessenger; -pub use self::shard_queuer::{ShardQueue, ShardQueuer}; -pub use self::shard_runner::{ShardRunner, ShardRunnerOptions}; -pub use self::shard_runner_message::ShardRunnerMessage; -#[cfg(feature = "voice")] -pub use self::voice::VoiceGatewayManager; -use super::ChunkGuildFilter; -use crate::gateway::ConnectionStage; -use crate::model::event::Event; -use crate::model::id::ShardId; - -/// A message to be sent to the [`ShardQueuer`]. -#[derive(Clone, Debug)] -pub enum ShardQueuerMessage { - /// Message to set the shard total. - SetShardTotal(NonZeroU16), - /// Message to start a shard. - Start { shard_id: ShardId, concurrent: bool }, - /// Message to shutdown the shard queuer. - Shutdown, - /// Message to dequeue/shutdown a shard. - ShutdownShard { shard_id: ShardId, code: u16 }, -} - -/// Information about a [`ShardRunner`]. -/// -/// The [`ShardId`] is not included because, as it stands, you probably already know the Id if you -/// obtained this. -#[derive(Debug)] -pub struct ShardRunnerInfo { - /// The latency between when a heartbeat was sent and when the acknowledgement was received. - pub latency: Option, - /// The channel used to communicate with the shard runner, telling it what to do with regards - /// to its status. - pub runner_tx: ShardMessenger, - /// The current connection stage of the shard. - pub stage: ConnectionStage, -} - -/// Newtype around a callback that will be called on every incoming request. As long as this -/// collector should still receive events, it should return `true`. Once it returns `false`, it is -/// removed. -#[derive(Clone)] -pub struct CollectorCallback(pub Arc bool + Send + Sync>); - -impl std::fmt::Debug for CollectorCallback { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("CollectorCallback").finish() - } -} - -impl PartialEq for CollectorCallback { - fn eq(&self, other: &Self) -> bool { - Arc::ptr_eq(&self.0, &other.0) - } -} diff --git a/src/gateway/bridge/shard_runner_message.rs b/src/gateway/bridge/shard_runner_message.rs deleted file mode 100644 index dc9ce9b97c7..00000000000 --- a/src/gateway/bridge/shard_runner_message.rs +++ /dev/null @@ -1,53 +0,0 @@ -use tokio_tungstenite::tungstenite::Message; - -use super::ShardId; -use crate::gateway::{ActivityData, ChunkGuildFilter}; -use crate::model::id::GuildId; -use crate::model::user::OnlineStatus; - -/// A message to send from a shard over a WebSocket. -#[derive(Debug)] -pub enum ShardRunnerMessage { - /// Indicator that a shard should be restarted. - Restart(ShardId), - /// Indicator that a shard should be fully shutdown without bringing it - /// back up. - Shutdown(ShardId, u16), - /// Indicates that the client is to send a member chunk message. - ChunkGuild { - /// The IDs of the [`Guild`] to chunk. - /// - /// [`Guild`]: crate::model::guild::Guild - guild_id: GuildId, - /// The maximum number of members to receive [`GuildMembersChunkEvent`]s for. - /// - /// [`GuildMembersChunkEvent`]: crate::model::event::GuildMembersChunkEvent - limit: Option, - /// Used to specify if we want the presences of the matched members. - /// - /// Requires [`crate::model::gateway::GatewayIntents::GUILD_PRESENCES`]. - presences: bool, - /// A filter to apply to the returned members. - filter: ChunkGuildFilter, - /// Optional nonce to identify [`GuildMembersChunkEvent`] responses. - /// - /// [`GuildMembersChunkEvent`]: crate::model::event::GuildMembersChunkEvent - nonce: Option, - }, - /// Indicates that the client is to close with the given status code and reason. - /// - /// You should rarely - if _ever_ - need this, but the option is available. Prefer to use the - /// [`ShardManager`] to shutdown WebSocket clients if you are intending to send a 1000 close - /// code. - /// - /// [`ShardManager`]: super::ShardManager - Close(u16, Option), - /// Indicates that the client is to send a custom WebSocket message. - Message(Message), - /// Indicates that the client is to update the shard's presence's activity. - SetActivity(Option), - /// Indicates that the client is to update the shard's presence in its entirety. - SetPresence(Option, OnlineStatus), - /// Indicates that the client is to update the shard's presence's status. - SetStatus(OnlineStatus), -} diff --git a/src/gateway/client/mod.rs b/src/gateway/client/mod.rs index b38a32656d9..d3f225c36b0 100644 --- a/src/gateway/client/mod.rs +++ b/src/gateway/client/mod.rs @@ -2,7 +2,24 @@ //! events to handlers and starting sharded gateway connections is handled directly by the client. //! In addition, the client automatically handles caching via the [`Cache`] struct. //! +//! # Sharding +//! +//! If you do not require sharding - such as for a small bot - then use [`Client::start`]. If you +//! don't know what sharding is, refer to the [`sharding`] module documentation. +//! +//! There are a few methods of sharding available: +//! - [`Client::start_autosharded`]: retrieves the number of shards Discord recommends using from +//! the API, and then automatically starts that number of shards. +//! - [`Client::start_shard`]: starts a single shard for use in the instance, handled by the +//! instance of the Client. Use this if you only want 1 shard handled by this instance. +//! - [`Client::start_shards`]: starts all shards in this instance. This is best for when you want a +//! completely shared State. +//! - [`Client::start_shard_range`]: start a range of shards within this instance. This should be +//! used when you, for example, want to split 10 shards across 3 instances. +//! //! Click [here][Client#examples] for an example on how to use a [`Client`]. +//! +//! [`sharding`]: crate::gateway::sharding mod context; pub(crate) mod dispatch; @@ -357,7 +374,7 @@ impl IntoFuture for ClientBuilder { /// 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][sharding docs] for more information. +/// using sharding][super::sharding] for more information. /// /// # Event Handlers /// @@ -399,7 +416,6 @@ impl IntoFuture for ClientBuilder { /// /// [`Shard`]: crate::gateway::Shard /// [`Event::MessageCreate`]: crate::model::event::Event::MessageCreate -/// [sharding docs]: crate::gateway#sharding pub struct Client { data: Arc, /// A HashMap of all shards instantiated by the Client. diff --git a/src/gateway/mod.rs b/src/gateway/mod.rs index a3dbc611419..26b4b0cd1ce 100644 --- a/src/gateway/mod.rs +++ b/src/gateway/mod.rs @@ -1,60 +1,30 @@ -//! The gateway module contains the pieces - primarily the `Shard` - responsible for maintaining a -//! WebSocket connection with Discord. +//! Contains the necessary plumping for maintaining a connection with Discord. +//! The primary building blocks are the [`Client`] and the [`Shard`]. //! -//! A shard is an interface for the lower-level receiver and sender. It provides what can otherwise -//! be thought of as "sugar methods". A shard represents a single connection to Discord. You can -//! make use of a method named "sharding" to have multiple shards, potentially offloading some -//! server load to another server(s). +//! The [`Client`] is a high-level interface that takes care of communicating with Discord's REST +//! API as well as receiving and dispatching events from the gateway using a WebSocket client. //! -//! # Sharding -//! -//! Sharding is a method to split portions of bots into separate processes. This is an enforced -//! strategy by Discord once a bot reaches a certain number of guilds (2500). Once this number is -//! reached, a bot must be sharded in a way that only 2500 guilds maximum may be allocated per -//! shard. -//! -//! The "recommended" number of guilds per shard is _around_ 1000. Sharding can be useful for -//! splitting processes across separate servers. Often you may want some or all shards to be in the -//! same process, allowing for a shared State. This is possible through this library. -//! -//! See [Discord's documentation][docs] for more information. -//! -//! If you do not require sharding - such as for a small bot - then use [`Client::start`]. -//! -//! There are a few methods of sharding available: -//! - [`Client::start_autosharded`]: retrieves the number of shards Discord recommends using from -//! the API, and then automatically starts that number of shards. -//! - [`Client::start_shard`]: starts a single shard for use in the instance, handled by the -//! instance of the Client. Use this if you only want 1 shard handled by this instance. -//! - [`Client::start_shards`]: starts all shards in this instance. This is best for when you want a -//! completely shared State. -//! - [`Client::start_shard_range`]: start a range of shards within this instance. This should be -//! used when you, for example, want to split 10 shards across 3 instances. -//! -//! [`Client`]: crate::Client -//! [`Client::start`]: crate::Client::start -//! [`Client::start_autosharded`]: crate::Client::start_autosharded -//! [`Client::start_shard`]: crate::Client::start_shard -//! [`Client::start_shard_range`]: crate::Client::start_shard_range -//! [`Client::start_shards`]: crate::Client::start_shards -//! [docs]: https://discordapp.com/developers/docs/topics/gateway#sharding +//! On the other hand, the [`Shard`] is a low-level receiver and sender representing a single +//! connection to Discord. The client will handle shard management automatically for you, so you +//! should only care about using it directly if you really need to. See the [`sharding`] module for +//! details and documentation. -mod bridge; pub mod client; mod error; -mod shard; +pub mod sharding; +#[cfg(feature = "voice")] +mod voice; mod ws; -use std::fmt; - #[cfg(feature = "http")] use reqwest::IntoUrl; use reqwest::Url; -pub use self::bridge::*; pub use self::client::*; pub use self::error::Error as GatewayError; -pub use self::shard::Shard; +pub use self::sharding::*; +#[cfg(feature = "voice")] +pub use self::voice::VoiceGatewayManager; pub use self::ws::WsClient; use crate::internal::prelude::*; use crate::model::gateway::{Activity, ActivityType}; @@ -169,92 +139,6 @@ impl From for ActivityData { } } -/// Indicates the current connection stage of a [`Shard`]. -/// -/// This can be useful for knowing which shards are currently "down"/"up". -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -#[non_exhaustive] -pub enum ConnectionStage { - /// Indicator that the [`Shard`] is normally connected and is not in, e.g., a resume phase. - Connected, - /// Indicator that the [`Shard`] is connecting and is in, e.g., a resume phase. - Connecting, - /// Indicator that the [`Shard`] is fully disconnected and is not in a reconnecting phase. - Disconnected, - /// Indicator that the [`Shard`] is currently initiating a handshake. - Handshake, - /// Indicator that the [`Shard`] has sent an IDENTIFY packet and is awaiting a READY packet. - Identifying, - /// Indicator that the [`Shard`] has sent a RESUME packet and is awaiting a RESUMED packet. - Resuming, -} - -impl ConnectionStage { - /// Whether the stage is a form of connecting. - /// - /// This will return `true` on: - /// - [`Connecting`][`ConnectionStage::Connecting`] - /// - [`Handshake`][`ConnectionStage::Handshake`] - /// - [`Identifying`][`ConnectionStage::Identifying`] - /// - [`Resuming`][`ConnectionStage::Resuming`] - /// - /// All other variants will return `false`. - /// - /// # Examples - /// - /// Assert that [`ConnectionStage::Identifying`] is a connecting stage: - /// - /// ```rust - /// use serenity::gateway::ConnectionStage; - /// - /// assert!(ConnectionStage::Identifying.is_connecting()); - /// ``` - /// - /// Assert that [`ConnectionStage::Connected`] is _not_ a connecting stage: - /// - /// ```rust - /// use serenity::gateway::ConnectionStage; - /// - /// assert!(!ConnectionStage::Connected.is_connecting()); - /// ``` - #[must_use] - pub fn is_connecting(self) -> bool { - use self::ConnectionStage::{Connecting, Handshake, Identifying, Resuming}; - matches!(self, Connecting | Handshake | Identifying | Resuming) - } -} - -impl fmt::Display for ConnectionStage { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(match *self { - Self::Connected => "connected", - Self::Connecting => "connecting", - Self::Disconnected => "disconnected", - Self::Handshake => "handshaking", - Self::Identifying => "identifying", - Self::Resuming => "resuming", - }) - } -} - -#[derive(Debug)] -#[non_exhaustive] -pub enum ShardAction { - Heartbeat, - Identify, - Reconnect(ReconnectType), -} - -/// The type of reconnection that should be performed. -#[derive(Debug)] -#[non_exhaustive] -pub enum ReconnectType { - /// Indicator that a new connection should be made by sending an IDENTIFY. - Reidentify, - /// Indicator that a new connection should be made by sending a RESUME. - Resume, -} - /// [Discord docs](https://discord.com/developers/docs/topics/gateway-events#request-guild-members). #[derive(Clone, Debug)] pub enum ChunkGuildFilter { diff --git a/src/gateway/shard.rs b/src/gateway/sharding/mod.rs similarity index 79% rename from src/gateway/shard.rs rename to src/gateway/sharding/mod.rs index 69c6cfd13a9..4f5248fa1ea 100644 --- a/src/gateway/shard.rs +++ b/src/gateway/sharding/mod.rs @@ -1,3 +1,44 @@ +//! Sharding is a method for load-balancing bots across separate threads or processes. Sharding is +//! enforced on bots by Discord once they reach a certain number of guilds (2500). Once this +//! threshold is reached, a but must be sharded such that at most 2500 guilds are allocated per +//! shard. +//! +//! The "recommended" number of guilds per shard is _around_ 1000. Sharding allows for bots to be +//! distributed by handing shards off to separate processes or even separate machines in a +//! distributed network (e.g. cloud workers). However, sometimes you may wish for all shards to +//! share some global state. Serenity accomodates both of these usecases. +//! +//! See [Discord's documentation][docs] for more information. +//! +//! This module also provides some lower-level facilities for performing sharding manually: +//! +//! ### [`ShardManager`] +//! +//! The shard manager provides a clean interface for communicating with shard runners either +//! individually or collectively, with functions such as [`ShardManager::shutdown`] and +//! [`ShardManager::restart`] to manage shards in a fine-grained way. +//! +//! For most use cases, the [`ShardManager`] will fit all your low-level sharding needs. +//! +//! ### [`ShardQueuer`] +//! +//! A light wrapper around an mpsc receiver that receives [`ShardQueuerMessage`]s. It should be run +//! in its own thread so it can receive messages to start shards concurrently in a queue. +//! +//! ### [`ShardRunner`] +//! +//! The shard runner is responsible for directly running a single shard and communicating with the +//! gateway through its respective WebSocket client. It performs actions such as identifying, +//! reconnecting, resuming, and sending presence updates to the gateway. +//! +//! [docs]: https://discordapp.com/developers/docs/topics/gateway#sharding + +mod shard_manager; +mod shard_messenger; +mod shard_queuer; +mod shard_runner; + +use std::fmt; use std::sync::Arc; use std::time::{Duration as StdDuration, Instant}; @@ -7,25 +48,20 @@ use tokio_tungstenite::tungstenite::protocol::frame::CloseFrame; use tracing::{debug, error, info, trace, warn}; use url::Url; -use super::{ - ActivityData, - ChunkGuildFilter, - ConnectionStage, - GatewayError, - PresenceData, - ReconnectType, - ShardAction, - WsClient, -}; +pub use self::shard_manager::{ShardManager, ShardManagerOptions}; +pub use self::shard_messenger::ShardMessenger; +pub use self::shard_queuer::{ShardQueue, ShardQueuer, ShardQueuerMessage}; +pub use self::shard_runner::{ShardRunner, ShardRunnerMessage, ShardRunnerOptions}; +use super::{ActivityData, ChunkGuildFilter, GatewayError, PresenceData, WsClient}; use crate::constants::{self, close_codes}; use crate::http::Token; use crate::internal::prelude::*; use crate::model::event::{Event, GatewayEvent}; use crate::model::gateway::{GatewayIntents, ShardInfo}; -use crate::model::id::{ApplicationId, GuildId}; +use crate::model::id::{ApplicationId, GuildId, ShardId}; use crate::model::user::OnlineStatus; -/// A Shard is a higher-level handler for a websocket connection to Discord's gateway. The shard +/// A Shard is an abstract handler for a websocket connection to Discord's gateway. The shard /// allows for sending and receiving messages over the websocket, such as setting the active /// activity, reconnecting, syncing guilds, and more. /// @@ -33,15 +69,13 @@ use crate::model::user::OnlineStatus; /// multiple shards, if you need to. /// /// Note that there are additional methods available if you are manually managing a shard yourself, -/// although they are hidden from the documentation since there are few use cases for doing such. +/// although they are hidden from the documentation since there are few use cases for doing so. /// /// # Stand-alone shards /// -/// You may instantiate a shard yourself - decoupled from the [`Client`] - if you need to. For most -/// use cases, you will not need to do this, and you can leave the client to do it. -/// -/// This can be done by passing in the required parameters to [`Self::new`]. You can then manually -/// handle the shard yourself. +/// You may instantiate a shard yourself - decoupled from the [`Client`] - by calling +/// [`Shard::new`]. Most use cases will not necessitate this, and unless you're doing something +/// really weird you can just let the client do it for you. /// /// **Note**: You _really_ do not need to do this. Just call one of the appropriate methods on the /// [`Client`]. @@ -778,3 +812,141 @@ async fn connect(base_url: &str) -> Result { WsClient::connect(url).await } + +#[derive(Debug)] +#[non_exhaustive] +pub enum ShardAction { + Heartbeat, + Identify, + Reconnect(ReconnectType), +} + +/// Information about a [`ShardRunner`]. +/// +/// The [`ShardId`] is not included because, as it stands, you probably already know the Id if you +/// obtained this. +#[derive(Debug)] +pub struct ShardRunnerInfo { + /// The latency between when a heartbeat was sent and when the acknowledgement was received. + pub latency: Option, + /// The channel used to communicate with the shard runner, telling it what to do with regards + /// to its status. + pub runner_tx: ShardMessenger, + /// The current connection stage of the shard. + pub stage: ConnectionStage, +} + +/// An event denoting that a shard's connection stage was changed. +/// +/// # Examples +/// +/// This might happen when a shard changes from [`ConnectionStage::Identifying`] to +/// [`ConnectionStage::Connected`]. +#[derive(Clone, Debug)] +pub struct ShardStageUpdateEvent { + /// The new connection stage. + pub new: ConnectionStage, + /// The old connection stage. + pub old: ConnectionStage, + /// The ID of the shard that had its connection stage change. + pub shard_id: ShardId, +} + +/// Indicates the current connection stage of a [`Shard`]. +/// +/// This can be useful for knowing which shards are currently "down"/"up". +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[non_exhaustive] +pub enum ConnectionStage { + /// Indicator that the [`Shard`] is normally connected and is not in, e.g., a resume phase. + Connected, + /// Indicator that the [`Shard`] is connecting and is in, e.g., a resume phase. + Connecting, + /// Indicator that the [`Shard`] is fully disconnected and is not in a reconnecting phase. + Disconnected, + /// Indicator that the [`Shard`] is currently initiating a handshake. + Handshake, + /// Indicator that the [`Shard`] has sent an IDENTIFY packet and is awaiting a READY packet. + Identifying, + /// Indicator that the [`Shard`] has sent a RESUME packet and is awaiting a RESUMED packet. + Resuming, +} + +impl ConnectionStage { + /// Whether the stage is a form of connecting. + /// + /// This will return `true` on: + /// - [`Connecting`][`ConnectionStage::Connecting`] + /// - [`Handshake`][`ConnectionStage::Handshake`] + /// - [`Identifying`][`ConnectionStage::Identifying`] + /// - [`Resuming`][`ConnectionStage::Resuming`] + /// + /// All other variants will return `false`. + /// + /// # Examples + /// + /// Assert that [`ConnectionStage::Identifying`] is a connecting stage: + /// + /// ```rust + /// use serenity::gateway::ConnectionStage; + /// + /// assert!(ConnectionStage::Identifying.is_connecting()); + /// ``` + /// + /// Assert that [`ConnectionStage::Connected`] is _not_ a connecting stage: + /// + /// ```rust + /// use serenity::gateway::ConnectionStage; + /// + /// assert!(!ConnectionStage::Connected.is_connecting()); + /// ``` + #[must_use] + pub fn is_connecting(self) -> bool { + use self::ConnectionStage::{Connecting, Handshake, Identifying, Resuming}; + matches!(self, Connecting | Handshake | Identifying | Resuming) + } +} + +impl fmt::Display for ConnectionStage { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match *self { + Self::Connected => "connected", + Self::Connecting => "connecting", + Self::Disconnected => "disconnected", + Self::Handshake => "handshaking", + Self::Identifying => "identifying", + Self::Resuming => "resuming", + }) + } +} + +/// The type of reconnection that should be performed. +#[derive(Debug)] +#[non_exhaustive] +pub enum ReconnectType { + /// Indicator that a new connection should be made by sending an IDENTIFY. + Reidentify, + /// Indicator that a new connection should be made by sending a RESUME. + Resume, +} + +/// Newtype around a callback that will be called on every incoming request. As long as this +/// collector should still receive events, it should return `true`. Once it returns `false`, it is +/// removed. +#[cfg(feature = "collector")] +#[derive(Clone)] +pub struct CollectorCallback(pub Arc bool + Send + Sync>); + +#[cfg(feature = "collector")] +impl fmt::Debug for CollectorCallback { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("CollectorCallback").finish() + } +} + +#[cfg(feature = "collector")] +impl PartialEq for CollectorCallback { + fn eq(&self, other: &Self) -> bool { + Arc::ptr_eq(&self.0, &other.0) + } +} diff --git a/src/gateway/bridge/shard_manager.rs b/src/gateway/sharding/shard_manager.rs similarity index 99% rename from src/gateway/bridge/shard_manager.rs rename to src/gateway/sharding/shard_manager.rs index 80e3c5eb368..413f886f34a 100644 --- a/src/gateway/bridge/shard_manager.rs +++ b/src/gateway/sharding/shard_manager.rs @@ -11,13 +11,13 @@ use tokio::sync::Mutex; use tokio::time::timeout; use tracing::{info, warn}; -#[cfg(feature = "voice")] -use super::VoiceGatewayManager; use super::{ShardId, ShardQueue, ShardQueuer, ShardQueuerMessage, ShardRunnerInfo}; #[cfg(feature = "cache")] use crate::cache::Cache; #[cfg(feature = "framework")] use crate::framework::Framework; +#[cfg(feature = "voice")] +use crate::gateway::VoiceGatewayManager; use crate::gateway::{ConnectionStage, GatewayError, InternalEventHandler, PresenceData}; use crate::http::Http; use crate::internal::prelude::*; diff --git a/src/gateway/bridge/shard_messenger.rs b/src/gateway/sharding/shard_messenger.rs similarity index 100% rename from src/gateway/bridge/shard_messenger.rs rename to src/gateway/sharding/shard_messenger.rs diff --git a/src/gateway/bridge/shard_queuer.rs b/src/gateway/sharding/shard_queuer.rs similarity index 96% rename from src/gateway/bridge/shard_queuer.rs rename to src/gateway/sharding/shard_queuer.rs index 054ec0d86c2..a68a934a98c 100644 --- a/src/gateway/bridge/shard_queuer.rs +++ b/src/gateway/sharding/shard_queuer.rs @@ -10,13 +10,10 @@ use tokio::sync::Mutex; use tokio::time::{sleep, timeout, Duration, Instant}; use tracing::{debug, info, warn}; -#[cfg(feature = "voice")] -use super::VoiceGatewayManager; use super::{ ShardId, ShardManager, ShardMessenger, - ShardQueuerMessage, ShardRunner, ShardRunnerInfo, ShardRunnerOptions, @@ -25,6 +22,8 @@ use super::{ use crate::cache::Cache; #[cfg(feature = "framework")] use crate::framework::Framework; +#[cfg(feature = "voice")] +use crate::gateway::VoiceGatewayManager; use crate::gateway::{ ConnectionStage, InternalEventHandler, @@ -342,3 +341,16 @@ impl ShardQueue { self.buckets.iter().all(|b| !b.is_empty()) } } + +/// A message to be sent to the [`ShardQueuer`]. +#[derive(Clone, Debug)] +pub enum ShardQueuerMessage { + /// Message to set the shard total. + SetShardTotal(NonZeroU16), + /// Message to start a shard. + Start { shard_id: ShardId, concurrent: bool }, + /// Message to shutdown the shard queuer. + Shutdown, + /// Message to dequeue/shutdown a shard. + ShutdownShard { shard_id: ShardId, code: u16 }, +} diff --git a/src/gateway/bridge/shard_runner.rs b/src/gateway/sharding/shard_runner.rs similarity index 89% rename from src/gateway/bridge/shard_runner.rs rename to src/gateway/sharding/shard_runner.rs index f0dbaabaa89..e8599352f1e 100644 --- a/src/gateway/bridge/shard_runner.rs +++ b/src/gateway/sharding/shard_runner.rs @@ -5,31 +5,26 @@ use futures::channel::mpsc::{self, UnboundedReceiver as Receiver, UnboundedSende use tokio_tungstenite::tungstenite; use tokio_tungstenite::tungstenite::error::Error as TungsteniteError; use tokio_tungstenite::tungstenite::protocol::frame::CloseFrame; +use tokio_tungstenite::tungstenite::Message; use tracing::{debug, error, info, trace, warn}; -use super::event::ShardStageUpdateEvent; #[cfg(feature = "collector")] use super::CollectorCallback; -#[cfg(feature = "voice")] -use super::VoiceGatewayManager; -use super::{ShardId, ShardManager, ShardRunnerMessage}; +use super::{ReconnectType, Shard, ShardAction, ShardId, ShardManager, ShardStageUpdateEvent}; #[cfg(feature = "cache")] use crate::cache::Cache; #[cfg(feature = "framework")] use crate::framework::Framework; use crate::gateway::dispatch::dispatch_model; -use crate::gateway::{ - Context, - GatewayError, - InternalEventHandler, - ReconnectType, - Shard, - ShardAction, -}; +#[cfg(feature = "voice")] +use crate::gateway::VoiceGatewayManager; +use crate::gateway::{ActivityData, ChunkGuildFilter, Context, GatewayError, InternalEventHandler}; use crate::http::Http; use crate::internal::prelude::*; use crate::internal::tokio::spawn_named; use crate::model::event::{Event, GatewayEvent}; +use crate::model::id::GuildId; +use crate::model::user::OnlineStatus; /// A runner for managing a [`Shard`] and its respective WebSocket client. pub struct ShardRunner { @@ -524,3 +519,50 @@ pub struct ShardRunnerOptions { pub cache: Arc, pub http: Arc, } + +/// A message to send from a shard over a WebSocket. +#[derive(Debug)] +pub enum ShardRunnerMessage { + /// Indicator that a shard should be restarted. + Restart(ShardId), + /// Indicator that a shard should be fully shutdown without bringing it + /// back up. + Shutdown(ShardId, u16), + /// Indicates that the client is to send a member chunk message. + ChunkGuild { + /// The IDs of the [`Guild`] to chunk. + /// + /// [`Guild`]: crate::model::guild::Guild + guild_id: GuildId, + /// The maximum number of members to receive [`GuildMembersChunkEvent`]s for. + /// + /// [`GuildMembersChunkEvent`]: crate::model::event::GuildMembersChunkEvent + limit: Option, + /// Used to specify if we want the presences of the matched members. + /// + /// Requires [`crate::model::gateway::GatewayIntents::GUILD_PRESENCES`]. + presences: bool, + /// A filter to apply to the returned members. + filter: ChunkGuildFilter, + /// Optional nonce to identify [`GuildMembersChunkEvent`] responses. + /// + /// [`GuildMembersChunkEvent`]: crate::model::event::GuildMembersChunkEvent + nonce: Option, + }, + /// Indicates that the client is to close with the given status code and reason. + /// + /// You should rarely - if _ever_ - need this, but the option is available. Prefer to use the + /// [`ShardManager`] to shutdown WebSocket clients if you are intending to send a 1000 close + /// code. + /// + /// [`ShardManager`]: super::ShardManager + Close(u16, Option), + /// Indicates that the client is to send a custom WebSocket message. + Message(Message), + /// Indicates that the client is to update the shard's presence's activity. + SetActivity(Option), + /// Indicates that the client is to update the shard's presence in its entirety. + SetPresence(Option, OnlineStatus), + /// Indicates that the client is to update the shard's presence's status. + SetStatus(OnlineStatus), +} diff --git a/src/gateway/bridge/voice.rs b/src/gateway/voice.rs similarity index 100% rename from src/gateway/bridge/voice.rs rename to src/gateway/voice.rs From 8b1fa5881cc8833ffe27ef0e5c312b174247e503 Mon Sep 17 00:00:00 2001 From: Michael Krasnitski Date: Tue, 20 Aug 2024 15:56:07 -0400 Subject: [PATCH 3/3] Don't re-export out of `gateway::client` submodule --- src/cache/mod.rs | 4 +-- src/framework/mod.rs | 6 ++-- src/gateway/client/event_handler.rs | 2 +- src/gateway/mod.rs | 3 +- src/gateway/sharding/shard_manager.rs | 12 +++----- src/gateway/sharding/shard_queuer.rs | 13 +++----- src/gateway/sharding/shard_runner.rs | 5 ++-- src/http/client.rs | 4 +-- src/http/mod.rs | 2 +- src/lib.rs | 8 ++--- src/model/application/command.rs | 2 +- src/model/application/command_interaction.rs | 2 +- .../application/component_interaction.rs | 2 +- src/model/event.rs | 30 +++++++++---------- src/prelude.rs | 4 ++- src/utils/quick_modal.rs | 2 +- 16 files changed, 48 insertions(+), 53 deletions(-) diff --git a/src/cache/mod.rs b/src/cache/mod.rs index ca409faddba..8ae6e1f6259 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -318,7 +318,7 @@ impl Cache { /// } /// ``` /// - /// [`Context`]: crate::gateway::Context + /// [`Context`]: crate::gateway::client::Context /// [`Shard`]: crate::gateway::Shard pub fn guilds(&self) -> Vec { let unavailable_guilds = self.unavailable_guilds(); @@ -404,7 +404,7 @@ impl Cache { /// # } /// ``` /// - /// [`EventHandler::message`]: crate::gateway::EventHandler::message + /// [`EventHandler::message`]: crate::gateway::client::EventHandler::message pub fn message(&self, channel_id: ChannelId, message_id: MessageId) -> Option> { #[cfg(feature = "temp_cache")] if let Some(message) = self.temp_messages.get(&message_id) { diff --git a/src/framework/mod.rs b/src/framework/mod.rs index afbe140a1a3..38914709698 100644 --- a/src/framework/mod.rs +++ b/src/framework/mod.rs @@ -2,18 +2,18 @@ //! //! This is used in combination with [`ClientBuilder::framework`]. //! -//! [`ClientBuilder::framework`]: crate::gateway::ClientBuilder::framework +//! [`ClientBuilder::framework`]: crate::gateway::client::ClientBuilder::framework use async_trait::async_trait; -use crate::gateway::{Client, Context, FullEvent}; +use crate::gateway::client::{Client, Context, FullEvent}; /// A trait for defining your own framework for serenity to use. /// /// Should you implement this trait, or define a `message` handler, depends on you. However, using /// this will benefit you by abstracting the [`EventHandler`] away. /// -/// [`EventHandler`]: crate::gateway::EventHandler +/// [`EventHandler`]: crate::gateway::client::EventHandler #[async_trait] pub trait Framework: Send + Sync { /// Called directly after the `Client` is created. diff --git a/src/gateway/client/event_handler.rs b/src/gateway/client/event_handler.rs index 3330ef1135f..1e39d8be1ea 100644 --- a/src/gateway/client/event_handler.rs +++ b/src/gateway/client/event_handler.rs @@ -71,7 +71,7 @@ macro_rules! event_handler { /// Returns the name of this event as a snake case string /// /// ```rust,no_run - /// # use serenity::gateway::{Context, FullEvent}; + /// # use serenity::gateway::client::{Context, FullEvent}; /// # fn _foo(ctx: Context, event: FullEvent) { /// if let FullEvent::Message { .. } = &event { /// assert_eq!(event.snake_case_name(), "message"); diff --git a/src/gateway/mod.rs b/src/gateway/mod.rs index 26b4b0cd1ce..3bf106bc3fc 100644 --- a/src/gateway/mod.rs +++ b/src/gateway/mod.rs @@ -8,6 +8,8 @@ //! connection to Discord. The client will handle shard management automatically for you, so you //! should only care about using it directly if you really need to. See the [`sharding`] module for //! details and documentation. +//! +//! [`Client`]: client::Client pub mod client; mod error; @@ -20,7 +22,6 @@ mod ws; use reqwest::IntoUrl; use reqwest::Url; -pub use self::client::*; pub use self::error::Error as GatewayError; pub use self::sharding::*; #[cfg(feature = "voice")] diff --git a/src/gateway/sharding/shard_manager.rs b/src/gateway/sharding/shard_manager.rs index 413f886f34a..5bdfd07ef90 100644 --- a/src/gateway/sharding/shard_manager.rs +++ b/src/gateway/sharding/shard_manager.rs @@ -16,9 +16,10 @@ use super::{ShardId, ShardQueue, ShardQueuer, ShardQueuerMessage, ShardRunnerInf use crate::cache::Cache; #[cfg(feature = "framework")] use crate::framework::Framework; +use crate::gateway::client::InternalEventHandler; #[cfg(feature = "voice")] use crate::gateway::VoiceGatewayManager; -use crate::gateway::{ConnectionStage, GatewayError, InternalEventHandler, PresenceData}; +use crate::gateway::{ConnectionStage, GatewayError, PresenceData}; use crate::http::Http; use crate::internal::prelude::*; use crate::internal::tokio::spawn_named; @@ -48,13 +49,8 @@ use crate::model::gateway::GatewayIntents; /// use std::env; /// use std::sync::{Arc, OnceLock}; /// -/// use serenity::gateway::{ -/// EventHandler, -/// InternalEventHandler, -/// RawEventHandler, -/// ShardManager, -/// ShardManagerOptions, -/// }; +/// use serenity::gateway::client::{EventHandler, InternalEventHandler, RawEventHandler}; +/// use serenity::gateway::{ShardManager, ShardManagerOptions}; /// use serenity::http::Http; /// use serenity::model::gateway::GatewayIntents; /// use serenity::prelude::*; diff --git a/src/gateway/sharding/shard_queuer.rs b/src/gateway/sharding/shard_queuer.rs index a68a934a98c..dc9a4802fba 100644 --- a/src/gateway/sharding/shard_queuer.rs +++ b/src/gateway/sharding/shard_queuer.rs @@ -22,15 +22,10 @@ use super::{ use crate::cache::Cache; #[cfg(feature = "framework")] use crate::framework::Framework; +use crate::gateway::client::InternalEventHandler; #[cfg(feature = "voice")] use crate::gateway::VoiceGatewayManager; -use crate::gateway::{ - ConnectionStage, - InternalEventHandler, - PresenceData, - Shard, - ShardRunnerMessage, -}; +use crate::gateway::{ConnectionStage, PresenceData, Shard, ShardRunnerMessage}; use crate::http::Http; use crate::internal::prelude::*; use crate::internal::tokio::spawn_named; @@ -49,8 +44,8 @@ pub struct ShardQueuer { pub data: Arc, /// A reference to [`EventHandler`] or [`RawEventHandler`]. /// - /// [`EventHandler`]: crate::gateway::EventHandler - /// [`RawEventHandler`]: crate::gateway::RawEventHandler + /// [`EventHandler`]: crate::gateway::client::EventHandler + /// [`RawEventHandler`]: crate::gateway::client::RawEventHandler pub event_handler: Option, /// A copy of the framework #[cfg(feature = "framework")] diff --git a/src/gateway/sharding/shard_runner.rs b/src/gateway/sharding/shard_runner.rs index e8599352f1e..fd7277e196f 100644 --- a/src/gateway/sharding/shard_runner.rs +++ b/src/gateway/sharding/shard_runner.rs @@ -15,10 +15,11 @@ use super::{ReconnectType, Shard, ShardAction, ShardId, ShardManager, ShardStage use crate::cache::Cache; #[cfg(feature = "framework")] use crate::framework::Framework; -use crate::gateway::dispatch::dispatch_model; +use crate::gateway::client::dispatch::dispatch_model; +use crate::gateway::client::{Context, InternalEventHandler}; #[cfg(feature = "voice")] use crate::gateway::VoiceGatewayManager; -use crate::gateway::{ActivityData, ChunkGuildFilter, Context, GatewayError, InternalEventHandler}; +use crate::gateway::{ActivityData, ChunkGuildFilter, GatewayError}; use crate::http::Http; use crate::internal::prelude::*; use crate::internal::tokio::spawn_named; diff --git a/src/http/client.rs b/src/http/client.rs index 710a9d7e46d..248b9b11fd1 100644 --- a/src/http/client.rs +++ b/src/http/client.rs @@ -530,7 +530,7 @@ impl Http { /// /// See [`Context::create_application_emoji`] for required fields. /// - /// [`Context::create_application_emoji`]: crate::gateway::Context::create_application_emoji + /// [`Context::create_application_emoji`]: crate::gateway::client::Context::create_application_emoji pub async fn create_application_emoji(&self, map: &impl serde::Serialize) -> Result { self.fire(Request { body: Some(to_vec(map)?), @@ -1506,7 +1506,7 @@ impl Http { /// /// See [`Context::edit_application_emoji`] for required fields. /// - /// [`Context::edit_application_emoji`]: crate::gateway::Context::edit_application_emoji + /// [`Context::edit_application_emoji`]: crate::gateway::client::Context::edit_application_emoji pub async fn edit_application_emoji( &self, emoji_id: EmojiId, diff --git a/src/http/mod.rs b/src/http/mod.rs index 28838c75d3d..ec3d6952f46 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs @@ -42,7 +42,7 @@ pub use self::typing::*; #[cfg(feature = "cache")] use crate::cache::Cache; #[cfg(feature = "gateway")] -use crate::gateway::Context; +use crate::gateway::client::Context; use crate::model::prelude::*; /// This trait will be required by functions that need [`Http`] and can optionally use a [`Cache`] diff --git a/src/lib.rs b/src/lib.rs index 3db5d4f5a6a..511f03afdfe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,8 +37,8 @@ //! ``` //! //! [`Cache`]: crate::cache::Cache -//! [`Context`]: crate::gateway::Context -//! [`EventHandler::message`]: crate::gateway::EventHandler::message +//! [`Context`]: crate::gateway::client::Context +//! [`EventHandler::message`]: crate::gateway::client::EventHandler::message //! [`Event`]: crate::model::event::Event //! [`Event::MessageCreate`]: crate::model::event::Event::MessageCreate //! [`Shard`]: crate::gateway::Shard @@ -108,7 +108,7 @@ mod error; pub use crate::error::{Error, Result}; #[cfg(feature = "gateway")] -pub use crate::gateway::Client; +pub use crate::gateway::client::Client; /// Special module that re-exports most public items from this crate. /// @@ -130,7 +130,7 @@ pub mod all { pub use crate::framework::*; #[cfg(feature = "gateway")] #[doc(no_inline)] - pub use crate::gateway::*; + pub use crate::gateway::{client::*, *}; #[cfg(feature = "http")] #[doc(no_inline)] pub use crate::http::*; diff --git a/src/model/application/command.rs b/src/model/application/command.rs index 5832e9747a6..42d5b13c75f 100644 --- a/src/model/application/command.rs +++ b/src/model/application/command.rs @@ -153,7 +153,7 @@ impl Command { /// /// See [`CreateCommand::execute`] for a list of possible errors. /// - /// [`InteractionCreate`]: crate::gateway::EventHandler::interaction_create + /// [`InteractionCreate`]: crate::gateway::client::EventHandler::interaction_create pub async fn create_global_command(http: &Http, builder: CreateCommand<'_>) -> Result { builder.execute(http, None, None).await } diff --git a/src/model/application/command_interaction.rs b/src/model/application/command_interaction.rs index 77db8ef55f7..8b0d0c2ea83 100644 --- a/src/model/application/command_interaction.rs +++ b/src/model/application/command_interaction.rs @@ -14,7 +14,7 @@ use crate::builder::{ EditInteractionResponse, }; #[cfg(feature = "collector")] -use crate::gateway::Context; +use crate::gateway::client::Context; #[cfg(feature = "model")] use crate::http::Http; use crate::internal::prelude::*; diff --git a/src/model/application/component_interaction.rs b/src/model/application/component_interaction.rs index b086c02007a..01cd875ec7c 100644 --- a/src/model/application/component_interaction.rs +++ b/src/model/application/component_interaction.rs @@ -10,7 +10,7 @@ use crate::builder::{ EditInteractionResponse, }; #[cfg(feature = "collector")] -use crate::gateway::Context; +use crate::gateway::client::Context; #[cfg(feature = "model")] use crate::http::Http; use crate::internal::prelude::*; diff --git a/src/model/event.rs b/src/model/event.rs index a3510c730f6..82c4bc078c1 100644 --- a/src/model/event.rs +++ b/src/model/event.rs @@ -1139,7 +1139,7 @@ pub enum Event { /// Fires the [`EventHandler::command_permissions_update`] event. /// /// [`Command`]: crate::model::application::Command - /// [`EventHandler::command_permissions_update`]: crate::gateway::EventHandler::command_permissions_update + /// [`EventHandler::command_permissions_update`]: crate::gateway::client::EventHandler::command_permissions_update #[serde(rename = "APPLICATION_COMMAND_PERMISSIONS_UPDATE")] CommandPermissionsUpdate(CommandPermissionsUpdateEvent), /// A [`Rule`] was created. @@ -1147,7 +1147,7 @@ pub enum Event { /// Fires the [`EventHandler::auto_moderation_rule_create`] event. /// /// [`EventHandler::auto_moderation_rule_create`]: - /// crate::gateway::EventHandler::auto_moderation_rule_create + /// crate::gateway::client::EventHandler::auto_moderation_rule_create #[serde(rename = "AUTO_MODERATION_RULE_CREATE")] AutoModRuleCreate(AutoModRuleCreateEvent), /// A [`Rule`] has been updated. @@ -1155,7 +1155,7 @@ pub enum Event { /// Fires the [`EventHandler::auto_moderation_rule_update`] event. /// /// [`EventHandler::auto_moderation_rule_update`]: - /// crate::gateway::EventHandler::auto_moderation_rule_update + /// crate::gateway::client::EventHandler::auto_moderation_rule_update #[serde(rename = "AUTO_MODERATION_RULE_UPDATE")] AutoModRuleUpdate(AutoModRuleUpdateEvent), /// A [`Rule`] was deleted. @@ -1163,7 +1163,7 @@ pub enum Event { /// Fires the [`EventHandler::auto_moderation_rule_delete`] event. /// /// [`EventHandler::auto_moderation_rule_delete`]: - /// crate::gateway::EventHandler::auto_moderation_rule_delete + /// crate::gateway::client::EventHandler::auto_moderation_rule_delete #[serde(rename = "AUTO_MODERATION_RULE_DELETE")] AutoModRuleDelete(AutoModRuleDeleteEvent), /// A [`Rule`] was triggered and an action was executed. @@ -1171,32 +1171,32 @@ pub enum Event { /// Fires the [`EventHandler::auto_moderation_action_execution`] event. /// /// [`EventHandler::auto_moderation_action_execution`]: - /// crate::gateway::EventHandler::auto_moderation_action_execution + /// crate::gateway::client::EventHandler::auto_moderation_action_execution #[serde(rename = "AUTO_MODERATION_ACTION_EXECUTION")] AutoModActionExecution(AutoModActionExecutionEvent), /// A [`Channel`] was created. /// /// Fires the [`EventHandler::channel_create`] event. /// - /// [`EventHandler::channel_create`]: crate::gateway::EventHandler::channel_create + /// [`EventHandler::channel_create`]: crate::gateway::client::EventHandler::channel_create ChannelCreate(ChannelCreateEvent), /// A [`Channel`] has been deleted. /// /// Fires the [`EventHandler::channel_delete`] event. /// - /// [`EventHandler::channel_delete`]: crate::gateway::EventHandler::channel_delete + /// [`EventHandler::channel_delete`]: crate::gateway::client::EventHandler::channel_delete ChannelDelete(ChannelDeleteEvent), /// The pins for a [`Channel`] have been updated. /// /// Fires the [`EventHandler::channel_pins_update`] event. /// - /// [`EventHandler::channel_pins_update`]: crate::gateway::EventHandler::channel_pins_update + /// [`EventHandler::channel_pins_update`]: crate::gateway::client::EventHandler::channel_pins_update ChannelPinsUpdate(ChannelPinsUpdateEvent), /// A [`Channel`] has been updated. /// /// Fires the [`EventHandler::channel_update`] event. /// - /// [`EventHandler::channel_update`]: crate::gateway::EventHandler::channel_update + /// [`EventHandler::channel_update`]: crate::gateway::client::EventHandler::channel_update ChannelUpdate(ChannelUpdateEvent), GuildAuditLogEntryCreate(GuildAuditLogEntryCreateEvent), GuildBanAdd(GuildBanAddEvent), @@ -1220,13 +1220,13 @@ pub enum Event { /// /// Fires the [`EventHandler::invite_create`] event handler. /// - /// [`EventHandler::invite_create`]: crate::gateway::EventHandler::invite_create + /// [`EventHandler::invite_create`]: crate::gateway::client::EventHandler::invite_create InviteCreate(InviteCreateEvent), /// An [`Invite`] was deleted. /// /// Fires the [`EventHandler::invite_delete`] event handler. /// - /// [`EventHandler::invite_delete`]: crate::gateway::EventHandler::invite_delete + /// [`EventHandler::invite_delete`]: crate::gateway::client::EventHandler::invite_delete InviteDelete(InviteDeleteEvent), MessageCreate(MessageCreateEvent), MessageDelete(MessageDeleteEvent), @@ -1239,28 +1239,28 @@ pub enum Event { /// /// Fires the [`EventHandler::reaction_add`] event handler. /// - /// [`EventHandler::reaction_add`]: crate::gateway::EventHandler::reaction_add + /// [`EventHandler::reaction_add`]: crate::gateway::client::EventHandler::reaction_add #[serde(rename = "MESSAGE_REACTION_ADD")] ReactionAdd(ReactionAddEvent), /// A reaction was removed to a message. /// /// Fires the [`EventHandler::reaction_remove`] event handler. /// - /// [`EventHandler::reaction_remove`]: crate::gateway::EventHandler::reaction_remove + /// [`EventHandler::reaction_remove`]: crate::gateway::client::EventHandler::reaction_remove #[serde(rename = "MESSAGE_REACTION_REMOVE")] ReactionRemove(ReactionRemoveEvent), /// A request was issued to remove all [`Reaction`]s from a [`Message`]. /// /// Fires the [`EventHandler::reaction_remove_all`] event handler. /// - /// [`EventHandler::reaction_remove_all`]: crate::gateway::EventHandler::reaction_remove_all + /// [`EventHandler::reaction_remove_all`]: crate::gateway::client::EventHandler::reaction_remove_all #[serde(rename = "MESSAGE_REACTION_REMOVE_ALL")] ReactionRemoveAll(ReactionRemoveAllEvent), /// Sent when a bot removes all instances of a given emoji from the reactions of a message. /// /// Fires the [`EventHandler::reaction_remove_emoji`] event handler. /// - /// [`EventHandler::reaction_remove_emoji`]: crate::gateway::EventHandler::reaction_remove_emoji + /// [`EventHandler::reaction_remove_emoji`]: crate::gateway::client::EventHandler::reaction_remove_emoji #[serde(rename = "MESSAGE_REACTION_REMOVE_EMOJI")] ReactionRemoveEmoji(ReactionRemoveEmojiEvent), /// The first event in a connection, containing the initial ready cache. diff --git a/src/prelude.rs b/src/prelude.rs index 3d8e72730b9..c8811c5748b 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -17,7 +17,9 @@ pub use tokio::sync::{Mutex, RwLock}; pub use crate::error::Error as SerenityError; #[cfg(feature = "gateway")] -pub use crate::gateway::{Client, Context, EventHandler, GatewayError, RawEventHandler}; +pub use crate::gateway::client::{Client, Context, EventHandler, RawEventHandler}; +#[cfg(feature = "gateway")] +pub use crate::gateway::GatewayError; #[cfg(feature = "http")] pub use crate::http::CacheHttp; #[cfg(feature = "http")] diff --git a/src/utils/quick_modal.rs b/src/utils/quick_modal.rs index da581fe6dea..e73612f8fda 100644 --- a/src/utils/quick_modal.rs +++ b/src/utils/quick_modal.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use crate::builder::{CreateActionRow, CreateInputText, CreateInteractionResponse, CreateModal}; use crate::collector::ModalInteractionCollector; -use crate::gateway::Context; +use crate::gateway::client::Context; use crate::internal::prelude::*; use crate::model::prelude::*;