From 73c81c19b3268e2afc667f1c662fbe23e6e24f52 Mon Sep 17 00:00:00 2001 From: Tim Vilgot Mikael Fredenberg <26655508+vilgotf@users.noreply.github.com> Date: Sat, 28 Jan 2023 07:59:20 +0100 Subject: [PATCH 1/6] ci: update all checkout steps to v3 --- .github/workflows/check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 93d9a21f154..59c529b5d62 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -205,7 +205,7 @@ jobs: steps: - name: Checkout sources - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Install stable toolchain uses: dtolnay/rust-toolchain@stable From ca6e0c4b364d9aedfe1486ac9ea1420037fdb4c0 Mon Sep 17 00:00:00 2001 From: Tim Vilgot Mikael Fredenberg <26655508+vilgotf@users.noreply.github.com> Date: Sat, 28 Jan 2023 08:22:33 +0100 Subject: [PATCH 2/6] refactor(gateway)!: remove create_* set of functions --- README.md | 9 +- .../src/chapter_1_crates/section_3_gateway.md | 6 +- .../section_4_cache_inmemory.md | 5 +- .../section_3_lavalink.md | 6 +- book/src/overview.md | 6 +- examples/gateway-intents.rs | 5 +- examples/gateway-parallel.rs | 45 +-- examples/gateway-request-members.rs | 11 +- examples/gateway-reshard.rs | 36 +- examples/gateway-shard.rs | 5 +- examples/lavalink-basic-bot.rs | 5 +- twilight-cache-inmemory/README.md | 5 +- twilight-gateway/Cargo.toml | 4 +- twilight-gateway/README.md | 38 +- twilight-gateway/src/config.rs | 10 +- twilight-gateway/src/connection.rs | 4 +- twilight-gateway/src/inflater.rs | 4 +- twilight-gateway/src/shard.rs | 78 +--- twilight-gateway/src/stream.rs | 361 +----------------- twilight-lavalink/README.md | 5 +- twilight-standby/README.md | 7 +- 21 files changed, 104 insertions(+), 551 deletions(-) diff --git a/README.md b/README.md index bc5f438fa56..2d6581c2f86 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,7 @@ bot's token. You must also depend on `futures`, `tokio`, ```rust,no_run use std::{env, error::Error, sync::Arc}; use twilight_cache_inmemory::{InMemoryCache, ResourceType}; -use twilight_gateway::{Event, Shard, ShardId}; +use twilight_gateway::{Config, Event, Shard, ShardId}; use twilight_http::Client as HttpClient; use twilight_model::gateway::Intents; @@ -133,11 +133,8 @@ async fn main() -> anyhow::Result<()> { let token = env::var("DISCORD_TOKEN")?; // Use intents to only receive guild message events. - let mut shard = Shard::new( - ShardId::ONE, - token.clone(), - Intents::GUILD_MESSAGES | Intents::MESSAGE_CONTENT, - ); + let config = Config::new(token, Intents::GUILD_MESSAGES | Intents::MESSAGE_CONTENT); + let mut shard = Shard::new(ShardId::ONE, config); // HTTP is separate from the gateway, so create a new client. let http = Arc::new(HttpClient::new(token)); diff --git a/book/src/chapter_1_crates/section_3_gateway.md b/book/src/chapter_1_crates/section_3_gateway.md index 76e7d626841..f89ddeb1554 100644 --- a/book/src/chapter_1_crates/section_3_gateway.md +++ b/book/src/chapter_1_crates/section_3_gateway.md @@ -89,7 +89,7 @@ Starting a `Shard` and printing the contents of new messages as they come in: ```rust,no_run use std::{env, error::Error}; -use twilight_gateway::{Intents, Shard, ShardId}; +use twilight_gateway::{Config, Intents, Shard, ShardId}; #[tokio::main] async fn main() -> Result<(), Box> { @@ -97,8 +97,8 @@ async fn main() -> Result<(), Box> { tracing_subscriber::fmt::init(); let token = env::var("DISCORD_TOKEN")?; - let intents = Intents::GUILD_MESSAGES; - let mut shard = Shard::new(ShardId::ONE, token, intents); + let config = Config::new(token, Intents::GUILD_MESSAGES); + let mut shard = Shard::new(ShardId::ONE, config); tracing::info!("created shard"); loop { diff --git a/book/src/chapter_1_crates/section_4_cache_inmemory.md b/book/src/chapter_1_crates/section_4_cache_inmemory.md index d0b31fe286a..bc487ba9e71 100644 --- a/book/src/chapter_1_crates/section_4_cache_inmemory.md +++ b/book/src/chapter_1_crates/section_4_cache_inmemory.md @@ -13,11 +13,12 @@ Process new messages that come over a shard into the cache: # async fn main() -> Result<(), Box> { use std::env; use twilight_cache_inmemory::InMemoryCache; -use twilight_gateway::{Intents, Shard, ShardId}; +use twilight_gateway::{Config, Intents, Shard, ShardId}; let token = env::var("DISCORD_TOKEN")?; -let mut shard = Shard::new(ShardId::ONE, token, Intents::GUILD_MESSAGES); +let config = Config::new(token, Intents::GUILD_MESSAGES); +let mut shard = Shard::new(ShardId::ONE, config); let cache = InMemoryCache::new(); diff --git a/book/src/chapter_1_crates/section_7_first_party/section_3_lavalink.md b/book/src/chapter_1_crates/section_7_first_party/section_3_lavalink.md index 746c097900b..07fe34cdda1 100644 --- a/book/src/chapter_1_crates/section_7_first_party/section_3_lavalink.md +++ b/book/src/chapter_1_crates/section_7_first_party/section_3_lavalink.md @@ -48,7 +48,7 @@ use std::{ net::SocketAddr, str::FromStr, }; -use twilight_gateway::{Intents, Shard, ShardId}; +use twilight_gateway::{Config, Intents, Shard, ShardId}; use twilight_http::Client as HttpClient; use twilight_lavalink::Lavalink; @@ -65,8 +65,8 @@ async fn main() -> Result<(), Box> { let lavalink = Lavalink::new(user_id, shard_count); lavalink.add(lavalink_host, lavalink_auth).await?; - let intents = Intents::GUILD_MESSAGES | Intents::GUILD_VOICE_STATES; - let mut shard = Shard::new(ShardId::ONE, token, intents); + let config = Config::new(token, Intents::GUILD_MESSAGES | Intents::GUILD_VOICE_STATES); + let mut shard = Shard::new(ShardId::ONE, config); loop { let event = match shard.next_event().await { diff --git a/book/src/overview.md b/book/src/overview.md index 04cde02f335..2e2c56354d9 100644 --- a/book/src/overview.md +++ b/book/src/overview.md @@ -48,7 +48,7 @@ in from a channel: ```rust,no_run use std::{env, error::Error, sync::Arc}; use twilight_cache_inmemory::{InMemoryCache, ResourceType}; -use twilight_gateway::{Event, Intents, Shard, ShardId}; +use twilight_gateway::{Config, Event, Intents, Shard, ShardId}; use twilight_http::Client as HttpClient; #[tokio::main] @@ -58,9 +58,9 @@ async fn main() -> Result<(), Box> { // Specify intents requesting events about things like new and updated // messages in a guild and direct messages. let intents = Intents::GUILD_MESSAGES | Intents::DIRECT_MESSAGES | Intents::MESSAGE_CONTENT; - + let config = Config::new(token.clone(), intents); // Create a single shard. - let mut shard = Shard::new(ShardId::ONE, token.clone(), intents); + let mut shard = Shard::new(ShardId::ONE, config); // The http client is separate from the gateway, so startup a new // one, also use Arc such that it can be cloned to other threads. diff --git a/examples/gateway-intents.rs b/examples/gateway-intents.rs index ef6f804c442..d5ab21ff9d9 100644 --- a/examples/gateway-intents.rs +++ b/examples/gateway-intents.rs @@ -1,5 +1,5 @@ use std::env; -use twilight_gateway::{Intents, Shard, ShardId}; +use twilight_gateway::{Config, Intents, Shard, ShardId}; #[tokio::main] async fn main() -> anyhow::Result<()> { @@ -7,7 +7,8 @@ async fn main() -> anyhow::Result<()> { tracing_subscriber::fmt::init(); let intents = Intents::GUILD_MESSAGES | Intents::DIRECT_MESSAGES; - let mut shard = Shard::new(ShardId::ONE, env::var("DISCORD_TOKEN")?, intents); + let config = Config::new(env::var("DISCORD_TOKEN")?, intents); + let mut shard = Shard::new(ShardId::ONE, config); println!("Created shard"); loop { diff --git a/examples/gateway-parallel.rs b/examples/gateway-parallel.rs index 7a14aa61d10..8efc2ddf5be 100644 --- a/examples/gateway-parallel.rs +++ b/examples/gateway-parallel.rs @@ -5,13 +5,9 @@ //! [`ShardMessageStream`]: twilight_gateway::stream::ShardMessageStream use futures_util::{future::join_all, StreamExt}; -use std::{env, iter, sync::Arc, thread}; +use std::{env, iter, thread}; use tokio::{signal, sync::watch, task::JoinSet}; -use twilight_gateway::{ - queue::LocalQueue, - stream::{self, ShardEventStream}, - CloseFrame, Config, Intents, Shard, -}; +use twilight_gateway::{stream::ShardEventStream, CloseFrame, Config, Intents, Shard, ShardId}; use twilight_http::Client; #[tokio::main] @@ -21,29 +17,24 @@ async fn main() -> anyhow::Result<()> { let token = env::var("DISCORD_TOKEN")?; let client = Client::new(token.clone()); - let queue = Arc::new(LocalQueue::new()); - // callback to create a config for each shard, useful for when not all - // shards have the same configuration, such as for per-shard presences - let config_callback = |_| { - Config::builder(token.clone(), Intents::GUILDS) - .queue(queue.clone()) - .build() + let config = Config::new(token, Intents::GUILDS); + let recommended_shards = client.gateway().authed().await?.model().await?.shards; + let shards = { + let tasks = thread::available_parallelism()?.get(); + + // Split shards into a vec of `tasks` vecs of shards. + let init = iter::repeat_with(Vec::new) + .take(tasks) + .collect::>>(); + (0..recommended_shards) + .map(|id| Shard::new(ShardId::new(id, recommended_shards), config.clone())) + .enumerate() + .fold(init, |mut fold, (idx, shard)| { + fold[idx % tasks].push(shard); + fold + }) }; - let tasks = thread::available_parallelism()?.get(); - - // Split shards into a vec of `tasks` vecs of shards. - let init = iter::repeat_with(Vec::new) - .take(tasks) - .collect::>>(); - let shards = stream::create_recommended(&client, config_callback) - .await? - .enumerate() - .fold(init, |mut fold, (idx, shard)| { - fold[idx % tasks].push(shard); - fold - }); - let (tx, rx) = watch::channel(false); let mut set = JoinSet::new(); diff --git a/examples/gateway-request-members.rs b/examples/gateway-request-members.rs index 7d68b29b7c1..e9e7af05c42 100644 --- a/examples/gateway-request-members.rs +++ b/examples/gateway-request-members.rs @@ -1,5 +1,5 @@ use std::env; -use twilight_gateway::{Event, Intents, Shard, ShardId}; +use twilight_gateway::{Config, Event, Intents, Shard, ShardId}; use twilight_model::{gateway::payload::outgoing::RequestGuildMembers, id::Id}; #[tokio::main] @@ -7,11 +7,10 @@ async fn main() -> anyhow::Result<()> { // Initialize the tracing subscriber. tracing_subscriber::fmt::init(); - let mut shard = Shard::new( - ShardId::ONE, - env::var("DISCORD_TOKEN")?, - Intents::GUILD_MEMBERS | Intents::GUILDS, - ); + let token = env::var("DISCORD_TOKEN")?; + + let config = Config::new(token, Intents::GUILD_MEMBERS | Intents::GUILDS); + let mut shard = Shard::new(ShardId::ONE, config); loop { let event = match shard.next_event().await { diff --git a/examples/gateway-reshard.rs b/examples/gateway-reshard.rs index 38dd3c66342..f4f038b67e7 100644 --- a/examples/gateway-reshard.rs +++ b/examples/gateway-reshard.rs @@ -2,8 +2,7 @@ use futures_util::StreamExt; use std::{env, sync::Arc, time::Duration}; use tokio::time; use twilight_gateway::{ - queue::{LocalQueue, Queue}, - stream::{self, ShardEventStream, ShardMessageStream}, + stream::{ShardEventStream, ShardMessageStream}, Config, Event, Intents, Shard, ShardId, }; use twilight_http::Client; @@ -15,21 +14,12 @@ async fn main() -> anyhow::Result<()> { let token = env::var("DISCORD_TOKEN")?; let client = Arc::new(Client::new(token.clone())); - let queue: Arc = Arc::new(LocalQueue::new()); - - let config_callback = |_| { - // A queue must be specified in the builder for the shards to reuse the - // same one, which is necessary to not hit any gateway queue ratelimit. - Config::builder( - token.clone(), - Intents::GUILD_MESSAGES | Intents::MESSAGE_CONTENT, - ) - .queue(Arc::clone(&queue)) - .build() - }; - let mut shards = stream::create_recommended(&client, &config_callback) - .await? - .collect::>(); + + let config = Config::new(token, Intents::GUILD_MESSAGES | Intents::MESSAGE_CONTENT); + let recommended_shards = client.gateway().authed().await?.model().await?.shards; + let mut shards = (0..recommended_shards) + .map(|id| Shard::new(ShardId::new(id, recommended_shards), config.clone())) + .collect(); loop { // Run `gateway_runner` and `reshard` concurrently until the first one @@ -40,7 +30,7 @@ async fn main() -> anyhow::Result<()> { _ = gateway_runner(Arc::clone(&client), shards) => break, // Resharding complete! Time to run `gateway_runner` with the new // list of shards. - Ok(Some(new_shards)) = reshard(&client, config_callback) => { + Ok(Some(new_shards)) = reshard(&client, config.clone()) => { // Assign the new list of shards to `shards`, dropping the // old list. shards = new_shards; @@ -92,17 +82,15 @@ async fn event_handler(client: Arc, event: Event) -> anyhow::Result<()> // Instrument to differentiate between the logs produced here and // in `gateway_runner`. #[tracing::instrument(skip_all)] -async fn reshard( - client: &Client, - config_callback: impl Fn(ShardId) -> Config, -) -> anyhow::Result>> { +async fn reshard(client: &Client, config: Config) -> anyhow::Result>> { const RESHARD_DURATION: Duration = Duration::from_secs(60 * 60 * 8); // Reshard every eight hours. time::sleep(RESHARD_DURATION).await; - let mut shards = stream::create_recommended(client, config_callback) - .await? + let recommended_shards = client.gateway().authed().await?.model().await?.shards; + let mut shards = (0..recommended_shards) + .map(|id| Shard::new(ShardId::new(id, recommended_shards), config.clone())) .collect::>(); let mut identified = vec![false; shards.len()]; diff --git a/examples/gateway-shard.rs b/examples/gateway-shard.rs index a5c0d64ebfc..7031750d640 100644 --- a/examples/gateway-shard.rs +++ b/examples/gateway-shard.rs @@ -1,5 +1,5 @@ use std::env; -use twilight_gateway::{Intents, Shard, ShardId}; +use twilight_gateway::{Config, Intents, Shard, ShardId}; #[tokio::main] async fn main() -> anyhow::Result<()> { @@ -7,7 +7,8 @@ async fn main() -> anyhow::Result<()> { tracing_subscriber::fmt::init(); let intents = Intents::GUILD_MESSAGES | Intents::GUILD_VOICE_STATES; - let mut shard = Shard::new(ShardId::ONE, env::var("DISCORD_TOKEN")?, intents); + let config = Config::new(env::var("DISCORD_TOKEN")?, intents); + let mut shard = Shard::new(ShardId::ONE, config); loop { let event = match shard.next_event().await { diff --git a/examples/lavalink-basic-bot.rs b/examples/lavalink-basic-bot.rs index d8debcdf2a4..c408ca703c3 100644 --- a/examples/lavalink-basic-bot.rs +++ b/examples/lavalink-basic-bot.rs @@ -3,7 +3,7 @@ use hyper::{ Body, Request, }; use std::{env, future::Future, net::SocketAddr, str::FromStr, sync::Arc}; -use twilight_gateway::{Event, Intents, MessageSender, Shard, ShardId}; +use twilight_gateway::{Config, Event, Intents, MessageSender, Shard, ShardId}; use twilight_http::Client as HttpClient; use twilight_lavalink::{ http::LoadedTracks, @@ -54,7 +54,8 @@ async fn main() -> anyhow::Result<()> { let intents = Intents::GUILD_MESSAGES | Intents::GUILD_VOICE_STATES | Intents::MESSAGE_CONTENT; - let shard = Shard::new(ShardId::ONE, token, intents); + let config = Config::new(token, intents); + let shard = Shard::new(ShardId::ONE, config); let sender = shard.sender(); ( diff --git a/twilight-cache-inmemory/README.md b/twilight-cache-inmemory/README.md index a5815079fa4..11535eaf637 100644 --- a/twilight-cache-inmemory/README.md +++ b/twilight-cache-inmemory/README.md @@ -35,7 +35,7 @@ Update a cache with events that come in through the gateway: ```rust,no_run use std::{env, error::Error}; use twilight_cache_inmemory::InMemoryCache; -use twilight_gateway::{Intents, Shard, ShardId}; +use twilight_gateway::{Config, Intents, Shard, ShardId}; #[tokio::main] async fn main() -> Result<(), Box> { @@ -43,7 +43,8 @@ async fn main() -> Result<(), Box> { tracing_subscriber::fmt::init(); let token = env::var("DISCORD_TOKEN")?; - let mut shard = Shard::new(ShardId::ONE, token, Intents::GUILD_MESSAGES); + let config = Config::new(token, Intents::GUILD_MESSAGES); + let mut shard = Shard::new(ShardId::ONE, config); // Create a cache, caching up to 10 messages per channel: let cache = InMemoryCache::builder().message_cache_size(10).build(); diff --git a/twilight-gateway/Cargo.toml b/twilight-gateway/Cargo.toml index ded9c0f1091..6657324d1b6 100644 --- a/twilight-gateway/Cargo.toml +++ b/twilight-gateway/Cargo.toml @@ -31,7 +31,6 @@ twilight-model = { default-features = false, path = "../twilight-model", version # it does not seem to update the total_in of the function to have an offset # https://github.com/alexcrichton/flate2-rs/issues/217 flate2 = { default-features = false, optional = true, version = "1.0.24" } -twilight-http = { default-features = false, optional = true, path = "../twilight-http", version = "0.15.0-rc.1" } simd-json = { default-features = false, features = ["serde_impl", "swar-number-parsing"], optional = true, version = ">=0.4, <0.8" } # TLS libraries @@ -48,9 +47,10 @@ serde_test = { default-features = false, version = "1.0.136" } static_assertions = { default-features = false, version = "1" } tokio = { default-features = false, features = ["macros", "rt-multi-thread", "test-util"], version = "1.12" } tracing-subscriber = { default-features = false, features = ["fmt", "tracing-log"], version = "0.3" } +twilight-http = { default-features = false, path = "../twilight-http", version = "0.15.0-rc.1" } [features] -default = ["rustls-native-roots", "twilight-http", "zlib-stock"] +default = ["rustls-native-roots", "zlib-stock"] native = ["dep:native-tls", "tokio-tungstenite/native-tls"] rustls-native-roots = ["dep:rustls-tls", "dep:rustls-native-certs", "tokio-tungstenite/rustls-tls-native-roots"] rustls-webpki-roots = ["dep:rustls-tls", "dep:webpki-roots", "tokio-tungstenite/rustls-tls-webpki-roots"] diff --git a/twilight-gateway/README.md b/twilight-gateway/README.md index 6f4536af4ab..d5d469fd594 100644 --- a/twilight-gateway/README.md +++ b/twilight-gateway/README.md @@ -11,8 +11,6 @@ connection to Discord's gateway. Much of its functionality can be configured, an it's used to receive deserialized gateway event payloads or raw Websocket messages, useful for load balancing and microservices. -Using the `stream` module, shards can be easily managed in groups. - ## Features * `simd-json`: use [`simd-json`] instead of [`serde_json`] for deserializing @@ -23,18 +21,17 @@ Using the `stream` module, shards can be easily managed in groups. * `rustls-native-roots` (*default*): [`rustls`] using native root certificates * `rustls-webpki-roots`: [`rustls`] using [`webpki-roots`] for root certificates, useful for `scratch` containers -* `twilight-http` (*default*): enable the `stream::create_recommended` function * Zlib (mutually exclusive) * `zlib-stock` (*default*): [`flate2`]'s stock zlib implementation * `zlib-ng`: use [`zlib-ng`] for zlib, may have better performance ## Examples -Start a shard and loop over guild and voice state events: +Run a shard and loop over guild and voice state events: ```rust,no_run use std::env; -use twilight_gateway::{Intents, Shard, ShardId}; +use twilight_gateway::{Config, Intents, Shard, ShardId}; #[tokio::main] async fn main() -> anyhow::Result<()> { @@ -42,10 +39,10 @@ async fn main() -> anyhow::Result<()> { tracing_subscriber::fmt::init(); let token = env::var("DISCORD_TOKEN")?; - let intents = Intents::GUILDS | Intents::GUILD_VOICE_STATES; // Initialize the first and only shard in use by a bot. - let mut shard = Shard::new(ShardId::ONE, token, intents); + let config = Config::new(token, Intents::GUILDS | Intents::GUILD_VOICE_STATES); + let mut shard = Shard::new(ShardId::ONE, config); tracing::info!("started shard"); @@ -73,16 +70,13 @@ async fn main() -> anyhow::Result<()> { } ``` -Create the recommended number of shards and stream over their events: +Run the recommended number of shards, reusing the config to share the queue and +TLS context, and loop over their events through the `stream` module: ```rust,no_run use futures::StreamExt; -use std::{collections::HashMap, env, sync::Arc}; -use twilight_gateway::{ - queue::LocalQueue, - stream::{self, ShardEventStream}, - Config, Intents, -}; +use std::env; +use twilight_gateway::{stream::ShardEventStream, Config, Intents, Shard, ShardId}; use twilight_http::Client; #[tokio::main] @@ -92,19 +86,13 @@ async fn main() -> anyhow::Result<()> { let token = env::var("DISCORD_TOKEN")?; let client = Client::new(token.clone()); - let queue = Arc::new(LocalQueue::new()); - // Callback to create a config for each shard, useful for when not all shards - // have the same configuration, such as for per-shard presences. - let config_callback = |_| { - Config::builder(token.clone(), Intents::GUILDS) - .queue(queue.clone()) - .build() - }; - - let mut shards = stream::create_recommended(&client, config_callback) - .await? + let config = Config::new(token, Intents::GUILDS); + let recommended_shards = client.gateway().authed().await?.model().await?.shards; + let mut shards = (0..recommended_shards) + .map(|id| Shard::new(ShardId::new(id, recommended_shards), config.clone())) .collect::>(); + // Create an infinite stream over the shard's events. let mut stream = ShardEventStream::new(shards.iter_mut()); while let Some((shard, event)) = stream.next().await { diff --git a/twilight-gateway/src/config.rs b/twilight-gateway/src/config.rs index 22974935788..55c30f58060 100644 --- a/twilight-gateway/src/config.rs +++ b/twilight-gateway/src/config.rs @@ -267,14 +267,6 @@ impl Config { &self.token.inner } - /// Set the TLS container for the configuration. - /// - /// This is necessary for sharing a TLS container across configurations. - #[allow(clippy::missing_const_for_fn)] - pub(crate) fn set_tls(&mut self, tls: TlsContainer) { - self.tls = tls; - } - /// Session information to resume a shard on initialization. pub(crate) fn take_session(&mut self) -> Option { self.session.take() @@ -450,7 +442,7 @@ impl ConfigBuilder { /// )?) /// .build(); /// - /// let shard = Shard::with_config(ShardId::ONE, config); + /// let shard = Shard::new(ShardId::ONE, config); /// # Ok(()) } /// ``` #[allow(clippy::missing_const_for_fn)] diff --git a/twilight-gateway/src/connection.rs b/twilight-gateway/src/connection.rs index 64fd59f22fc..1061d735f66 100644 --- a/twilight-gateway/src/connection.rs +++ b/twilight-gateway/src/connection.rs @@ -35,10 +35,8 @@ const WEBSOCKET_CONFIG: WebSocketConfig = WebSocketConfig { /// [`tokio_tungstenite`] library Websocket connection. /// -/// Connections are used by [`Shard`]s when [initially connecting] and when -/// reconnecting. +/// Connections are used by [`Shard`]s when reconnecting. /// -/// [initially connecting]: crate::Shard::with_config /// [`Shard`]: crate::Shard pub type Connection = WebSocketStream>; diff --git a/twilight-gateway/src/inflater.rs b/twilight-gateway/src/inflater.rs index df5c83b95fb..17d7ec683df 100644 --- a/twilight-gateway/src/inflater.rs +++ b/twilight-gateway/src/inflater.rs @@ -92,9 +92,9 @@ fn is_incomplete_message(message: &[u8]) -> bool { /// /// Calculate the percentage bytes saved: /// ``` -/// # use twilight_gateway::{Intents, Shard, ShardId}; +/// # use twilight_gateway::{Config, Intents, Shard, ShardId}; /// # #[tokio::main] async fn main() { -/// # let shard = Shard::new(ShardId::ONE, String::new(), Intents::empty()); +/// # let shard = Shard::new(ShardId::ONE, Config::new(String::new(), Intents::empty())); /// let inflater = shard.inflater(); /// let total_percentage_compressed = /// inflater.processed() as f64 * 100.0 / inflater.produced() as f64; diff --git a/twilight-gateway/src/shard.rs b/twilight-gateway/src/shard.rs index 99cbea34eb5..0a840417759 100644 --- a/twilight-gateway/src/shard.rs +++ b/twilight-gateway/src/shard.rs @@ -99,7 +99,7 @@ use twilight_model::gateway::{ Heartbeat, Identify, Resume, }, }, - CloseCode, CloseFrame, Intents, OpCode, + CloseCode, CloseFrame, OpCode, }; /// Who initiated the closing of the websocket connection. @@ -257,8 +257,10 @@ struct MinimalReady { /// /// # Sharding /// -/// Bots in more than 2500 guilds must run multiple shards with different -/// [`ShardId`]s, which is easiest done by using items in the [`stream`] module. +/// A shard may not be connected to more than 2500 guilds, so large bots must +/// split themselves across multiple shards. See the +/// [Discord Docs/Sharding][docs:shards], [`ShardId`], and [`stream`] +/// documentation for more info. /// /// # Sending shard commands in different tasks /// @@ -266,54 +268,7 @@ struct MinimalReady { /// directly send [gateway commands] over a shard. To solve this /// [`Shard::sender`] can be used to receive an MPSC channel to send commands. /// -/// # Examples -/// -/// Create and start a shard and print new and deleted messages: -/// -/// ```no_run -/// use std::env; -/// use twilight_gateway::{Config, Event, EventTypeFlags, Intents, Shard, ShardId}; -/// -/// # #[tokio::main] async fn main() -> Result<(), Box> { -/// // Use the value of the "DISCORD_TOKEN" environment variable as the bot's -/// // token. Of course, this value may be passed into the program however is -/// // preferred. -/// let token = env::var("DISCORD_TOKEN")?; -/// let event_types = EventTypeFlags::MESSAGE_CREATE | EventTypeFlags::MESSAGE_DELETE; -/// -/// let config = Config::builder(token, Intents::GUILD_MESSAGES) -/// .event_types(event_types) -/// .build(); -/// let mut shard = Shard::with_config(ShardId::ONE, config); -/// -/// // Create a loop of only new messages and deleted messages. -/// -/// loop { -/// let event = match shard.next_event().await { -/// Ok(event) => event, -/// Err(source) => { -/// tracing::warn!(?source, "error receiving event"); -/// -/// if source.is_fatal() { -/// break; -/// } -/// -/// continue; -/// } -/// }; -/// -/// match event { -/// Event::MessageCreate(message) => { -/// println!("message received with content: {}", message.content); -/// } -/// Event::MessageDelete(message) => { -/// println!("message with ID {} deleted", message.id); -/// } -/// _ => {} -/// } -/// } -/// # Ok(()) } -/// ``` +/// See the crate root documentation for examples. /// /// [docs:shards]: https://discord.com/developers/docs/topics/gateway#sharding /// [gateway commands]: Shard::command @@ -326,7 +281,7 @@ pub struct Shard { /// User provided configuration. /// /// Configurations are provided or created in shard initializing via - /// [`Shard::new`] or [`Shard::with_config`]. + /// [`Shard::new`]. config: Config, /// Websocket connection, which may be connected to Discord's gateway. /// @@ -376,15 +331,8 @@ pub struct Shard { } impl Shard { - /// Create a new shard with the default configuration. - pub fn new(id: ShardId, token: String, intents: Intents) -> Self { - let config = Config::builder(token, intents).build(); - - Self::with_config(id, config) - } - /// Create a new shard with the provided configuration. - pub fn with_config(shard_id: ShardId, mut config: Config) -> Self { + pub fn new(shard_id: ShardId, mut config: Config) -> Self { let session = config.take_session(); Self { @@ -704,13 +652,13 @@ impl Shard { /// # #[tokio::main] /// # async fn main() -> Result<(), Box> { /// use std::env; - /// use twilight_gateway::{ConnectionStatus, Intents, Shard, ShardId}; + /// use twilight_gateway::{Config, ConnectionStatus, Intents, Shard, ShardId}; /// use twilight_model::{gateway::payload::outgoing::RequestGuildMembers, id::Id}; /// - /// let intents = Intents::GUILD_VOICE_STATES; /// let token = env::var("DISCORD_TOKEN")?; /// - /// let mut shard = Shard::new(ShardId::ONE, token, intents); + /// let config = Config::new(token, Intents::GUILD_VOICE_STATES); + /// let mut shard = Shard::new(ShardId::ONE, config); /// /// // Discord only allows sending the `RequestGuildMembers` command after /// // the shard is identified. @@ -822,9 +770,9 @@ impl Shard { /// Close the gateway connection but process already received messages: /// /// ```no_run - /// # use twilight_gateway::{Intents, Shard, ShardId}; + /// # use twilight_gateway::{Config, Intents, Shard, ShardId}; /// # #[tokio::main] async fn main() -> Result<(), Box> { - /// # let mut shard = Shard::new(ShardId::ONE, String::new(), Intents::empty()); + /// # let mut shard = Shard::new(ShardId::ONE, Config::new(String::new(), Intents::empty())); /// use twilight_gateway::{error::ReceiveMessageErrorType, CloseFrame, Message}; /// /// shard.close(CloseFrame::NORMAL).await?; diff --git a/twilight-gateway/src/stream.rs b/twilight-gateway/src/stream.rs index a00df5929a0..2b1bbdfe7ed 100644 --- a/twilight-gateway/src/stream.rs +++ b/twilight-gateway/src/stream.rs @@ -1,12 +1,5 @@ //! Utilities for managing collections of shards. //! -//! Multiple shards may easily be created at once, with a per shard config -//! created from a `Fn(ShardId) -> Config` closure, with the help of the -//! `create_` set of functions. These functions will also reuse shards' TLS -//! context, something otherwise achieved by cloning an existing [`Config`], but -//! will not by default set a shared [session queue] (see -//! [`ConfigBuilder::queue`]). -//! //! # Concurrency //! //! Multiple shards' events or websocket messages may be concurrently streamed @@ -28,136 +21,27 @@ //! //! See the [gateway-parallel] example for how to implement this. //! -//! [`ConfigBuilder::queue`]: crate::ConfigBuilder::queue //! [gateway-parallel]: https://github.com/twilight-rs/twilight/blob/main/examples/gateway-parallel.rs -//! [session queue]: crate::queue -use crate::{ - error::ReceiveMessageError, message::Message, tls::TlsContainer, Config, Shard, ShardId, -}; +use crate::{error::ReceiveMessageError, message::Message, Shard}; use futures_util::{ future::BoxFuture, stream::{FuturesUnordered, Stream, StreamExt}, }; -#[cfg(feature = "twilight-http")] -use std::{ - error::Error, - fmt::{Display, Formatter, Result as FmtResult}, -}; use std::{ - ops::{Bound, Deref, DerefMut, Range, RangeBounds}, + ops::{Deref, DerefMut}, pin::Pin, sync::mpsc, task::{Context, Poll}, }; -#[cfg(feature = "twilight-http")] -use twilight_http::Client; use twilight_model::gateway::event::Event; /// Generic list of unordered futures producing an item for each shard. type FutureList<'a, Item> = FuturesUnordered>>; -/// Failure when fetching the recommended number of shards to use from Discord's -/// REST API. -#[cfg(feature = "twilight-http")] -#[derive(Debug)] -pub struct StartRecommendedError { - /// Type of error. - pub(crate) kind: StartRecommendedErrorType, - /// Source error if available. - pub(crate) source: Option>, -} - -#[cfg(feature = "twilight-http")] -impl Display for StartRecommendedError { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - match self.kind { - StartRecommendedErrorType::Deserializing => { - f.write_str("payload isn't a recognized type") - } - StartRecommendedErrorType::Request => f.write_str("request failed to complete"), - } - } -} - -#[cfg(feature = "twilight-http")] -impl Error for StartRecommendedError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - self.source - .as_ref() - .map(|source| &**source as &(dyn Error + 'static)) - } -} - -/// Type of [`StartRecommendedError`] that occurred. -#[cfg(feature = "twilight-http")] -#[derive(Debug)] -pub enum StartRecommendedErrorType { - /// Received gateway event failed to be deserialized. - /// - /// The message payload is likely an unrecognized type that is not yet - /// supported. - Deserializing, - /// Requesting recommended shards from Discord's REST API failed. - /// - /// May be due to something such as a network or authentication issue. - Request, -} - /// Stream selecting the next gateway event from a collection of shards. /// -/// # Examples -/// -/// Create the recommended number of shards and stream over their events: -/// -/// ```no_run -/// use futures::StreamExt; -/// use std::{env, sync::Arc}; -/// use twilight_gateway::{ -/// queue::LocalQueue, -/// stream::{self, ShardEventStream}, -/// Config, Intents, -/// }; -/// use twilight_http::Client; -/// -/// # #[tokio::main] -/// # async fn main() -> Result<(), Box> { -/// let token = env::var("DISCORD_TOKEN")?; -/// let client = Client::new(token.clone()); -/// -/// let queue = Arc::new(LocalQueue::new()); -/// // callback to create a config for each shard, useful for when not all shards -/// // have the same configuration, such as for per-shard presences -/// let config_callback = |_| { -/// Config::builder(token.clone(), Intents::GUILDS) -/// .queue(queue.clone()) -/// .build() -/// }; -/// -/// let mut shards = stream::create_recommended(&client, config_callback) -/// .await? -/// .collect::>(); -/// -/// let mut stream = ShardEventStream::new(shards.iter_mut()); -/// -/// while let Some((shard, event)) = stream.next().await { -/// let event = match event { -/// Ok(event) => event, -/// Err(source) => { -/// tracing::warn!(?source, "error receiving event"); -/// -/// if source.is_fatal() { -/// break; -/// } -/// -/// continue; -/// } -/// }; -/// -/// tracing::debug!(?event, shard = ?shard.id(), "received event"); -/// } -/// # Ok(()) } -/// ``` +/// See the crate root documentation for examples. pub struct ShardEventStream<'a> { /// Set of futures resolving to the next event of each shard. futures: FutureList<'a, Event>, @@ -218,58 +102,7 @@ impl<'a> Stream for ShardEventStream<'a> { /// Stream selecting the next websocket message from a collection of shards. /// -/// # Examples -/// -/// Create the recommended number of shards and stream over their messages: -/// -/// ```no_run -/// use futures::StreamExt; -/// use std::{env, sync::Arc}; -/// use twilight_gateway::{ -/// queue::LocalQueue, -/// stream::{self, ShardMessageStream}, -/// Config, Intents, -/// }; -/// use twilight_http::Client; -/// -/// # #[tokio::main] -/// # async fn main() -> Result<(), Box> { -/// let token = env::var("DISCORD_TOKEN")?; -/// let client = Client::new(token.clone()); -/// -/// let queue = Arc::new(LocalQueue::new()); -/// // callback to create a config for each shard, useful for when not all shards -/// // have the same configuration, such as for per-shard presences -/// let config_callback = |_| { -/// Config::builder(token.clone(), Intents::GUILDS) -/// .queue(queue.clone()) -/// .build() -/// }; -/// -/// let mut shards = stream::create_recommended(&client, config_callback) -/// .await? -/// .collect::>(); -/// -/// let mut stream = ShardMessageStream::new(shards.iter_mut()); -/// -/// while let Some((shard, event)) = stream.next().await { -/// let message = match event { -/// Ok(message) => message, -/// Err(source) => { -/// tracing::warn!(?source, "error receiving message"); -/// -/// if source.is_fatal() { -/// break; -/// } -/// -/// continue; -/// } -/// }; -/// -/// tracing::debug!(?message, shard = ?shard.id(), "received message"); -/// } -/// # Ok(()) } -/// ``` +/// See the crate root documentation for examples. pub struct ShardMessageStream<'a> { /// Set of futures resolving to the next message of each shard. futures: FutureList<'a, Message>, @@ -371,192 +204,6 @@ struct NextItemOutput<'a, Item> { shard: &'a mut Shard, } -/// Create a single bucket's worth of shards with provided configuration for -/// each shard. -/// -/// # Examples -/// -/// Start bucket 2 out of 10 with 100 shards in total and collect them into a -/// list: -/// -/// ```no_run -/// use std::{env, sync::Arc}; -/// use twilight_gateway::{queue::LocalQueue, stream, Config, Intents}; -/// -/// # #[tokio::main] -/// # async fn main() -> Result<(), Box> { -/// let token = env::var("DISCORD_TOKEN")?; -/// -/// let queue = Arc::new(LocalQueue::new()); -/// // callback to create a config for each shard, useful for when not all shards -/// // have the same configuration, such as for per-shard presences -/// let config_callback = |_| { -/// Config::builder(token.clone(), Intents::GUILDS) -/// .queue(queue.clone()) -/// .build() -/// }; -/// -/// let shards = stream::create_bucket(2, 10, 100, config_callback) -/// .map(|shard| (shard.id().number(), shard)) -/// .collect::>(); -/// -/// assert_eq!(shards.len(), 10); -/// # Ok(()) } -/// ``` -/// -/// # Panics -/// -/// Panics if `bucket_id >= total` or if `concurrency >= total`. -/// -/// Panics if `concurrency` doesn't fit into a usize. -/// -/// Panics if loading TLS certificates fails. -#[track_caller] -pub fn create_bucket Config>( - bucket_id: u64, - concurrency: u64, - total: u64, - per_shard_config: F, -) -> impl Iterator { - assert!(bucket_id < total, "bucket id must be less than the total"); - assert!( - concurrency < total, - "concurrency must be less than the total" - ); - - let concurrency = concurrency.try_into().unwrap(); - let tls = TlsContainer::new().unwrap(); - - (bucket_id..total).step_by(concurrency).map(move |index| { - let id = ShardId::new(index, total); - let mut config = per_shard_config(id); - config.set_tls(tls.clone()); - - Shard::with_config(id, config) - }) -} - -/// Create a range of shards with provided configuration for each shard. -/// -/// # Examples -/// -/// Start 10 out of 10 shards and collect them into a map: -/// -/// ```no_run -/// use std::{collections::HashMap, env, sync::Arc}; -/// use twilight_gateway::{queue::LocalQueue, stream, Config, Intents}; -/// -/// # #[tokio::main] -/// # async fn main() -> Result<(), Box> { -/// let token = env::var("DISCORD_TOKEN")?; -/// -/// let queue = Arc::new(LocalQueue::new()); -/// // callback to create a config for each shard, useful for when not all shards -/// // have the same configuration, such as for per-shard presences -/// let config_callback = |_| { -/// Config::builder(token.clone(), Intents::GUILDS) -/// .queue(queue.clone()) -/// .build() -/// }; -/// -/// let shards = stream::create_range(0..10, 10, config_callback) -/// .map(|shard| (shard.id().number(), shard)) -/// .collect::>(); -/// -/// assert_eq!(shards.len(), 10); -/// # Ok(()) } -/// ``` -/// -/// # Panics -/// -/// Panics if `start >= total` or if `end > total`, where `start` and `end` -/// refer to `range`'s start and end. -/// -/// Panics if loading TLS certificates fails. -#[track_caller] -pub fn create_range Config>( - range: impl RangeBounds, - total: u64, - per_shard_config: F, -) -> impl Iterator { - let range = calculate_range(range, total); - let tls = TlsContainer::new().unwrap(); - - range.map(move |index| { - let id = ShardId::new(index, total); - let mut config = per_shard_config(id); - config.set_tls(tls.clone()); - - Shard::with_config(id, config) - }) -} - -/// Create a range of shards from Discord's recommendation with configuration -/// for each shard. -/// -/// Internally calls [`create_range`] with the values from [`GetGatewayAuthed`]. -/// -/// # Errors -/// -/// Returns a [`StartRecommendedErrorType::Deserializing`] error type if the -/// response body failed to deserialize. -/// -/// Returns a [`StartRecommendedErrorType::Request`] error type if the request -/// failed to complete. -/// -/// # Panics -/// -/// Panics if loading TLS certificates fails. -/// -/// [`GetGatewayAuthed`]: twilight_http::request::GetGatewayAuthed -#[cfg(feature = "twilight-http")] -pub async fn create_recommended Config>( - client: &Client, - per_shard_config: F, -) -> Result, StartRecommendedError> { - let request = client.gateway().authed(); - let response = request.await.map_err(|source| StartRecommendedError { - kind: StartRecommendedErrorType::Request, - source: Some(Box::new(source)), - })?; - let info = response - .model() - .await - .map_err(|source| StartRecommendedError { - kind: StartRecommendedErrorType::Deserializing, - source: Some(Box::new(source)), - })?; - - Ok(create_range(.., info.shards, per_shard_config)) -} - -/// Transform any range into a sized range based on the total. -/// -/// # Panics -/// -/// Panics if `start >= total` or if `end > total`, where `start` and `end` -/// refer to `range`'s start and end. -fn calculate_range(range: impl RangeBounds, total: u64) -> Range { - // 0, or the provided start bound (inclusive). - let start = match range.start_bound() { - Bound::Excluded(from) => *from + 1, - Bound::Included(from) => *from, - Bound::Unbounded => 0, - }; - - // Total, or the provided end bound (exclusive). - let end = match range.end_bound() { - Bound::Excluded(to) => *to, - Bound::Included(to) => *to + 1, - Bound::Unbounded => total, - }; - - assert!(start < total, "range start must be less than the total"); - assert!(end <= total, "range end must be less than the total"); - - start..end -} - #[cfg(test)] mod tests { use super::{ShardEventStream, ShardMessageStream, ShardRef}; diff --git a/twilight-lavalink/README.md b/twilight-lavalink/README.md index 64d95ed469f..67bdfdb0c3e 100644 --- a/twilight-lavalink/README.md +++ b/twilight-lavalink/README.md @@ -64,7 +64,7 @@ use std::{ net::SocketAddr, str::FromStr, }; -use twilight_gateway::{Event, Intents, Shard, ShardId}; +use twilight_gateway::{Config, Event, Intents, Shard, ShardId}; use twilight_http::Client as HttpClient; use twilight_lavalink::{http::LoadedTracks, model::Play, Lavalink}; @@ -85,7 +85,8 @@ async fn main() -> anyhow::Result<()> { lavalink.add(lavalink_host, lavalink_auth).await?; let intents = Intents::GUILD_MESSAGES | Intents::GUILD_VOICE_STATES; - let mut shard = Shard::new(ShardId::ONE, token, intents); + let config = Config::new(token, Intents::GUILD_MESSAGES | Intents::GUILD_VOICE_STATES); + let mut shard = Shard::new(ShardId::ONE, config); loop { let event = match shard.next_event().await { diff --git a/twilight-standby/README.md b/twilight-standby/README.md index 2cee7e1657b..41458385d8a 100644 --- a/twilight-standby/README.md +++ b/twilight-standby/README.md @@ -69,7 +69,7 @@ including a handler to wait for reactions: ```rust,no_run use futures_util::StreamExt; use std::{env, sync::Arc}; -use twilight_gateway::{Event, Intents, Shard, ShardId}; +use twilight_gateway::{Config, Event, Intents, Shard, ShardId}; use twilight_model::{ channel::Message, gateway::payload::incoming::ReactionAdd, @@ -80,9 +80,8 @@ use twilight_standby::Standby; async fn main() -> anyhow::Result<()> { let token = env::var("DISCORD_TOKEN")?; - // Start a shard connected to the gateway to receive events. - let intents = Intents::GUILD_MESSAGES | Intents::GUILD_MESSAGE_REACTIONS; - let mut shard = Shard::new(ShardId::ONE, token, intents); + let config = Config::new(token, Intents::GUILD_MESSAGES | Intents::GUILD_MESSAGE_REACTIONS); + let mut shard = Shard::new(ShardId::ONE, config); let standby = Arc::new(Standby::new()); From f871f89610d68d8858be75f0c8d0357fb80fdc4c Mon Sep 17 00:00:00 2001 From: Tim Vilgot Mikael Fredenberg <26655508+vilgotf@users.noreply.github.com> Date: Sat, 28 Jan 2023 08:27:07 +0100 Subject: [PATCH 3/6] refactor(gateway): remove dead simple examples --- examples/Cargo.toml | 8 -------- examples/gateway-intents.rs | 32 -------------------------------- examples/gateway-shard.rs | 31 ------------------------------- 3 files changed, 71 deletions(-) delete mode 100644 examples/gateway-intents.rs delete mode 100644 examples/gateway-shard.rs diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 20a52acb92b..a0a7502cf02 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -24,10 +24,6 @@ twilight-lavalink = { path = "../twilight-lavalink" } twilight-model = { path = "../twilight-model" } twilight-standby = { path = "../twilight-standby" } -[[example]] -name = "gateway-intents" -path = "gateway-intents.rs" - [[example]] name = "gateway-parallel" path = "gateway-parallel.rs" @@ -40,10 +36,6 @@ path = "gateway-reshard.rs" name = "gateway-request-members" path = "gateway-request-members.rs" -[[example]] -name = "gateway-shard" -path = "gateway-shard.rs" - [[example]] name = "http-allowed-mentions" path = "http-allowed-mentions.rs" diff --git a/examples/gateway-intents.rs b/examples/gateway-intents.rs deleted file mode 100644 index d5ab21ff9d9..00000000000 --- a/examples/gateway-intents.rs +++ /dev/null @@ -1,32 +0,0 @@ -use std::env; -use twilight_gateway::{Config, Intents, Shard, ShardId}; - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - // Initialize the tracing subscriber. - tracing_subscriber::fmt::init(); - - let intents = Intents::GUILD_MESSAGES | Intents::DIRECT_MESSAGES; - let config = Config::new(env::var("DISCORD_TOKEN")?, intents); - let mut shard = Shard::new(ShardId::ONE, config); - println!("Created shard"); - - loop { - let event = match shard.next_event().await { - Ok(event) => event, - Err(source) => { - tracing::warn!(?source, "error receiving event"); - - if source.is_fatal() { - break; - } - - continue; - } - }; - - println!("Event: {event:?}"); - } - - Ok(()) -} diff --git a/examples/gateway-shard.rs b/examples/gateway-shard.rs deleted file mode 100644 index 7031750d640..00000000000 --- a/examples/gateway-shard.rs +++ /dev/null @@ -1,31 +0,0 @@ -use std::env; -use twilight_gateway::{Config, Intents, Shard, ShardId}; - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - // Initialize the tracing subscriber. - tracing_subscriber::fmt::init(); - - let intents = Intents::GUILD_MESSAGES | Intents::GUILD_VOICE_STATES; - let config = Config::new(env::var("DISCORD_TOKEN")?, intents); - let mut shard = Shard::new(ShardId::ONE, config); - - loop { - let event = match shard.next_event().await { - Ok(event) => event, - Err(source) => { - tracing::warn!(?source, "error receiving event"); - - if source.is_fatal() { - break; - } - - continue; - } - }; - - println!("Event: {event:?}"); - } - - Ok(()) -} From 62c81d59ea1d11e7b3a259fbff73f0f329a51622 Mon Sep 17 00:00:00 2001 From: Tim Vilgot Mikael Fredenberg <26655508+vilgotf@users.noreply.github.com> Date: Sat, 28 Jan 2023 08:32:41 +0100 Subject: [PATCH 4/6] docs(gateway): remove odd parallel stream example --- twilight-gateway/src/stream.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/twilight-gateway/src/stream.rs b/twilight-gateway/src/stream.rs index 2b1bbdfe7ed..9b7137864d1 100644 --- a/twilight-gateway/src/stream.rs +++ b/twilight-gateway/src/stream.rs @@ -14,10 +14,10 @@ //! //! A multi-threaded executor is able to run tasks in parallel, but splitting //! shards across tasks requires channels to communicate between them, for -//! example, to coordinate shutdowns or to collect all events to a single event -//! handler task. It is therefore **not** recommended unless required for -//! performance reasons (a single core should, on a reasonably performant CPU, -//! be capable of handling tens of thousands of Discord events per second). +//! example, to coordinate shutdowns. It is therefore **not** recommended unless +//! required for performance reasons (a single core should, on a reasonably +//! performant CPU, be capable of handling tens of thousands of Discord events +//! per second). //! //! See the [gateway-parallel] example for how to implement this. //! From 48fc517b59b10aa955175e2fe5163e6a92dbd962 Mon Sep 17 00:00:00 2001 From: Tim Vilgot Mikael Fredenberg <26655508+vilgotf@users.noreply.github.com> Date: Sat, 28 Jan 2023 08:33:15 +0100 Subject: [PATCH 5/6] docs(gateway): `Config`'s reuse, incl. TLS ctx --- twilight-gateway/src/config.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/twilight-gateway/src/config.rs b/twilight-gateway/src/config.rs index 55c30f58060..cd0ea115dc6 100644 --- a/twilight-gateway/src/config.rs +++ b/twilight-gateway/src/config.rs @@ -152,7 +152,15 @@ impl Display for ShardId { /// Configuration used by the shard to identify with the gateway and operate. /// -/// Use [`Config::builder`] to configure a shard's configuration. +/// Use [`ConfigBuilder`] to configure all settings, easily created through the +/// [`Config::builder`] or [`ConfigBuilder::with_config`] functions, and turn it +/// into a config through the [`ConfigBuilder::build`] method. +/// +/// May be reused by cloning, also reusing the hidden TLS context---reducing +/// memory usage. The TLS context may still be reused with an otherwise +/// different config by turning it into to a [`ConfigBuilder`] through the +/// [`ConfigBuilder::with_config`] function and then rebuilding it into a new +/// config. #[derive(Clone, Debug)] pub struct Config { /// Event type flags. From 6147d75f4bef7039be9667aef82b2742ca578a65 Mon Sep 17 00:00:00 2001 From: Tim Vilgot Mikael Fredenberg <26655508+vilgotf@users.noreply.github.com> Date: Wed, 1 Feb 2023 09:04:48 +0100 Subject: [PATCH 6/6] fix test --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2d6581c2f86..30e3d6cfb84 100644 --- a/README.md +++ b/README.md @@ -133,7 +133,7 @@ async fn main() -> anyhow::Result<()> { let token = env::var("DISCORD_TOKEN")?; // Use intents to only receive guild message events. - let config = Config::new(token, Intents::GUILD_MESSAGES | Intents::MESSAGE_CONTENT); + let config = Config::new(token.clone(), Intents::GUILD_MESSAGES | Intents::MESSAGE_CONTENT); let mut shard = Shard::new(ShardId::ONE, config); // HTTP is separate from the gateway, so create a new client.