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.Threading.Tasks; | |||
| using Refit; | |||
| using Discord.Rest.Models; | |||
| using Discord.Models; | |||
| using System.Net.Http.Headers; | |||
| using System; | |||
| using System.Net.Http; | |||
| @@ -32,11 +32,11 @@ namespace Discord.Rest | |||
| }; | |||
| _api = RestService.For<IDiscordRestApi>(_http, refitSettings); | |||
| } | |||
| public Task<GatewayInfo> GetGatewayInfoAsync() | |||
| { | |||
| return _api.GetGatewayInfoAsync(); | |||
| } | |||
| => _api.GetGatewayInfoAsync(); | |||
| public Task<GatewayInfo> GetBotGatewayInfoAsync() | |||
| => _api.GetBotGatewayInfoAsync(); | |||
| public void Dispose() | |||
| { | |||
| @@ -1,13 +1,34 @@ | |||
| using System; | |||
| using System.Threading.Tasks; | |||
| using Refit; | |||
| using Discord.Rest.Models; | |||
| using Discord.Models; | |||
| namespace Discord.Rest | |||
| { | |||
| public interface IDiscordRestApi | |||
| { | |||
| // --- /applications | |||
| // --- /channels | |||
| // --- /gateway | |||
| [Get("/gateway/bot")] | |||
| 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 | |||
| using System.Text.Json.Serialization; | |||
| namespace Discord.Rest.Models | |||
| namespace Discord.Models | |||
| { | |||
| public class GatewayInfo | |||
| { | |||
| [JsonPropertyName("url")] | |||
| public string Url { get; set; } | |||
| [JsonPropertyName("shards")] | |||
| public int Shards { get; set; } | |||
| public int? Shards { get; set; } | |||
| [JsonPropertyName("session_start_limit")] | |||
| public GatewaySessionStartInfo SessionStartInfo { get; set; } | |||
| public GatewaySessionStartInfo? SessionStartInfo { get; set; } | |||
| } | |||
| 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/ | |||
| namespace Discord.Rest | |||
| namespace Discord | |||
| { | |||
| 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; } | |||
| } | |||
| } | |||