1- # PawSharp
1+ <div align =" center " >
2+ <img src =" assets/pawsharp-logo.svg " alt =" PawSharp Logo " width =" 180 " /><br /><br />
23
3- A Discord bot library for .NET 8. Handles the gateway connection, REST calls,
4- caching, slash commands, and voice with full DAVE E2EE.
4+ # PawSharp
55
6- ** Version:** 0.11.0-alpha.1 | ** Discord API:** v10 | ** Status:** alpha | [ Changelog] ( CHANGELOG.md )
6+ ** A modular Discord API library for .NET**
7+
8+ [ ![ NuGet] [ nuget-badge ]] [ nuget ]
9+ [ ![ Discord API] [ discord-api-badge ]] [ discord-docs ]
10+ [ ![ .NET] [ dotnet-badge ]] [ dotnet-link ]
11+ [ ![ License] [ license-badge ]] [ license ]
12+ [ ![ Build] [ build-badge ]] [ build ]
13+
14+ [ Documentation] [ docs ] · ; [ Changelog] [ changelog ] · ; [ Examples] [ examples ] · ; [ NuGet] [ nuget ]
15+
16+ </div >
17+
18+ ---
19+
20+ PawSharp is a feature-complete, modular Discord API library for C# and .NET. It covers the full gateway lifecycle, ~ 140 REST endpoints, prefix commands with preconditions, slash command routing, in-memory caching, per-route rate limiting, interactivity helpers, and full voice support including Discord's ** DAVE end-to-end encryption** — all in a single cohesive package suite with zero mandatory third-party dependencies outside the .NET runtime.
21+
22+ > ** Status:** ` 0.11.0-alpha.1 ` — public alpha. APIs may change between minor versions. See the [ versioning policy] [ versioning ] .
23+
24+ ---
25+
26+ ## Packages
27+
28+ Install only what your bot needs:
29+
30+ | Package | Description |
31+ | ---------| -------------|
32+ | ` PawSharp.Client ` | High-level ` DiscordClient ` — the recommended starting point |
33+ | ` PawSharp.Core ` | Entities, enums, exceptions, validators, CDN helpers |
34+ | ` PawSharp.API ` | Raw REST client with bucket-aware rate limiting |
35+ | ` PawSharp.Gateway ` | WebSocket gateway, heartbeat, sharding, session resume |
36+ | ` PawSharp.Commands ` | Attribute-based prefix command framework with preconditions |
37+ | ` PawSharp.Interactions ` | Slash commands, buttons, select menus, modals |
38+ | ` PawSharp.Interactivity ` | Reaction waiting, polls, pagination, component waiters |
39+ | ` PawSharp.Voice ` | Voice connections + Opus + RTP + DAVE E2EE (MLS / AES-128-GCM) |
740
841---
942
10- ## Install
43+ ## Installation
1144
1245``` bash
13- # Everything in one package
14- dotnet add package PawSharp.Client # 0.11.0-alpha.1
15-
16- # Or pick only what you need
17- dotnet add package PawSharp.API # REST endpoints only
18- dotnet add package PawSharp.Gateway # WebSocket / gateway only
19- dotnet add package PawSharp.Commands # Prefix-based text commands
20- dotnet add package PawSharp.Interactions # Slash commands & components
21- dotnet add package PawSharp.Interactivity # Reactions, polls, pagination
22- dotnet add package PawSharp.Voice # Voice channels + DAVE E2EE
46+ # Full client (recommended)
47+ dotnet add package PawSharp.Client
48+
49+ # Or add individual packages
50+ dotnet add package PawSharp.Commands
51+ dotnet add package PawSharp.Interactions
52+ dotnet add package PawSharp.Voice
2353```
2454
2555---
2656
27- ## Quickstart
57+ ## Quick Start
2858
2959``` csharp
60+ using PawSharp .Client ;
61+ using PawSharp .Core .Enums ;
62+
3063var client = new PawSharpClientBuilder ()
3164 .WithToken (Environment .GetEnvironmentVariable (" DISCORD_TOKEN" )! )
3265 .WithIntents (GatewayIntents .AllNonPrivileged | GatewayIntents .MessageContent )
33- .WithPresence (" pinging " , status : " online" )
66+ .WithPresence (" with .NET " , status : " online" )
3467 .UseConsoleLogging ()
3568 .Build ();
3669
3770client .OnMessageCreated (async msg =>
3871{
3972 if (msg .Author ? .Bot == true ) return ;
4073 if (msg .Content == " !ping" )
41- await client .Rest .CreateMessageAsync (msg .ChannelId , new () { Content = " Pong!" });
74+ await client .Rest .CreateMessageAsync (msg .ChannelId , new () { Content = " Pong! 🏓 " });
4275});
4376
4477await client .ConnectAsync ();
4578await Task .Delay (Timeout .Infinite );
4679```
4780
48- More examples in [ examples/] ( examples/ ) .
49-
5081---
5182
52- ## What it does
53-
54- - ** REST** — ~ 140 Discord API endpoints (messages, channels, guilds, roles, webhooks, threads, AutoMod, polls, stage instances, scheduled events, and more)
55- - ** Gateway** — WebSocket connection with auto-reconnect, session resume, sharding, and all opcodes handled
56- - ** Caching** — in-memory entity cache (guilds, channels, messages, members, roles) kept in sync from gateway events
57- - ** Rate limiting** — per-route bucket tracking, automatic retry on 429s
58- - ** Slash commands & interactions** — routing, response builders, and follow-up helpers
59- - ** Prefix commands** — attribute-based command modules (reflection scanner in progress, see below)
60- - ** Voice + DAVE E2EE** — Opus encode/decode (Concentus), RTP framing, AES-128-GCM per RFC 9420 MLS — zero extra crypto dependencies
61- - ** CDN helpers** — typed URL builders for avatars, guild icons, banners, emojis, and stickers
83+ ## Prefix Commands
6284
63- ---
85+ PawSharp's command framework uses attributes and supports cooldowns, permission checks, and guild-only guards out of the box.
6486
65- ## Error handling
87+ ``` csharp
88+ var commands = client .UseCommands (prefix : " !" );
89+ commands .RegisterModule (client , new ModerationCommands ());
90+ commands .CommandErrored = async args =>
91+ {
92+ if (args .Exception is PreconditionFailedException ex )
93+ await args .Context .ReplyAsync (ex .Message );
94+ };
6695
67- Everything throws typed exceptions:
96+ // ── Module ────────────────────────────────────────────────────────────────────
6897
69- ``` csharp
70- try
98+ public class ModerationCommands : BaseCommandModule
7199{
72- await client .Rest .CreateMessageAsync (channelId , new () { Content = text });
100+ [Command (" ping" )]
101+ [Description (" Latency check" )]
102+ public async Task PingAsync (CommandContext ctx )
103+ => await ctx .ReplyAsync (" Pong! 🏓" );
104+
105+ [Command (" ban" )]
106+ [RequireGuild ]
107+ [RequirePermissions (Permissions .BanMembers )]
108+ [Cooldown (maxUses : 3 , perSeconds : 10 , CooldownBucketType .User )]
109+ public async Task BanAsync (CommandContext ctx , ulong userId , string reason = " No reason" )
110+ {
111+ await ctx .Client .Rest .CreateGuildBanAsync (ctx .GuildId ! .Value , userId , reason : reason );
112+ await ctx .ReplyAsync ($" User `{userId }` has been banned." );
113+ }
73114}
74- catch (ValidationException ex ) { /* bad input */ }
75- catch (RateLimitException ex ) { /* slow down */ }
76- catch (DiscordApiException ex ) { /* API error */ }
77115```
78116
79117---
80118
81- ## Slash commands
119+ ## Slash Commands
82120
83121``` csharp
84122client .Interactions .RegisterCommand (" ping" , async interaction =>
@@ -87,109 +125,157 @@ client.Interactions.RegisterCommand("ping", async interaction =>
87125 new InteractionResponse
88126 {
89127 Type = (int )InteractionResponseType .ChannelMessageWithSource ,
90- Data = new InteractionCallbackData { Content = " Pong!" }
128+ Data = new InteractionCallbackData { Content = " Pong! 🏓 " }
91129 });
92130});
93131```
94132
95133---
96134
97- ## Voice (DAVE E2EE)
135+ ## Interactivity
136+
137+ Wait for button clicks or select menu submissions directly on a message:
138+
139+ ``` csharp
140+ var msg = await ctx .Client .Rest .CreateMessageAsync (ctx .ChannelId , new ()
141+ {
142+ Content = " Choose an option:" ,
143+ Components = ComponentBuilder .ActionRow (
144+ ComponentBuilder .Button (" Confirm" , customId : " confirm" , style : ButtonStyle .Success ),
145+ ComponentBuilder .Button (" Cancel" , customId : " cancel" , style : ButtonStyle .Danger ))
146+ });
147+
148+ var result = await msg .WaitForButtonAsync (ctx .Client , user : ctx .User , timeout : TimeSpan .FromSeconds (30 ));
149+
150+ if (result .TimedOut )
151+ await ctx .RespondAsync (" Timed out." );
152+ else if (result .Result ! .Data ? .CustomId == " confirm" )
153+ await ctx .RespondAsync (" Confirmed!" );
154+ ```
155+
156+ ---
157+
158+ ## Voice + DAVE E2EE
98159
99160``` csharp
100161var voice = client .UseVoice ();
101- var connection = await voice .ConnectAsync (voiceChannel );
162+ var connection = await voice .ConnectAsync (voiceChannelId );
102163
103- // Tell Discord you're about to speak, then start the mic pipeline
104164await connection .SetSpeakingAsync (true );
105- connection .StartCapture (); // PCM captured → Opus encoded → DAVE encrypted → RTP packet → sent
106165
107- // Push pre-recorded PCM (16-bit signed mono 48 kHz) directly
166+ // Stream pre-encoded PCM (16-bit mono 48 kHz)
108167await connection .SendAudioAsync (pcmBytes );
109168
110- // Incoming packets are automatically decrypted and decoded; push to speaker:
111- await connection .PlayAudioAsync (receivedPcm );
112-
113- await connection .SetSpeakingAsync (false );
169+ // Or capture from microphone
170+ connection .StartCapture (); // PCM → Opus → AES-128-GCM (DAVE) → RTP → UDP
171+ // ...
114172connection .StopCapture ();
173+
115174await connection .DisconnectAsync ();
116175```
117176
118- Each outgoing frame is a 20 ms Opus packet wrapped in a 12-byte RTP header
119- (RFC 3550 §5.1, payload type 120). The header is passed as Additional
120- Authenticated Data to AES-128-GCM so the auth tag covers the full packet, not
121- just the payload. Keys are derived per-sender via HKDF-SHA256 from the MLS
122- epoch secret — the entire crypto stack is built on ` System.Security.Cryptography `
123- primitives without any third-party crypto libraries.
177+ Each outgoing frame is a 20 ms Opus packet in a 12-byte RTP header (RFC 3550 §5.1, payload type 120). The RTP header is passed as Additional Authenticated Data to AES-128-GCM, so the auth tag covers the full packet. Keys are derived per-sender via HKDF-SHA256 from the MLS epoch secret. The full crypto stack is built on ` System.Security.Cryptography ` — no third-party crypto packages required.
124178
125179---
126180
127- ## Prefix commands
181+ ## Dependency Injection
128182
129- ``` csharp
130- var commands = client .UseCommands (" !" );
131-
132- public class MyCommands : BaseCommandModule
133- {
134- [Command (" ping" )]
135- public async Task PingAsync (CommandContext ctx )
136- => await ctx .RespondAsync (" Pong!" );
137- }
183+ PawSharp integrates cleanly with ` Microsoft.Extensions.DependencyInjection ` :
138184
139- commands .RegisterModule (new MyCommands ());
185+ ``` csharp
186+ services .AddSingleton (new PawSharpOptions { Token = token });
187+ services .AddHttpClient <IDiscordRestClient , DiscordRestClient >();
188+ services .AddSingleton <DiscordClient >();
140189```
141190
142- > ** Note:** The reflection scanner that discovers ` [Command] ` methods and wires them up is
143- > not yet implemented. Registration will work once that ships in the next release.
144-
145191---
146192
147- ## Dependency injection
193+ ## Error Handling
194+
195+ All errors surface as typed exceptions:
148196
149197``` csharp
150- services .AddSingleton (new PawSharpOptions { Token = token });
151- services .AddSingleton <IDiscordRestClient , DiscordRestClient >();
152- services .AddSingleton <DiscordClient >();
198+ try
199+ {
200+ await client .Rest .CreateMessageAsync (channelId , request );
201+ }
202+ catch (ValidationException ex ) { /* invalid content / embed */ }
203+ catch (RateLimitException ex ) { /* still rate-limited */ }
204+ catch (DiscordApiException ex ) { /* non-2xx response from API */ }
153205```
154206
155207---
156208
157- ## What is not done yet
209+ ## Features at a Glance
158210
159- | Feature | Status |
160- | ---------| --------|
161- | Command module auto-registration | Attribute system works; reflection scanner not shipped yet |
162- | Slash command attribute auto-register | Manual registration works; ` [SlashCommand] ` scanner pending |
163- | Redis cache as published package | Provider exists and is tested; not yet on NuGet |
211+ | Area | Detail |
212+ | ------| --------|
213+ | ** REST** | ~ 140 endpoints — messages, channels, guilds, roles, webhooks, threads, AutoMod, polls, stage instances, scheduled events |
214+ | ** Gateway** | Auto-reconnect, session resume, configurable sharding, all standard opcodes |
215+ | ** Caching** | In-memory entity cache (guilds, channels, messages, members, roles) kept in sync from gateway events |
216+ | ** Rate Limiting** | Per-route bucket tracking, global rate limit detection, automatic 429 retry with back-off |
217+ | ** Commands** | Attribute-based modules, ` [RequireGuild] ` , ` [RequirePermissions] ` , ` [Cooldown] ` , ` ReplyAsync ` |
218+ | ** Interactions** | Slash command routing, button & select handlers, modal support, follow-up messages |
219+ | ** Interactivity** | ` WaitForReactionAsync ` , ` WaitForButtonAsync ` , ` WaitForSelectAsync ` , ` CollectReactionsAsync ` , polls |
220+ | ** Voice** | Full Opus encode/decode (Concentus), RFC 3550 RTP framing, DAVE E2EE via RFC 9420 MLS |
221+ | ** CDN** | Typed URL builders for avatars, guild icons, banners, emojis, stickers |
164222
165223---
166224
167- ## Project layout
225+ ## Project Layout
168226
169227```
170228src/
171- PawSharp.Core - entities, enums, exceptions, builders, validators
172- PawSharp.API - REST client and rate limiter
173- PawSharp.Gateway - WebSocket gateway, event dispatcher, heartbeat, sharding
174- PawSharp.Cache - cache abstractions and in-memory provider
175- PawSharp.Client - high-level DiscordClient combining all of the above
176- PawSharp.Commands - prefix command framework
177- PawSharp.Interactions - slash commands, buttons , modals
178- PawSharp.Interactivity - reaction waiting, polls, pagination
179- PawSharp.Voice - voice connections + DAVE E2EE ( Opus + MLS + RTP)
180- tests/ - unit and integration tests (94+ passing)
181- examples/ - sample bots ( DashboardBot, ModerationBot, MusicBot)
182- docs/ - developer guides + DocFX API reference
229+ PawSharp.Core — entities, enums, exceptions, builders, validators, CDN helpers
230+ PawSharp.API — REST client + advanced rate limiter
231+ PawSharp.Gateway — WebSocket gateway, event dispatcher, heartbeat, sharding
232+ PawSharp.Cache — cache abstractions + in-memory provider
233+ PawSharp.Client — high-level DiscordClient and fluent builder
234+ PawSharp.Commands — prefix command framework with preconditions
235+ PawSharp.Interactions — slash commands, components , modals
236+ PawSharp.Interactivity — reaction/component waiting, polls, pagination
237+ PawSharp.Voice — voice connections, Opus codec, RTP, DAVE E2EE
238+ tests/ — unit and integration tests
239+ examples/ — sample bots: DashboardBot, ModerationBot, MusicBot
240+ docs/ — developer guides + DocFX API reference
183241```
184242
185243---
186244
245+ ## What Is Still In Progress
246+
247+ | Feature | Status |
248+ | ---------| --------|
249+ | Slash command attribute auto-register | Manual registration works; ` [SlashCommand] ` scanner coming in a future release |
250+ | Redis cache NuGet package | Provider exists and is tested; publication pending |
251+
252+ ---
253+
187254## Contributing
188255
189- See [ CONTRIBUTING.md] ( CONTRIBUTING.md ) .
256+ Contributions are welcome! Please read [ CONTRIBUTING.md] [ contributing ] before opening a pull request .
190257
191258---
192259
193260## License
194261
195- MIT
262+ PawSharp is distributed under the [ MIT License] [ license ] .
263+
264+ ---
265+
266+ <!-- Reference links -->
267+ [ nuget ] : https://www.nuget.org/packages/PawSharp.Client
268+ [ nuget-badge ] : https://img.shields.io/nuget/v/PawSharp.Client?style=flat-square&color=5865F2&label=nuget
269+ [ discord-api-badge ] : https://img.shields.io/badge/Discord%20API-v10-5865F2?style=flat-square
270+ [ discord-docs ] : https://discord.com/developers/docs
271+ [ dotnet-badge ] : https://img.shields.io/badge/.NET-8.0-512BD4?style=flat-square
272+ [ dotnet-link ] : https://dotnet.microsoft.com/en-us/download/dotnet/8.0
273+ [ license-badge ] : https://img.shields.io/badge/license-MIT-22c55e?style=flat-square
274+ [ license ] : LICENSE
275+ [ build-badge ] : https://img.shields.io/github/actions/workflow/status/M1tsumi/PawSharp/build.yml?style=flat-square
276+ [ build ] : https://github.com/M1tsumi/PawSharp/actions
277+ [ docs ] : https://github.com/M1tsumi/PawSharp/tree/main/docs
278+ [ changelog ] : CHANGELOG.md
279+ [ examples ] : examples/
280+ [ contributing ] : CONTRIBUTING.md
281+ [ versioning ] : docs/VERSIONING_POLICY.md
0 commit comments