@@ -11,11 +11,24 @@ connection to Discord's gateway. Much of its functionality can be configured,
1111and it's used to receive gateway events or raw Websocket messages, useful for
1212load balancing and microservices.
1313
14- Multiple shards may easily be created at once, with a per shard config created
15- from a ` Fn(ShardId, ConfigBuilder) -> Config ` closure, with the help of the
16- ` create_ ` set of functions. These functions will reuse shards' TLS context and
17- [ session queue] [ queue ] , something otherwise achieved by cloning an existing
18- [ ` Config ` ] .
14+ Multiple shards may be created with the ` bucket ` function, and optionally with a
15+ per-shard config.
16+
17+ ``` rust
18+ use twilight_gateway :: {Config , Shard };
19+
20+ fn shared (config : Config , shards : u32 ) -> impl Iterator <Item = Shard > {
21+ unique (std :: iter :: repeat_n (config , shards as usize ))
22+ }
23+
24+ fn unique (iter : impl ExactSizeIterator <Item = Config >) -> impl Iterator <Item = Shard > {
25+ let bucket_id = 0 ;
26+ let buckets = 1 ;
27+ let shards = iter . len () as u32 ;
28+ iter . zip (twilight_gateway :: bucket (bucket_id , buckets , shards ))
29+ . map (| (config , shard_id )| Shard :: with_config (shard_id , config ))
30+ }
31+ ```
1932
2033## Features
2134
@@ -33,145 +46,43 @@ from a `Fn(ShardId, ConfigBuilder) -> Config` closure, with the help of the
3346 * ` zlib ` : Zlib transport compression using [ ` zlib-rs ` ] [ ^1 ]
3447 * ` zstd ` (* default* ): Zstandard transport compression using [ ` zstd-sys ` ]
3548
36- ## Example
49+ ## Examples
3750
38- Create the recommended number of shards and loop over their guild messages :
51+ Create a shard and loop over guild events :
3952
4053``` rust,no_run
41- mod context {
42- use std::{ops::Deref, sync::OnceLock};
43- use twilight_http::Client;
44-
45- pub static CONTEXT: Handle = Handle(OnceLock::new());
46-
47- #[derive(Debug)]
48- pub struct Context {
49- pub http: Client,
50- }
51-
52- pub fn initialize(http: Client) {
53- let context = Context { http };
54- assert!(CONTEXT.0.set(context).is_ok());
55- }
56-
57- pub struct Handle(OnceLock<Context>);
58- impl Deref for Handle {
59- type Target = Context;
60-
61- fn deref(&self) -> &Self::Target {
62- self.0.get().unwrap()
63- }
64- }
65- }
66-
67- use context::CONTEXT;
68- use std::{env, pin::pin};
69- use tokio::signal;
70- use tokio_util::task::TaskTracker;
71- use twilight_gateway::{
72- CloseFrame, Config, Event, EventTypeFlags, Intents, MessageSender, Shard, StreamExt as _,
73- };
74- use twilight_http::Client;
75- use twilight_model::gateway::payload::{incoming::MessageCreate, outgoing::UpdateVoiceState};
76-
77- const EVENT_TYPES: EventTypeFlags = EventTypeFlags::MESSAGE_CREATE;
78- const INTENTS: Intents = Intents::GUILD_MESSAGES.union(Intents::MESSAGE_CONTENT);
54+ use std::env;
55+ use twilight_gateway::{EventTypeFlags, Intents, Shard, ShardId, StreamExt as _};
7956
80- #[tokio::main]
57+ #[tokio::main(flavor = "current_thread") ]
8158async fn main() -> anyhow::Result<()> {
8259 // Initialize the tracing subscriber.
8360 tracing_subscriber::fmt::init();
8461
8562 // Select rustls backend
8663 rustls::crypto::ring::default_provider().install_default().unwrap();
8764
88- let token = env::var("DISCORD_TOKEN")?;
89-
90- let config = Config::new(token.clone(), INTENTS);
91- let http = Client::new(token);
92- let shards =
93- twilight_gateway::create_recommended(&http, config, |_, builder| builder.build()).await?;
94- context::initialize(http);
95-
96- let tracker = TaskTracker::new();
97- for shard in shards {
98- tracker.spawn(dispatcher(shard));
99- }
100- tracker.close();
101- tracker.wait().await;
102-
103- Ok(())
104- }
65+ let token = env::var("TOKEN")?;
10566
106- #[tracing::instrument(fields(shard = %shard.id()), skip_all)]
107- async fn dispatcher(mut shard: Shard) {
108- let mut ctrl_c = pin!(signal::ctrl_c());
109- let mut shutdown = false;
110- let tracker = TaskTracker::new();
111- loop {
112- tokio::select! {
113- // Do not poll ctrl_c after it's completed.
114- _ = &mut ctrl_c, if !shutdown => {
115- // Cleanly shut down once we receive the echo close frame.
116- shard.close(CloseFrame::NORMAL);
117- shutdown = true;
118- },
119- Some(item) = shard.next_event(EVENT_TYPES) => {
120- let event = match item {
121- Ok(event) => event,
122- Err(source) => {
123- tracing::warn!(?source, "error receiving event");
124- continue;
125- }
126- };
127-
128- let handler = match event {
129- // Clean shutdown exit condition.
130- Event::GatewayClose(_) if shutdown => break,
131- Event::MessageCreate(e) => message(e, shard.sender()),
132- _ => continue,
133- };
134-
135- tracker.spawn(async move {
136- if let Err(source) = handler.await {
137- tracing::warn!(?source, "error handling event");
138- }
139- });
140- }
141- }
142- }
67+ // Initialize the first and only shard in use by a bot.
68+ let mut shard = Shard::new(ShardId::ONE, token, Intents::GUILDS);
14369
144- tracker.close();
145- tracker.wait().await;
146- }
70+ tracing::info!("started shard");
14771
148- #[tracing::instrument(fields(id = %event.id), skip_all)]
149- async fn message(event: Box<MessageCreate>, sender: MessageSender) -> anyhow::Result<()> {
150- match &*event.content {
151- "!join" if event.guild_id.is_some() => {
152- sender.command(&UpdateVoiceState::new(
153- event.guild_id.unwrap(),
154- Some(event.channel_id),
155- false,
156- false,
157- ))?;
158- }
159- "!ping" => {
160- CONTEXT
161- .http
162- .create_message(event.channel_id)
163- .content("Pong!")
164- .await?;
72+ while let Some(event) = shard.next_event(EventTypeFlags::all()).await {
73+ match event {
74+ Ok(event) => tracing::info!(?event, "received event"),
75+ Err(source) => tracing::warn!(?source, "failed to receive event"),
16576 }
166- _ => {}
16777 }
16878
16979 Ok(())
17080}
17181```
17282
17383There are a few additional examples located in the
174- [ repository] [ github examples link ] .
84+ [ repository] [ github examples link ] . Check out our [ template] to get started
85+ quickly.
17586
17687[ ^ 1 ] : Except for the s390x arch, where [ ` zlib-ng-sys ` ] is used instead.
17788
@@ -194,3 +105,4 @@ There are a few additional examples located in the
194105[ license badge ] : https://img.shields.io/badge/license-ISC-blue.svg?style=for-the-badge&logo=pastebin
195106[ license link ] : https://github.com/twilight-rs/twilight/blob/main/LICENSE.md
196107[ rust badge ] : https://img.shields.io/badge/rust-1.79+-93450a.svg?style=for-the-badge&logo=rust
108+ [ template ] : https://github.com/twilight-rs/template
0 commit comments