Optional struct needs work still, + writing the converter for it is going to be a headachepull/1435/head
| @@ -0,0 +1,106 @@ | |||||
| https://gist.github.com/SinisterRectus/9518f3e7d0d1ccb4335b2a0d389c30b0 | |||||
| Sorted By Route | |||||
| -------------------------------------------------------------------------------------------------------------------- | |||||
| Get Entitlements GET /applications/{application.id}/entitlements | |||||
| Get Entitlement GET /applications/{application.id}/entitlements/{entitlement.id} | |||||
| Delete Test Entitlement DELETE /applications/{application.id}/entitlements/{entitlement.id}/ | |||||
| Consume SKU POST /applications/{application.id}/entitlements/{entitlement.id}/consume | |||||
| Get SKUs GET /applications/{application.id}/skus | |||||
| Delete/Close Channel DELETE /channels/{channel.id} | |||||
| Get Channel GET /channels/{channel.id} | |||||
| Modify Channel PUT/PATCH /channels/{channel.id} | |||||
| Get Channel Invites GET /channels/{channel.id}/invites | |||||
| Create Channel Invite POST /channels/{channel.id}/invites | |||||
| Get Channel Messages GET /channels/{channel.id}/messages | |||||
| Create Message POST /channels/{channel.id}/messages | |||||
| Bulk Delete Messages POST /channels/{channel.id}/messages/bulk-delete | |||||
| Bulk Delete Messages (deprecated) POST /channels/{channel.id}/messages/bulk_delete | |||||
| Delete Message DELETE /channels/{channel.id}/messages/{message.id} | |||||
| Get Channel Message GET /channels/{channel.id}/messages/{message.id} | |||||
| Edit Message PATCH /channels/{channel.id}/messages/{message.id} | |||||
| Delete All Reactions DELETE /channels/{channel.id}/messages/{message.id}/reactions | |||||
| Get Reactions GET /channels/{channel.id}/messages/{message.id}/reactions/{emoji} | |||||
| Delete Own Reaction DELETE /channels/{channel.id}/messages/{message.id}/reactions/{emoji}/@me | |||||
| Create Reaction PUT /channels/{channel.id}/messages/{message.id}/reactions/{emoji}/@me | |||||
| Delete User Reaction DELETE /channels/{channel.id}/messages/{message.id}/reactions/{emoji}/{user.id} | |||||
| Delete Channel Permission DELETE /channels/{channel.id}/permissions/{overwrite.id} | |||||
| Edit Channel Permissions PUT /channels/{channel.id}/permissions/{overwrite.id} | |||||
| Get Pinned Messages GET /channels/{channel.id}/pins | |||||
| Delete Pinned Channel Message DELETE /channels/{channel.id}/pins/{message.id} | |||||
| Add Pinned Channel Message PUT /channels/{channel.id}/pins/{message.id} | |||||
| Group DM Remove Recipient DELETE /channels/{channel.id}/recipients/{user.id} | |||||
| Group DM Add Recipient PUT /channels/{channel.id}/recipients/{user.id} | |||||
| Trigger Typing Indicator POST /channels/{channel.id}/typing | |||||
| Get Channel Webhooks GET /channels/{channel.id}/webhooks | |||||
| Create Webhook POST /channels/{channel.id}/webhooks | |||||
| Get Gateway GET /gateway | |||||
| Get Gateway Bot GET /gateway/bot | |||||
| Create Guild POST /guilds | |||||
| Delete Guild DELETE /guilds/{guild.id} | |||||
| Get Guild GET /guilds/{guild.id} | |||||
| Modify Guild PATCH /guilds/{guild.id} | |||||
| Get Guild Audit Log GET /guilds/{guild.id}/audit-logs | |||||
| Get Guild Bans GET /guilds/{guild.id}/bans | |||||
| Remove Guild Ban DELETE /guilds/{guild.id}/bans/{user.id} | |||||
| Get Guild Ban GET /guilds/{guild.id}/bans/{user.id} | |||||
| Create Guild Ban PUT /guilds/{guild.id}/bans/{user.id} | |||||
| Get Guild Channels GET /guilds/{guild.id}/channels | |||||
| Modify Guild Channel Positions PATCH /guilds/{guild.id}/channels | |||||
| Create Guild Channel POST /guilds/{guild.id}/channels | |||||
| Get Guild Embed GET /guilds/{guild.id}/embed | |||||
| Modify Guild Embed PATCH /guilds/{guild.id}/embed | |||||
| List Guild Emojis GET /guilds/{guild.id}/emojis | |||||
| Create Guild Emoji POST /guilds/{guild.id}/emojis | |||||
| Delete Guild Emoji DELETE /guilds/{guild.id}/emojis/{emoji.id} | |||||
| Get Guild Emoji GET /guilds/{guild.id}/emojis/{emoji.id} | |||||
| Modify Guild Emoji PATCH /guilds/{guild.id}/emojis/{emoji.id} | |||||
| Get Guild Integrations GET /guilds/{guild.id}/integrations | |||||
| Create Guild Integration POST /guilds/{guild.id}/integrations | |||||
| Delete Guild Integration DELETE /guilds/{guild.id}/integrations/{integration.id} | |||||
| Modify Guild Integration PATCH /guilds/{guild.id}/integrations/{integration.id} | |||||
| Sync Guild Integration POST /guilds/{guild.id}/integrations/{integration.id}/sync | |||||
| Get Guild Invites GET /guilds/{guild.id}/invites | |||||
| List Guild Members GET /guilds/{guild.id}/members | |||||
| Modify Current User Nick PATCH /guilds/{guild.id}/members/@me/nick | |||||
| Remove Guild Member DELETE /guilds/{guild.id}/members/{user.id} | |||||
| Get Guild Member GET /guilds/{guild.id}/members/{user.id} | |||||
| Modify Guild Member PATCH /guilds/{guild.id}/members/{user.id} | |||||
| Add Guild Member PUT /guilds/{guild.id}/members/{user.id} | |||||
| Remove Guild Member Role DELETE /guilds/{guild.id}/members/{user.id}/roles/{role.id} | |||||
| Add Guild Member Role PUT /guilds/{guild.id}/members/{user.id}/roles/{role.id} | |||||
| Get Guild Prune Count GET /guilds/{guild.id}/prune | |||||
| Begin Guild Prune POST /guilds/{guild.id}/prune | |||||
| Get Guild Voice Regions GET /guilds/{guild.id}/regions | |||||
| Get Guild Roles GET /guilds/{guild.id}/roles | |||||
| Modify Guild Role Positions PATCH /guilds/{guild.id}/roles | |||||
| Create Guild Role POST /guilds/{guild.id}/roles | |||||
| Delete Guild Role DELETE /guilds/{guild.id}/roles/{role.id} | |||||
| Modify Guild Role PATCH /guilds/{guild.id}/roles/{role.id} | |||||
| Get Guild Vanity URL GET /guilds/{guild.id}/vanity-url | |||||
| Get Guild Webhooks GET /guilds/{guild.id}/webhooks | |||||
| Get Guild Widget Image GET /guilds/{guild.id}/widget.png | |||||
| Delete Invite DELETE /invites/{invite.code} | |||||
| Get Invite GET /invites/{invite.code} | |||||
| Get Current Application Information GET /oauth2/applications/@me | |||||
| Delete Purchase Discount DELETE /store/skus/{sku.id}/discounts/{user.id}/ | |||||
| Create Purchase Discount PUT /store/skus/{sku.id}/discounts/{user.id}/ | |||||
| Get Current User GET /users/@me | |||||
| Modify Current User PATCH /users/@me | |||||
| Get User DMs GET /users/@me/channels | |||||
| Create DM POST /users/@me/channels | |||||
| Create Group DM POST /users/@me/channels | |||||
| Get User Connections GET /users/@me/connections | |||||
| Get Current User Guilds GET /users/@me/guilds | |||||
| Leave Guild DELETE /users/@me/guilds/{guild.id} | |||||
| Get User GET /users/{user.id} | |||||
| List Voice Regions GET /voice/regions | |||||
| Delete Webhook DELETE /webhooks/{webhook.id} | |||||
| Get Webhook GET /webhooks/{webhook.id} | |||||
| Modify Webhook PATCH /webhooks/{webhook.id} | |||||
| Delete Webhook with Token DELETE /webhooks/{webhook.id}/{webhook.token} | |||||
| Get Webhook with Token GET /webhooks/{webhook.id}/{webhook.token} | |||||
| Modify Webhook with Token PATCH /webhooks/{webhook.id}/{webhook.token} | |||||
| Execute Webhook POST /webhooks/{webhook.id}/{webhook.token} | |||||
| Execute GitHub-Compatible Webhook POST /webhooks/{webhook.id}/{webhook.token}/github | |||||
| Execute Slack-Compatible Webhook POST /webhooks/{webhook.id}/{webhook.token}/slack | |||||
| @@ -0,0 +1,24 @@ | |||||
| namespace Discord | |||||
| { | |||||
| /// <summary> | |||||
| /// A Snowflake represents a unique, 64-bit identifier. | |||||
| /// </summary> | |||||
| public struct Snowflake | |||||
| { | |||||
| private readonly ulong _value; | |||||
| private Snowflake(ulong value) | |||||
| { | |||||
| _value = value; | |||||
| } | |||||
| public static implicit operator ulong(Snowflake snowflake) | |||||
| { | |||||
| return snowflake._value; | |||||
| } | |||||
| public static implicit operator Snowflake(ulong value) | |||||
| { | |||||
| return new Snowflake(value); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,7 +1,7 @@ | |||||
| using System.Text.Json; | using System.Text.Json; | ||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| using Refit; | using Refit; | ||||
| using Discord.Rest.Models; | |||||
| using Discord.Models; | |||||
| using System.Net.Http.Headers; | using System.Net.Http.Headers; | ||||
| using System; | using System; | ||||
| using System.Net.Http; | using System.Net.Http; | ||||
| @@ -32,11 +32,11 @@ namespace Discord.Rest | |||||
| }; | }; | ||||
| _api = RestService.For<IDiscordRestApi>(_http, refitSettings); | _api = RestService.For<IDiscordRestApi>(_http, refitSettings); | ||||
| } | } | ||||
| public Task<GatewayInfo> GetGatewayInfoAsync() | public Task<GatewayInfo> GetGatewayInfoAsync() | ||||
| { | |||||
| return _api.GetGatewayInfoAsync(); | |||||
| } | |||||
| => _api.GetGatewayInfoAsync(); | |||||
| public Task<GatewayInfo> GetBotGatewayInfoAsync() | |||||
| => _api.GetBotGatewayInfoAsync(); | |||||
| public void Dispose() | public void Dispose() | ||||
| { | { | ||||
| @@ -1,13 +1,34 @@ | |||||
| using System; | using System; | ||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| using Refit; | using Refit; | ||||
| using Discord.Rest.Models; | |||||
| using Discord.Models; | |||||
| namespace Discord.Rest | namespace Discord.Rest | ||||
| { | { | ||||
| public interface IDiscordRestApi | public interface IDiscordRestApi | ||||
| { | { | ||||
| // --- /applications | |||||
| // --- /channels | |||||
| // --- /gateway | |||||
| [Get("/gateway/bot")] | [Get("/gateway/bot")] | ||||
| Task<GatewayInfo> GetGatewayInfoAsync(); | Task<GatewayInfo> GetGatewayInfoAsync(); | ||||
| [Get("/gateway/bot")] | |||||
| Task<GatewayInfo> GetBotGatewayInfoAsync(); | |||||
| // --- /guilds | |||||
| // --- /invites | |||||
| // --- /oauth2 | |||||
| // --- /store | |||||
| // --- /users | |||||
| // --- /voice | |||||
| // --- /webhooks | |||||
| } | } | ||||
| } | } | ||||
| @@ -0,0 +1,59 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Text; | |||||
| using System.Text.Json.Serialization; | |||||
| namespace Discord.Models | |||||
| { | |||||
| public class Channel | |||||
| { | |||||
| public const int MinChannelNameLength = 2; | |||||
| public const int MaxChannelNameLength = 100; | |||||
| public const int MinChannelTopicLength = 0; | |||||
| public const int MaxChannelTopicLength = 1024; | |||||
| public const int MinUserLimit = 0; | |||||
| public const int MaxUserLimit = 100; | |||||
| public const int MinBitrate = 8000; | |||||
| public const int MaxBitrate = 384000; | |||||
| public const int MinRateLimitPerUser = 0; | |||||
| public const int MaxRateLimitPerUser = 21600; | |||||
| [JsonPropertyName("id")] | |||||
| public Snowflake Id { get; set; } | |||||
| [JsonPropertyName("type")] | |||||
| public ChannelType Type { get; set; } | |||||
| [JsonPropertyName("guild_id")] | |||||
| public Optional<Snowflake> GuildId { get; set; } | |||||
| [JsonPropertyName("position")] | |||||
| public Optional<short> Position { get; set; } | |||||
| [JsonPropertyName("permission_overwrites")] | |||||
| public Optional<Overwrite[]> Overwrites { get; set; } | |||||
| [JsonPropertyName("name")] | |||||
| public Optional<string> Name { get; set; } | |||||
| [JsonPropertyName("topic")] | |||||
| public Optional<string?> Topic { get; set; } | |||||
| [JsonPropertyName("nsfw")] | |||||
| public Optional<bool> Nsfw { get; set; } | |||||
| [JsonPropertyName("user_limit")] | |||||
| public Optional<short> Bitrate { get; set; } | |||||
| [JsonPropertyName("rate_limit_per_user")] | |||||
| public Optional<int> RateLimitPerUser { get; set; } | |||||
| [JsonPropertyName("recipients")] | |||||
| public Optional<User[]> Recipients { get; set; } | |||||
| [JsonPropertyName("icon")] | |||||
| public Optional<string?> IconId { get; set; } | |||||
| [JsonPropertyName("owner_id")] | |||||
| public Optional<Snowflake> OwnerId { get; set; } | |||||
| [JsonPropertyName("application_id")] | |||||
| public Optional<Snowflake> ApplicationId { get; set; } | |||||
| [JsonPropertyName("parent_id")] | |||||
| public Optional<Snowflake> ParentId { get; set; } | |||||
| [JsonPropertyName("last_pin_timestamp")] | |||||
| public Optional<DateTimeOffset> LastPinTimestamp { get; set; } | |||||
| // omitted: last_message_id | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,13 @@ | |||||
| namespace Discord.Models | |||||
| { | |||||
| public enum ChannelType : byte | |||||
| { | |||||
| Text = 0, | |||||
| Direct = 1, | |||||
| Voice = 2, | |||||
| Group = 3, | |||||
| Category = 4, | |||||
| News = 5, | |||||
| Store = 6 | |||||
| } | |||||
| } | |||||
| @@ -1,16 +1,16 @@ | |||||
| #pragma warning disable CS8618 // Uninitialized NRT expected in models | #pragma warning disable CS8618 // Uninitialized NRT expected in models | ||||
| using System.Text.Json.Serialization; | using System.Text.Json.Serialization; | ||||
| namespace Discord.Rest.Models | |||||
| namespace Discord.Models | |||||
| { | { | ||||
| public class GatewayInfo | public class GatewayInfo | ||||
| { | { | ||||
| [JsonPropertyName("url")] | [JsonPropertyName("url")] | ||||
| public string Url { get; set; } | public string Url { get; set; } | ||||
| [JsonPropertyName("shards")] | [JsonPropertyName("shards")] | ||||
| public int Shards { get; set; } | |||||
| public int? Shards { get; set; } | |||||
| [JsonPropertyName("session_start_limit")] | [JsonPropertyName("session_start_limit")] | ||||
| public GatewaySessionStartInfo SessionStartInfo { get; set; } | |||||
| public GatewaySessionStartInfo? SessionStartInfo { get; set; } | |||||
| } | } | ||||
| public class GatewaySessionStartInfo | public class GatewaySessionStartInfo | ||||
| @@ -0,0 +1,36 @@ | |||||
| using System; | |||||
| namespace Discord.Models | |||||
| { | |||||
| [Flags] | |||||
| public enum ChannelPermissions : ulong | |||||
| { | |||||
| // General | |||||
| CreateInstantInvite = 0x0000_0001, | |||||
| ManageChannel = 0x0000_0010, | |||||
| AddReactions = 0x0000_0040, | |||||
| ViewChannel = 0x0000_0400, | |||||
| ManagePermissions = 0x1000_0000, | |||||
| ManageWebhooks = 0x2000_0000, | |||||
| // Messages | |||||
| SendMessages = 0x0000_0800, | |||||
| SendTtsMessages = 0x0000_0100, | |||||
| ManageMessages = 0x0000_02000, | |||||
| EmbedLinks = 0x0000_4000, | |||||
| AttachFiles = 0x0000_8000, | |||||
| ReadMessageHistory = 0x0001_0000, | |||||
| MentionEveryone = 0x0002_0000, | |||||
| UseExternalEmoji = 0x0004_0000, | |||||
| // Voice | |||||
| Connect = 0x0010_0000, | |||||
| Speak = 0x0020_0000, | |||||
| MuteMembers = 0x0040_0000, | |||||
| DeafenMembers = 0x0080_0000, | |||||
| MoveMembers = 0x0100_0000, | |||||
| UseVoiceActivity = 0x0200_0000, | |||||
| PrioritySpeaker = 0x0000_0100, | |||||
| Stream = 0x0000_0200, | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,45 @@ | |||||
| using System; | |||||
| namespace Discord.Models | |||||
| { | |||||
| // todo: doc these when other models exist | |||||
| [Flags] | |||||
| public enum GuildPermissions : ulong | |||||
| { | |||||
| // General | |||||
| CreateInstantInvite = 0x0000_0001, | |||||
| KickMembers = 0x0000_0002, | |||||
| BanMembers = 0x0000_0004, | |||||
| Administrator = 0x0000_0008, | |||||
| ManageChannels = 0x0000_0010, | |||||
| ManageGuild = 0x0000_0020, | |||||
| AddReactions = 0x0000_0040, | |||||
| ViewAuditLog = 0x0000_0080, | |||||
| ViewChannel = 0x0000_0400, | |||||
| ChangeNickname = 0x0400_0000, | |||||
| ManageNicknames = 0x0800_0000, | |||||
| ManageRoles = 0x1000_0000, | |||||
| ManageWebhooks = 0x2000_0000, | |||||
| ManageEmoji = 0x4000_0000, | |||||
| // Messages | |||||
| SendMessages = 0x0000_0800, | |||||
| SendTtsMessages = 0x0000_0100, | |||||
| ManageMessages = 0x0000_02000, | |||||
| EmbedLinks = 0x0000_4000, | |||||
| AttachFiles = 0x0000_8000, | |||||
| ReadMessageHistory = 0x0001_0000, | |||||
| MentionEveryone = 0x0002_0000, | |||||
| UseExternalEmoji = 0x0004_0000, | |||||
| // Voice | |||||
| Connect = 0x0010_0000, | |||||
| Speak = 0x0020_0000, | |||||
| MuteMembers = 0x0040_0000, | |||||
| DeafenMembers = 0x0080_0000, | |||||
| MoveMembers = 0x0100_0000, | |||||
| UseVoiceActivity = 0x0200_0000, | |||||
| PrioritySpeaker = 0x0000_0100, | |||||
| Stream = 0x0000_0200, | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,16 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Text; | |||||
| using System.Text.Json.Serialization; | |||||
| namespace Discord.Models | |||||
| { | |||||
| public class Overwrite | |||||
| { | |||||
| [JsonPropertyName("id")] | |||||
| public Snowflake Id { get; set; } | |||||
| [JsonPropertyName("type")] | |||||
| [JsonConverter(typeof(JsonStringEnumConverter))] | |||||
| public PermissionTarget TargetType { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,8 @@ | |||||
| namespace Discord.Models | |||||
| { | |||||
| public enum PermissionTarget | |||||
| { | |||||
| Member, | |||||
| Role | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,20 @@ | |||||
| using System; | |||||
| namespace Discord.Models | |||||
| { | |||||
| [Flags] | |||||
| public enum AccountFlags : short | |||||
| { | |||||
| None = 0, | |||||
| Employee = 1<<0, | |||||
| Partner = 1<<1, | |||||
| HypesquadEvents = 1<<2, | |||||
| BugHunter = 1<<3, | |||||
| HypesquadBravery = 1<<6, | |||||
| HypesquadBrilliance = 1<<7, | |||||
| HypesquadBalance = 1<<8, | |||||
| EarlySupporter = 1<<9, | |||||
| TeamUser = 1<<10, | |||||
| System = 1<<12, | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,8 @@ | |||||
| namespace Discord.Models | |||||
| { | |||||
| public enum PremiumType : byte | |||||
| { | |||||
| Classic = 1, | |||||
| Nitro = 2 | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,33 @@ | |||||
| #pragma warning disable CS8618 // Uninitialized NRT expected in models <username> | |||||
| using System.Text.Json.Serialization; | |||||
| namespace Discord.Models | |||||
| { | |||||
| public class User | |||||
| { | |||||
| [JsonPropertyName("id")] | |||||
| public Snowflake Id { get; set; } | |||||
| [JsonPropertyName("username")] | |||||
| public string Username { get; set; } | |||||
| [JsonPropertyName("discriminator")] | |||||
| public ushort Discriminator { get; set; } | |||||
| [JsonPropertyName("avatar")] | |||||
| public string? AvatarId { get; set; } | |||||
| [JsonPropertyName("bot")] | |||||
| public Optional<bool> Bot { get; set; } | |||||
| [JsonPropertyName("system")] | |||||
| public Optional<bool> System { get; set; } | |||||
| [JsonPropertyName("mfa_enabled")] | |||||
| public Optional<bool> MfaEnabled { get; set; } | |||||
| [JsonPropertyName("locale")] | |||||
| public Optional<string> Locale { get; set; } | |||||
| [JsonPropertyName("verified")] | |||||
| public Optional<bool> Verified { get; set; } | |||||
| [JsonPropertyName("email")] | |||||
| public Optional<string> Email { get; set; } | |||||
| [JsonPropertyName("flags")] | |||||
| public Optional<AccountFlags> Flags { get; set; } | |||||
| [JsonPropertyName("premium_type")] | |||||
| public Optional<PremiumType> PremiumType { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -8,7 +8,7 @@ using Refit; | |||||
| // https://blog.martincostello.com/refit-and-system-text-json/ | // https://blog.martincostello.com/refit-and-system-text-json/ | ||||
| namespace Discord.Rest | |||||
| namespace Discord | |||||
| { | { | ||||
| public class JsonContentSerializer : IContentSerializer | public class JsonContentSerializer : IContentSerializer | ||||
| { | { | ||||
| @@ -0,0 +1,22 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Text; | |||||
| using System.Text.Json; | |||||
| using System.Text.Json.Serialization; | |||||
| namespace Discord.Serialization | |||||
| { | |||||
| // 😅 | |||||
| public class OptionalConverter<T> : JsonConverter<Optional<T>> | |||||
| { | |||||
| public override Optional<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) | |||||
| { | |||||
| throw new NotImplementedException(); | |||||
| } | |||||
| public override void Write(Utf8JsonWriter writer, Optional<T> value, JsonSerializerOptions options) | |||||
| { | |||||
| throw new NotImplementedException(); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,12 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Text; | |||||
| // todo: impl | |||||
| namespace Discord | |||||
| { | |||||
| public struct Optional<T> | |||||
| { | |||||
| public bool IsSpecified { get; private set; } | |||||
| public T Value { get; set; } | |||||
| } | |||||
| } | |||||