| Crates.io | disruption_gateway |
| lib.rs | disruption_gateway |
| version | 0.2.0 |
| created_at | 2023-10-14 08:57:24.892026+00 |
| updated_at | 2025-10-26 23:16:07.314024+00 |
| description | A small wrapper around the Discord gateway. |
| homepage | |
| repository | https://github.com/H1ghBre4k3r/disruption |
| max_upload_size | |
| id | 1003015 |
| size | 66,088 |
Low-level WebSocket gateway connection manager for the Discord API. This crate handles the WebSocket connection lifecycle, heartbeats, reconnection logic, and message routing.
Part of the Disruption Discord API wrapper ecosystem.
disruption_gateway provides production-ready gateway connection management with automatic reconnection, RESUME support, and reliable event delivery. It handles all the low-level details of maintaining a persistent WebSocket connection to Discord's gateway.
disruption_gateway directly if:disruption crate if:Add this to your Cargo.toml:
[dependencies]
disruption_gateway = "0.1.0"
tokio = { version = "1.47", features = ["full"] }
use disruption_gateway::Gateway;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Connect to Discord's gateway
let gateway = Gateway::connect("YOUR_BOT_TOKEN").await?;
// Get the receiver for gateway events
let receiver = gateway.receiver().await.clone();
// Process incoming payloads
loop {
let payload = receiver.recv().await?;
println!("Received event: {:?}", payload.t);
}
}
The Gateway struct manages the entire connection lifecycle:
pub struct Gateway {
token: String,
writer: WriterLock,
rec_tuple: (Sender<Payload>, Receiver<Payload>),
receiver_handle: Option<JoinHandle<()>>,
heartbeat_handle: Arc<Mutex<Option<JoinHandle<()>>>>,
}
Key Methods:
connect(token): Establishes a connection and returns a Gateway instancereceiver(): Returns the receiver for incoming payloadsseq_num(): Returns the current sequence numbersession_id(): Returns the current session ID (if available)set_session_id(): Sets the session ID (used internally)When the connection drops, the gateway attempts to RESUME the session:
// Gateway automatically tracks:
// - Last sequence number received
// - Session ID from READY event
// On reconnection:
if let (Some(session_id), Some(seq)) = (gateway.session_id(), gateway.seq_num()) {
// Send RESUME payload
// Discord replays any missed events
} else {
// Send IDENTIFY payload (new session)
}
Benefits:
Every Dispatch event (opcode 0) includes a sequence number:
// Gateway tracks the sequence number from each event
let payload = receiver.recv().await?;
if payload.op == GatewayOpcode::Dispatch {
// Sequence number automatically tracked internally
}
Benefits:
Reconnection delays increase exponentially:
Attempt 1: 1 second
Attempt 2: 2 seconds
Attempt 3: 4 seconds
Attempt 4: 8 seconds
Attempt 5: 16 seconds
Attempt 6: 32 seconds
Attempt 7+: 60 seconds (max)
Benefits:
Heartbeats are sent automatically based on the interval provided in HELLO:
// Gateway spawns a heartbeat task that:
// 1. Waits for the specified interval
// 2. Sends a Heartbeat payload with current sequence number
// 3. Expects a HeartbeatACK response
// 4. Reconnects if ACK not received
Benefits:
Gateway events are delivered as Payload structs:
pub struct Payload {
pub op: GatewayOpcode, // Operation code (0-11)
pub d: Option<Value>, // Event data (JSON)
pub s: Option<u64>, // Sequence number
pub t: Option<String>, // Event name
}
pub enum GatewayOpcode {
Dispatch = 0, // Event dispatched
Heartbeat = 1, // Heartbeat sent by client
Identify = 2, // Session start
PresenceUpdate = 3, // Presence update
VoiceStateUpdate = 4, // Voice state update
Resume = 6, // Resume disconnected session
Reconnect = 7, // Server requests reconnect
RequestGuildMembers = 8,// Request guild member info
InvalidSession = 9, // Session invalidated
Hello = 10, // Connection established
HeartbeatACK = 11, // Heartbeat acknowledged
}
let gateway = Gateway::connect(token).await?;
// Get current sequence number
if let Some(seq) = gateway.seq_num().await {
println!("Current sequence: {}", seq);
}
// Get session ID
if let Some(session_id) = gateway.session_id().await {
println!("Session ID: {}", session_id);
}
use disruption_gateway::Gateway;
use disruption_types::opcodes::GatewayOpcode;
let gateway = Gateway::connect(token).await?;
let receiver = gateway.receiver().await.clone();
loop {
let payload = receiver.recv().await?;
match payload.op {
GatewayOpcode::Dispatch => {
// Gateway event (MESSAGE_CREATE, GUILD_CREATE, etc.)
if let Some(event_name) = payload.t {
println!("Event: {}", event_name);
// payload.d contains the event data
}
}
GatewayOpcode::HeartbeatACK => {
println!("Heartbeat acknowledged");
}
GatewayOpcode::Reconnect => {
println!("Server requested reconnect");
}
GatewayOpcode::InvalidSession => {
println!("Session invalidated");
}
_ => {}
}
}
The gateway handles most errors internally and attempts to recover:
Critical errors are propagated to the caller through the Result type.
Enable logging to see gateway activity:
env_logger::init();
// Logs include:
// - Connection attempts and failures
// - IDENTIFY/RESUME messages
// - Heartbeat activity
// - Sequence number updates
// - Reconnection backoff delays
Set log level with the RUST_LOG environment variable:
RUST_LOG=disruption_gateway=debug cargo run
The Gateway struct uses Arc<Mutex<>> internally for thread-safe access to:
This allows the gateway to be used across multiple async tasks safely.
| Feature | disruption_gateway | serenity | twilight |
|---|---|---|---|
| RESUME Support | ✅ | ✅ | ✅ |
| Exponential Backoff | ✅ | ✅ | ✅ |
| Standalone Gateway | ✅ | ❌ | ✅ |
| Lightweight | ✅ | ❌ | ✅ |
| Raw Payload Access | ✅ | ❌ | ✅ |
This project is licensed under the MIT License - see the LICENSE file for details.
Part of the Disruption ecosystem | Built with ❤️ in Rust