diself
Async Rust library for Discord selfbot automation. Type-safe, event-driven, built on tokio.
The Problem
Automating Discord user accounts in Rust meant dealing with raw WebSocket connections, manually parsing gateway events, handling reconnection logic, and managing rate limits — all from scratch. Existing solutions were either outdated, incomplete, or tied to bot-only APIs that don't work with user tokens.
The Approach
diself provides a clean, strongly-typed async API that abstracts away the complexity of Discord's gateway and REST protocols. You implement an EventHandler trait, and the library handles the connection lifecycle — heartbeats, session resumption, exponential backoff, and caching — so you can focus on what your automation actually does.
Technical Choices
Async-first on tokio
Discord bots need to handle many concurrent events — messages, presence updates, guild changes — without blocking. Tokio's async runtime lets diself process all of this efficiently on a single thread, with zero-cost futures and cooperative scheduling.
Exhaustive type system
60+ gateway events are modeled as typed Rust enums. Every channel, message, guild, role, and permission has a dedicated struct. If your handler compiles, it handles the data correctly — no runtime surprises from untyped JSON.
Built-in resilience
Network drops happen. diself automatically reconnects, resumes sessions when possible, and backs off exponentially when the gateway pushes back. Rate limits on the REST API are tracked and retried transparently.
Key Features
Usage Example
1use diself::prelude::*;23struct Handler;45#[async_trait]6impl EventHandler for Handler {7async fn message_create(&self, ctx: Context, msg: Message) {8if msg.content == "!ping" {9ctx.http10.create_message(msg.channel_id)11.content("Pong!")12.send()13.await14.ok();15}16}1718async fn ready(&self, _ctx: Context, user: User) {19println!("Connected as {}", user.username);20}21}2223#[tokio::main]24async fn main() {25Client::builder("token")26.event_handler(Handler)27.build()28.await29.expect("Failed to start client")30.start()31.await;32}