Compare commits

...

42 Commits

Author SHA1 Message Date
  RogueException b6b0a4dbbd Updated RPC and Webhooks to use the new serializer events 7 years ago
  RogueException ebcdd14fc6 Support serializing streams where CanSeek is false 7 years ago
  RogueException d2c4d81317 Added support for most escape chars 7 years ago
  RogueException 6663a5754c Added StringEnum attribute to EmbedType 7 years ago
  RogueException 1e68b4a6fd Added logging for deserialization errors and unknown properties 7 years ago
  RogueException a4dbef6725 Added support for escapable strings 7 years ago
  RogueException 33861089df Scan base types when searching for serializable props 7 years ago
  RogueException f6c6dbbcad Fixed UserStatus model 7 years ago
  RogueException 10afbb155a Moved StringEnum attribute to enum def 7 years ago
  RogueException 5005ddf98a Added Pool utility class 7 years ago
  RogueException d7fbf9fa20 Added support for strings containing escapes 7 years ago
  RogueException 2381de6bd7 Fixed several serialization errors, added dictionary and array support 7 years ago
  RogueException 016b7fa550 Added support for property selectors and numeric enums 7 years ago
  RogueException 65a2c1e1fd Made DiscordJsonSerializer public 7 years ago
  RogueException e0ce1813a2 Cleaned up Serializers, removed SerializationFormat 7 years ago
  RogueException 894efcca0a Added enum serialization 7 years ago
  RogueException eea11ef8d2 Added image serializer 7 years ago
  RogueException d00aef8982 Replace invalid span usage. 7 years ago
  RogueException ebf12e351d Greatly reduce allocations for float/double/decimal 7 years ago
  RogueException a3e404d8f4 Added serialization support for Utf8String 7 years ago
  RogueException 0bea893076 Improved DateTime(Offset) deserialization 7 years ago
  RogueException 91b4fb3272 Don't allocate strings for property key lookups 7 years ago
  RogueException 9027bcad0c Fixed List serialization 7 years ago
  RogueException d908e01e0e Temp removed char serializer 7 years ago
  RogueException 81f35a6082 Support strings when parsing numbers 7 years ago
  RogueException a1c17856b9 Added serialization support for submodels 7 years ago
  RogueException fed2e94517 Added ExcludeNull support 7 years ago
  RogueException b0147a9126 Added Guid serialization support 7 years ago
  RogueException 1f44306b2e Cleaned csprojs 7 years ago
  RogueException 99d3283d25 Isolated new serialization logic, decoupled from json. 7 years ago
  RogueException 7c25415d32 Removed unused buffers 7 years ago
  RogueException 501c76b2bd Added experimental json serializer 7 years ago
  RogueException c83b1bd321 Abstracted serialization 7 years ago
  RogueException 5714a50b5b Lets try this again 7 years ago
  RogueException c1ad858f9b Avoid GCHandle.IsAllocated 7 years ago
  RogueException 805fa00df0 Pin audio buffers at stream creation 7 years ago
  RogueException f4866e35ce Fix deserialization error from extra data in decompress buffer 7 years ago
  RogueException c56354ff8c Automatically recycle RTPFrame in InputStream.ReadAsync 8 years ago
  RogueException 9224fae4cd Fixed compressed message handling 8 years ago
  RogueException 597092cdaa Fix styling 8 years ago
  RogueException f51e86e736 Reduce voice buffer allocations, add frame recycling 8 years ago
  RogueException 7e62d78160 Bumped version to 1.1.0-alpha 8 years ago
100 changed files with 599 additions and 1010 deletions
Split View
  1. +22
    -4
      Discord.Net.sln
  2. +3
    -2
      Discord.Net.targets
  3. +3
    -3
      src/Discord.Net.Commands/CommandService.cs
  4. +3
    -0
      src/Discord.Net.Core/Audio/IAudioClient.cs
  5. +1
    -1
      src/Discord.Net.Core/Audio/RTPFrame.cs
  6. +7
    -2
      src/Discord.Net.Core/Discord.Net.Core.csproj
  7. +6
    -1
      src/Discord.Net.Core/Entities/Guilds/PermissionTarget.cs
  8. +6
    -2
      src/Discord.Net.Core/Entities/Image.cs
  9. +11
    -8
      src/Discord.Net.Core/Entities/Messages/EmbedType.cs
  10. +3
    -1
      src/Discord.Net.Core/Entities/Permissions/Overwrite.cs
  11. +10
    -1
      src/Discord.Net.Core/Entities/Users/UserStatus.cs
  12. +2
    -2
      src/Discord.Net.Core/Format.cs
  13. +2
    -1
      src/Discord.Net.Core/Net/Rest/IRestClient.cs
  14. +5
    -5
      src/Discord.Net.Core/Net/Rest/RestResponse.cs
  15. +2
    -3
      src/Discord.Net.Core/Net/WebSockets/IWebSocketClient.cs
  16. +13
    -7
      src/Discord.Net.Providers.WS4Net/WS4NetClient.cs
  17. +8
    -8
      src/Discord.Net.Rest/API/Common/Application.cs
  18. +8
    -8
      src/Discord.Net.Rest/API/Common/Attachment.cs
  19. +3
    -3
      src/Discord.Net.Rest/API/Common/Ban.cs
  20. +14
    -14
      src/Discord.Net.Rest/API/Common/Channel.cs
  21. +6
    -6
      src/Discord.Net.Rest/API/Common/Connection.cs
  22. +14
    -15
      src/Discord.Net.Rest/API/Common/Embed.cs
  23. +5
    -5
      src/Discord.Net.Rest/API/Common/EmbedAuthor.cs
  24. +4
    -4
      src/Discord.Net.Rest/API/Common/EmbedField.cs
  25. +4
    -4
      src/Discord.Net.Rest/API/Common/EmbedFooter.cs
  26. +5
    -5
      src/Discord.Net.Rest/API/Common/EmbedImage.cs
  27. +3
    -3
      src/Discord.Net.Rest/API/Common/EmbedProvider.cs
  28. +5
    -5
      src/Discord.Net.Rest/API/Common/EmbedThumbnail.cs
  29. +4
    -4
      src/Discord.Net.Rest/API/Common/EmbedVideo.cs
  30. +6
    -6
      src/Discord.Net.Rest/API/Common/Emoji.cs
  31. +4
    -12
      src/Discord.Net.Rest/API/Common/Game.cs
  32. +18
    -18
      src/Discord.Net.Rest/API/Common/Guild.cs
  33. +3
    -3
      src/Discord.Net.Rest/API/Common/GuildEmbed.cs
  34. +7
    -7
      src/Discord.Net.Rest/API/Common/GuildMember.cs
  35. +12
    -12
      src/Discord.Net.Rest/API/Common/Integration.cs
  36. +3
    -3
      src/Discord.Net.Rest/API/Common/IntegrationAccount.cs
  37. +4
    -4
      src/Discord.Net.Rest/API/Common/Invite.cs
  38. +4
    -4
      src/Discord.Net.Rest/API/Common/InviteChannel.cs
  39. +4
    -4
      src/Discord.Net.Rest/API/Common/InviteGuild.cs
  40. +8
    -8
      src/Discord.Net.Rest/API/Common/InviteMetadata.cs
  41. +17
    -17
      src/Discord.Net.Rest/API/Common/Message.cs
  42. +5
    -5
      src/Discord.Net.Rest/API/Common/Overwrite.cs
  43. +7
    -7
      src/Discord.Net.Rest/API/Common/Presence.cs
  44. +4
    -4
      src/Discord.Net.Rest/API/Common/Reaction.cs
  45. +4
    -4
      src/Discord.Net.Rest/API/Common/ReadState.cs
  46. +4
    -4
      src/Discord.Net.Rest/API/Common/Relationship.cs
  47. +9
    -9
      src/Discord.Net.Rest/API/Common/Role.cs
  48. +9
    -9
      src/Discord.Net.Rest/API/Common/User.cs
  49. +6
    -6
      src/Discord.Net.Rest/API/Common/UserGuild.cs
  50. +7
    -7
      src/Discord.Net.Rest/API/Common/VoiceRegion.cs
  51. +10
    -10
      src/Discord.Net.Rest/API/Common/VoiceState.cs
  52. +4
    -1
      src/Discord.Net.Rest/API/Image.cs
  53. +5
    -6
      src/Discord.Net.Rest/API/Rest/CreateChannelInviteParams.cs
  54. +2
    -3
      src/Discord.Net.Rest/API/Rest/CreateDMChannelParams.cs
  55. +4
    -5
      src/Discord.Net.Rest/API/Rest/CreateGuildChannelParams.cs
  56. +3
    -4
      src/Discord.Net.Rest/API/Rest/CreateGuildIntegrationParams.cs
  57. +4
    -5
      src/Discord.Net.Rest/API/Rest/CreateGuildParams.cs
  58. +5
    -6
      src/Discord.Net.Rest/API/Rest/CreateMessageParams.cs
  59. +7
    -8
      src/Discord.Net.Rest/API/Rest/CreateWebhookMessageParams.cs
  60. +2
    -3
      src/Discord.Net.Rest/API/Rest/DeleteMessagesParams.cs
  61. +3
    -3
      src/Discord.Net.Rest/API/Rest/GetBotGatewayResponse.cs
  62. +2
    -2
      src/Discord.Net.Rest/API/Rest/GetGatewayResponse.cs
  63. +2
    -2
      src/Discord.Net.Rest/API/Rest/GetGuildPruneCountResponse.cs
  64. +2
    -3
      src/Discord.Net.Rest/API/Rest/GuildPruneParams.cs
  65. +4
    -5
      src/Discord.Net.Rest/API/Rest/ModifyChannelPermissionsParams.cs
  66. +2
    -3
      src/Discord.Net.Rest/API/Rest/ModifyCurrentUserNickParams.cs
  67. +3
    -4
      src/Discord.Net.Rest/API/Rest/ModifyCurrentUserParams.cs
  68. +3
    -4
      src/Discord.Net.Rest/API/Rest/ModifyGuildChannelParams.cs
  69. +3
    -4
      src/Discord.Net.Rest/API/Rest/ModifyGuildChannelsParams.cs
  70. +3
    -4
      src/Discord.Net.Rest/API/Rest/ModifyGuildEmbedParams.cs
  71. +4
    -5
      src/Discord.Net.Rest/API/Rest/ModifyGuildIntegrationParams.cs
  72. +6
    -7
      src/Discord.Net.Rest/API/Rest/ModifyGuildMemberParams.cs
  73. +11
    -12
      src/Discord.Net.Rest/API/Rest/ModifyGuildParams.cs
  74. +6
    -7
      src/Discord.Net.Rest/API/Rest/ModifyGuildRoleParams.cs
  75. +3
    -4
      src/Discord.Net.Rest/API/Rest/ModifyGuildRolesParams.cs
  76. +3
    -4
      src/Discord.Net.Rest/API/Rest/ModifyMessageParams.cs
  77. +2
    -3
      src/Discord.Net.Rest/API/Rest/ModifyTextChannelParams.cs
  78. +3
    -4
      src/Discord.Net.Rest/API/Rest/ModifyVoiceChannelParams.cs
  79. +6
    -4
      src/Discord.Net.Rest/BaseDiscordClient.cs
  80. +9
    -0
      src/Discord.Net.Rest/Discord.Net.Rest.csproj
  81. +61
    -51
      src/Discord.Net.Rest/DiscordRestApiClient.cs
  82. +20
    -4
      src/Discord.Net.Rest/DiscordRestClient.cs
  83. +1
    -1
      src/Discord.Net.Rest/Extensions/EntityExtensions.cs
  84. +25
    -0
      src/Discord.Net.Rest/Extensions/StreamExtensions.cs
  85. +0
    -59
      src/Discord.Net.Rest/Net/Converters/ArrayConverter.cs
  86. +0
    -102
      src/Discord.Net.Rest/Net/Converters/DiscordContractResolver.cs
  87. +0
    -36
      src/Discord.Net.Rest/Net/Converters/ImageConverter.cs
  88. +0
    -50
      src/Discord.Net.Rest/Net/Converters/NullableConverter.cs
  89. +0
    -38
      src/Discord.Net.Rest/Net/Converters/OptionalConverter.cs
  90. +0
    -42
      src/Discord.Net.Rest/Net/Converters/PermissionTargetConverter.cs
  91. +0
    -27
      src/Discord.Net.Rest/Net/Converters/StringEntityConverter.cs
  92. +0
    -25
      src/Discord.Net.Rest/Net/Converters/UInt64Converter.cs
  93. +0
    -28
      src/Discord.Net.Rest/Net/Converters/UInt64EntityConverter.cs
  94. +0
    -42
      src/Discord.Net.Rest/Net/Converters/UInt64EntityOrIdConverter.cs
  95. +0
    -58
      src/Discord.Net.Rest/Net/Converters/UserStatusConverter.cs
  96. +8
    -8
      src/Discord.Net.Rest/Net/DefaultRestClient.cs
  97. +1
    -1
      src/Discord.Net.Rest/Net/Queue/RequestQueue.cs
  98. +22
    -16
      src/Discord.Net.Rest/Net/Queue/RequestQueueBucket.cs
  99. +5
    -4
      src/Discord.Net.Rest/Net/Queue/Requests/JsonRestRequest.cs
  100. +3
    -3
      src/Discord.Net.Rest/Net/Queue/Requests/WebSocketRequest.cs

+ 22
- 4
Discord.Net.sln View File

@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26228.4
VisualStudioVersion = 15.0.26711.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Core", "src\Discord.Net.Core\Discord.Net.Core.csproj", "{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}"
EndProject
@@ -14,8 +14,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Commands", "src
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.WebSocket", "src\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj", "{688FD1D8-7F01-4539-B2E9-F473C5D699C7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Providers", "Providers", "{B0657AAE-DCC5-4FBF-8E5D-1FB578CF3012}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Providers.WS4Net", "src\Discord.Net.Providers.WS4Net\Discord.Net.Providers.WS4Net.csproj", "{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions", "Extensions", "{CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}"
@@ -24,6 +22,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Tests", "test\D
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Webhook", "src\Discord.Net.Webhook\Discord.Net.Webhook.csproj", "{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{1876A445-1C70-4F84-912B-4D3CEA21E0C3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Serialization", "src\Discord.Net.Serialization\Discord.Net.Serialization.csproj", "{AA3B67BE-767E-4230-9810-F7948B6AE689}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -130,6 +132,18 @@ Global
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Release|x64.Build.0 = Release|Any CPU
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Release|x86.ActiveCfg = Release|Any CPU
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Release|x86.Build.0 = Release|Any CPU
{AA3B67BE-767E-4230-9810-F7948B6AE689}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AA3B67BE-767E-4230-9810-F7948B6AE689}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AA3B67BE-767E-4230-9810-F7948B6AE689}.Debug|x64.ActiveCfg = Debug|Any CPU
{AA3B67BE-767E-4230-9810-F7948B6AE689}.Debug|x64.Build.0 = Debug|Any CPU
{AA3B67BE-767E-4230-9810-F7948B6AE689}.Debug|x86.ActiveCfg = Debug|Any CPU
{AA3B67BE-767E-4230-9810-F7948B6AE689}.Debug|x86.Build.0 = Debug|Any CPU
{AA3B67BE-767E-4230-9810-F7948B6AE689}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AA3B67BE-767E-4230-9810-F7948B6AE689}.Release|Any CPU.Build.0 = Release|Any CPU
{AA3B67BE-767E-4230-9810-F7948B6AE689}.Release|x64.ActiveCfg = Release|Any CPU
{AA3B67BE-767E-4230-9810-F7948B6AE689}.Release|x64.Build.0 = Release|Any CPU
{AA3B67BE-767E-4230-9810-F7948B6AE689}.Release|x86.ActiveCfg = Release|Any CPU
{AA3B67BE-767E-4230-9810-F7948B6AE689}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -139,7 +153,11 @@ Global
{5688A353-121E-40A1-8BFA-B17B91FB48FB} = {288C363D-A636-4EAE-9AC1-4698B641B26E}
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}
{688FD1D8-7F01-4539-B2E9-F473C5D699C7} = {288C363D-A636-4EAE-9AC1-4698B641B26E}
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7} = {B0657AAE-DCC5-4FBF-8E5D-1FB578CF3012}
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7} = {1876A445-1C70-4F84-912B-4D3CEA21E0C3}
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}
{AA3B67BE-767E-4230-9810-F7948B6AE689} = {1876A445-1C70-4F84-912B-4D3CEA21E0C3}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9828C525-49C7-48F4-A9E7-94E223052DA2}
EndGlobalSection
EndGlobal

+ 3
- 2
Discord.Net.targets View File

@@ -1,7 +1,8 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VersionPrefix>1.0.2</VersionPrefix>
<VersionPrefix>1.1.0-alpha</VersionPrefix>
<VersionSuffix></VersionSuffix>
<LangVersion>latest</LangVersion>
<Authors>RogueException</Authors>
<PackageTags>discord;discordapp</PackageTags>
<PackageProjectUrl>https://github.com/RogueException/Discord.Net</PackageProjectUrl>
@@ -18,7 +19,7 @@
<VersionSuffix Condition=" '$(VersionSuffix)' == '' ">build-$(BuildNumber)</VersionSuffix>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' Or '$(TargetFramework)' == 'net45' ">
<DefineConstants>$(DefineConstants);FILESYSTEM;DEFAULTUDPCLIENT;DEFAULTWEBSOCKET</DefineConstants>
<DefineConstants>$(DefineConstants);FILESYSTEM;DEFAULTUDPCLIENT;DEFAULTWEBSOCKET;MSBUFFER</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
<DefineConstants>$(DefineConstants);FORMATSTR;UNIXTIME;MSTRYBUFFER;UDPDISPOSE</DefineConstants>


+ 3
- 3
src/Discord.Net.Commands/CommandService.cs View File

@@ -309,14 +309,14 @@ namespace Discord.Commands
if (match.Command.Parameters.Count > 0)
{
var argValuesSum = parseResult.ArgValues?.Sum(x => x.Values.OrderByDescending(y => y.Score).FirstOrDefault().Score) ?? 0;
var paramValuesSum = parseResult.ParamValues?.Sum(x => x.Values.OrderByDescending(y => y.Score).FirstOrDefault().Score) ?? 0;
float argValuesSum = parseResult.ArgValues?.Sum(x => x.Values.OrderByDescending(y => y.Score).FirstOrDefault().Score) ?? 0;
float paramValuesSum = parseResult.ParamValues?.Sum(x => x.Values.OrderByDescending(y => y.Score).FirstOrDefault().Score) ?? 0;

argValuesScore = argValuesSum / match.Command.Parameters.Count;
paramValuesScore = paramValuesSum / match.Command.Parameters.Count;
}

var totalArgsScore = (argValuesScore + paramValuesScore) / 2;
float totalArgsScore = (argValuesScore + paramValuesScore) / 2;
return match.Command.Priority + totalArgsScore * 0.99f;
}



+ 3
- 0
src/Discord.Net.Core/Audio/IAudioClient.cs View File

@@ -31,5 +31,8 @@ namespace Discord.Audio
AudioOutStream CreatePCMStream(AudioApplication application, int? bitrate = null, int bufferMillis = 1000, int packetLoss = 30);
/// <summary>Creates a new direct outgoing stream accepting PCM (raw) data. This is a direct stream with no internal timer.</summary>
AudioOutStream CreateDirectPCMStream(AudioApplication application, int? bitrate = null, int packetLoss = 30);
/// <summary>Recycles an RTPFrame's payload buffer. Do not call more than once for a given frame.</summary>
void RecycleFrame(RTPFrame frame);
}
}

+ 1
- 1
src/Discord.Net.Core/Audio/RTPFrame.cs View File

@@ -5,7 +5,7 @@ namespace Discord.Audio
public readonly ushort Sequence;
public readonly uint Timestamp;
public readonly byte[] Payload;
public readonly bool Missed;
public readonly bool Missed;

public RTPFrame(ushort sequence, uint timestamp, byte[] payload, bool missed)
{


+ 7
- 2
src/Discord.Net.Core/Discord.Net.Core.csproj View File

@@ -7,8 +7,13 @@
<TargetFrameworks>net45;netstandard1.1;netstandard1.3</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
<PackageReference Include="System.Collections.Immutable" Version="1.3.1" />
<PackageReference Include="System.Buffers" Version="4.4.0" />
<PackageReference Include="System.Collections.Immutable" Version="1.4.0" />
<PackageReference Include="System.Interactive.Async" Version="3.1.1" />
<PackageReference Include="System.Memory" Version="4.4.0-preview2-25405-01" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Discord.Net.Serialization\Discord.Net.Serialization.csproj" />
</ItemGroup>
</Project>

+ 6
- 1
src/Discord.Net.Core/Entities/Guilds/PermissionTarget.cs View File

@@ -1,8 +1,13 @@
namespace Discord
using Discord.Serialization;

namespace Discord
{
[ModelStringEnum]
public enum PermissionTarget
{
[ModelEnumValue("role")]
Role,
[ModelEnumValue("member")]
User
}
}

+ 6
- 2
src/Discord.Net.Core/Entities/Image.cs View File

@@ -7,13 +7,16 @@ namespace Discord
public struct Image
{
public Stream Stream { get; }
public ImageFormat Format { get; }

/// <summary>
/// Create the image with a Stream.
/// </summary>
/// <param name="stream">This must be some type of stream with the contents of a file in it.</param>
public Image(Stream stream)
public Image(Stream stream, ImageFormat format = ImageFormat.Jpeg)
{
Stream = stream;
Format = format;
}
#if FILESYSTEM
/// <summary>
@@ -23,9 +26,10 @@ namespace Discord
/// This file path is NOT validated, and is passed directly into a <see cref="File.OpenRead(string)"/>
/// </remarks>
/// <param name="path">The path to the file.</param>
public Image(string path)
public Image(string path, ImageFormat format = ImageFormat.Jpeg)
{
Stream = File.OpenRead(path);
Format = format;
}
#endif
}


+ 11
- 8
src/Discord.Net.Core/Entities/Messages/EmbedType.cs View File

@@ -1,13 +1,16 @@
namespace Discord
using Discord.Serialization;

namespace Discord
{
[ModelStringEnum]
public enum EmbedType
{
Rich,
Link,
Video,
Image,
Gifv,
Article,
Tweet
[ModelEnumValue("rich")] Rich,
[ModelEnumValue("link")] Link,
[ModelEnumValue("video")] Video,
[ModelEnumValue("image")] Image,
[ModelEnumValue("gifv")] Gifv,
[ModelEnumValue("article")] Article,
[ModelEnumValue("tweet")] Tweet
}
}

+ 3
- 1
src/Discord.Net.Core/Entities/Permissions/Overwrite.cs View File

@@ -1,4 +1,6 @@
namespace Discord
using Discord.Serialization;

namespace Discord
{
public struct Overwrite
{


+ 10
- 1
src/Discord.Net.Core/Entities/Users/UserStatus.cs View File

@@ -1,12 +1,21 @@
namespace Discord
using Discord.Serialization;

namespace Discord
{
[ModelStringEnum]
public enum UserStatus
{
[ModelEnumValue("offline", EnumValueType.ReadOnly)]
Offline,
[ModelEnumValue("online")]
Online,
[ModelEnumValue("idle")]
Idle,
[ModelEnumValue("idle", EnumValueType.WriteOnly)]
AFK,
[ModelEnumValue("dnd")]
DoNotDisturb,
[ModelEnumValue("invisible", EnumValueType.WriteOnly)]
Invisible,
}
}

+ 2
- 2
src/Discord.Net.Core/Format.cs View File

@@ -3,7 +3,7 @@
public static class Format
{
// Characters which need escaping
private static string[] SensitiveCharacters = { "\\", "*", "_", "~", "`" };
private static string[] _sensitiveCharacters = { "\\", "*", "_", "~", "`" };

/// <summary> Returns a markdown-formatted string with bold formatting. </summary>
public static string Bold(string text) => $"**{text}**";
@@ -26,7 +26,7 @@
/// <summary> Sanitizes the string, safely escaping any Markdown sequences. </summary>
public static string Sanitize(string text)
{
foreach (string unsafeChar in SensitiveCharacters)
foreach (string unsafeChar in _sensitiveCharacters)
text = text.Replace(unsafeChar, $"\\{unsafeChar}");
return text;
}


+ 2
- 1
src/Discord.Net.Core/Net/Rest/IRestClient.cs View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
@@ -10,7 +11,7 @@ namespace Discord.Net.Rest
void SetCancelToken(CancellationToken cancelToken);

Task<RestResponse> SendAsync(string method, string endpoint, CancellationToken cancelToken, bool headerOnly = false, string reason = null);
Task<RestResponse> SendAsync(string method, string endpoint, string json, CancellationToken cancelToken, bool headerOnly = false, string reason = null);
Task<RestResponse> SendAsync(string method, string endpoint, ReadOnlyBuffer<byte> jsonPayload, CancellationToken cancelToken, bool headerOnly = false, string reason = null);
Task<RestResponse> SendAsync(string method, string endpoint, IReadOnlyDictionary<string, object> multipartParams, CancellationToken cancelToken, bool headerOnly = false, string reason = null);
}
}

+ 5
- 5
src/Discord.Net.Core/Net/Rest/RestResponse.cs View File

@@ -1,5 +1,5 @@
using System.Collections.Generic;
using System.IO;
using System;
using System.Collections.Generic;
using System.Net;

namespace Discord.Net.Rest
@@ -8,13 +8,13 @@ namespace Discord.Net.Rest
{
public HttpStatusCode StatusCode { get; }
public Dictionary<string, string> Headers { get; }
public Stream Stream { get; }
public ReadOnlyBuffer<byte> Data { get; }

public RestResponse(HttpStatusCode statusCode, Dictionary<string, string> headers, Stream stream)
public RestResponse(HttpStatusCode statusCode, Dictionary<string, string> headers, ReadOnlyBuffer<byte> data)
{
StatusCode = statusCode;
Headers = headers;
Stream = stream;
Data = data;
}
}
}

+ 2
- 3
src/Discord.Net.Core/Net/WebSockets/IWebSocketClient.cs View File

@@ -6,8 +6,7 @@ namespace Discord.Net.WebSockets
{
public interface IWebSocketClient
{
event Func<byte[], int, int, Task> BinaryMessage;
event Func<string, Task> TextMessage;
event Func<ReadOnlyBuffer<byte>, bool, Task> Message;
event Func<Exception, Task> Closed;

void SetHeader(string key, string value);
@@ -16,6 +15,6 @@ namespace Discord.Net.WebSockets
Task ConnectAsync(string host);
Task DisconnectAsync();

Task SendAsync(byte[] data, int index, int count, bool isText);
Task SendAsync(ReadOnlyBuffer<byte> data, bool isText);
}
}

+ 13
- 7
src/Discord.Net.Providers.WS4Net/WS4NetClient.cs View File

@@ -3,6 +3,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Utf8;
using System.Threading;
using System.Threading.Tasks;
using WebSocket4Net;
@@ -12,8 +13,7 @@ namespace Discord.Net.Providers.WS4Net
{
internal class WS4NetClient : IWebSocketClient, IDisposable
{
public event Func<byte[], int, int, Task> BinaryMessage;
public event Func<string, Task> TextMessage;
public event Func<ReadOnlyBuffer<byte>, bool, Task> Message;
public event Func<Exception, Task> Closed;

private readonly SemaphoreSlim _lock;
@@ -129,15 +129,20 @@ namespace Discord.Net.Providers.WS4Net
_cancelToken = CancellationTokenSource.CreateLinkedTokenSource(_parentToken, _cancelTokenSource.Token).Token;
}

public async Task SendAsync(byte[] data, int index, int count, bool isText)
public async Task SendAsync(ReadOnlyBuffer<byte> data, bool isText)
{
await _lock.WaitAsync(_cancelToken).ConfigureAwait(false);
try
{
if (isText)
_client.Send(Encoding.UTF8.GetString(data, index, count));
_client.Send(new Utf8String(data.Span).ToString());
else
_client.Send(data, index, count);
{
if (data.DangerousTryGetArray(out var array))
_client.Send(array.Array, 0, data.Length);
else
_client.Send(data.ToArray(), 0, data.Length);
}
}
finally
{
@@ -147,11 +152,12 @@ namespace Discord.Net.Providers.WS4Net

private void OnTextMessage(object sender, MessageReceivedEventArgs e)
{
TextMessage(e.Message).GetAwaiter().GetResult();
//TODO: Inefficient, but were dropping this plugin ASAP
Message(new ReadOnlyBuffer<byte>(Encoding.UTF8.GetBytes(e.Message)), true).GetAwaiter().GetResult();
}
private void OnBinaryMessage(object sender, DataReceivedEventArgs e)
{
BinaryMessage(e.Data, 0, e.Data.Count()).GetAwaiter().GetResult();
Message(new ReadOnlyBuffer<byte>(e.Data, 0, e.Data.Count()), false).GetAwaiter().GetResult();
}
private void OnConnected(object sender, object e)
{


+ 8
- 8
src/Discord.Net.Rest/API/Common/Application.cs View File

@@ -1,24 +1,24 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class Application
{
[JsonProperty("description")]
[ModelProperty("description")]
public string Description { get; set; }
[JsonProperty("rpc_origins")]
[ModelProperty("rpc_origins")]
public string[] RPCOrigins { get; set; }
[JsonProperty("name")]
[ModelProperty("name")]
public string Name { get; set; }
[JsonProperty("id")]
[ModelProperty("id")]
public ulong Id { get; set; }
[JsonProperty("icon")]
[ModelProperty("icon")]
public string Icon { get; set; }

[JsonProperty("flags"), Int53]
[ModelProperty("flags"), Int53]
public Optional<ulong> Flags { get; set; }
[JsonProperty("owner")]
[ModelProperty("owner")]
public Optional<User> Owner { get; set; }
}
}

+ 8
- 8
src/Discord.Net.Rest/API/Common/Attachment.cs View File

@@ -1,23 +1,23 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class Attachment
{
[JsonProperty("id")]
[ModelProperty("id")]
public ulong Id { get; set; }
[JsonProperty("filename")]
[ModelProperty("filename")]
public string Filename { get; set; }
[JsonProperty("size")]
[ModelProperty("size")]
public int Size { get; set; }
[JsonProperty("url")]
[ModelProperty("url")]
public string Url { get; set; }
[JsonProperty("proxy_url")]
[ModelProperty("proxy_url")]
public string ProxyUrl { get; set; }
[JsonProperty("height")]
[ModelProperty("height")]
public Optional<int> Height { get; set; }
[JsonProperty("width")]
[ModelProperty("width")]
public Optional<int> Width { get; set; }
}
}

+ 3
- 3
src/Discord.Net.Rest/API/Common/Ban.cs View File

@@ -1,13 +1,13 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class Ban
{
[JsonProperty("user")]
[ModelProperty("user")]
public User User { get; set; }
[JsonProperty("reason")]
[ModelProperty("reason")]
public string Reason { get; set; }
}
}

+ 14
- 14
src/Discord.Net.Rest/API/Common/Channel.cs View File

@@ -1,5 +1,5 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;
using System;

namespace Discord.API
@@ -7,41 +7,41 @@ namespace Discord.API
internal class Channel
{
//Shared
[JsonProperty("id")]
[ModelProperty("id")]
public ulong Id { get; set; }
[JsonProperty("type")]
[ModelProperty("type")]
public ChannelType Type { get; set; }
[JsonProperty("last_message_id")]
[ModelProperty("last_message_id")]
public ulong? LastMessageId { get; set; }

//GuildChannel
[JsonProperty("guild_id")]
[ModelProperty("guild_id")]
public Optional<ulong> GuildId { get; set; }
[JsonProperty("name")]
[ModelProperty("name")]
public Optional<string> Name { get; set; }
[JsonProperty("position")]
[ModelProperty("position")]
public Optional<int> Position { get; set; }
[JsonProperty("permission_overwrites")]
[ModelProperty("permission_overwrites")]
public Optional<Overwrite[]> PermissionOverwrites { get; set; }

//TextChannel
[JsonProperty("topic")]
[ModelProperty("topic")]
public Optional<string> Topic { get; set; }
[JsonProperty("last_pin_timestamp")]
[ModelProperty("last_pin_timestamp")]
public Optional<DateTimeOffset?> LastPinTimestamp { get; set; }

//VoiceChannel
[JsonProperty("bitrate")]
[ModelProperty("bitrate")]
public Optional<int> Bitrate { get; set; }
[JsonProperty("user_limit")]
[ModelProperty("user_limit")]
public Optional<int> UserLimit { get; set; }

//PrivateChannel
[JsonProperty("recipients")]
[ModelProperty("recipients")]
public Optional<User[]> Recipients { get; set; }

//GroupChannel
[JsonProperty("icon")]
[ModelProperty("icon")]
public Optional<string> Icon { get; set; }
}
}

+ 6
- 6
src/Discord.Net.Rest/API/Common/Connection.cs View File

@@ -1,21 +1,21 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;
using System.Collections.Generic;

namespace Discord.API
{
internal class Connection
{
[JsonProperty("id")]
[ModelProperty("id")]
public string Id { get; set; }
[JsonProperty("type")]
[ModelProperty("type")]
public string Type { get; set; }
[JsonProperty("name")]
[ModelProperty("name")]
public string Name { get; set; }
[JsonProperty("revoked")]
[ModelProperty("revoked")]
public bool Revoked { get; set; }

[JsonProperty("integrations")]
[ModelProperty("integrations")]
public IReadOnlyCollection<ulong> Integrations { get; set; }
}
}

+ 14
- 15
src/Discord.Net.Rest/API/Common/Embed.cs View File

@@ -1,37 +1,36 @@
#pragma warning disable CS1591
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Discord.Serialization;

namespace Discord.API
{
internal class Embed
{
[JsonProperty("title")]
[ModelProperty("title")]
public string Title { get; set; }
[JsonProperty("description")]
[ModelProperty("description")]
public string Description { get; set; }
[JsonProperty("url")]
[ModelProperty("url")]
public string Url { get; set; }
[JsonProperty("color")]
[ModelProperty("color")]
public uint? Color { get; set; }
[JsonProperty("type"), JsonConverter(typeof(StringEnumConverter))]
[ModelProperty("type")]
public EmbedType Type { get; set; }
[JsonProperty("timestamp")]
[ModelProperty("timestamp")]
public DateTimeOffset? Timestamp { get; set; }
[JsonProperty("author")]
[ModelProperty("author")]
public Optional<EmbedAuthor> Author { get; set; }
[JsonProperty("footer")]
[ModelProperty("footer")]
public Optional<EmbedFooter> Footer { get; set; }
[JsonProperty("video")]
[ModelProperty("video")]
public Optional<EmbedVideo> Video { get; set; }
[JsonProperty("thumbnail")]
[ModelProperty("thumbnail")]
public Optional<EmbedThumbnail> Thumbnail { get; set; }
[JsonProperty("image")]
[ModelProperty("image")]
public Optional<EmbedImage> Image { get; set; }
[JsonProperty("provider")]
[ModelProperty("provider")]
public Optional<EmbedProvider> Provider { get; set; }
[JsonProperty("fields")]
[ModelProperty("fields")]
public Optional<EmbedField[]> Fields { get; set; }
}
}

+ 5
- 5
src/Discord.Net.Rest/API/Common/EmbedAuthor.cs View File

@@ -1,17 +1,17 @@
using System;
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class EmbedAuthor
{
[JsonProperty("name")]
[ModelProperty("name")]
public string Name { get; set; }
[JsonProperty("url")]
[ModelProperty("url")]
public string Url { get; set; }
[JsonProperty("icon_url")]
[ModelProperty("icon_url")]
public string IconUrl { get; set; }
[JsonProperty("proxy_icon_url")]
[ModelProperty("proxy_icon_url")]
public string ProxyIconUrl { get; set; }
}
}

+ 4
- 4
src/Discord.Net.Rest/API/Common/EmbedField.cs View File

@@ -1,14 +1,14 @@
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class EmbedField
{
[JsonProperty("name")]
[ModelProperty("name")]
public string Name { get; set; }
[JsonProperty("value")]
[ModelProperty("value")]
public string Value { get; set; }
[JsonProperty("inline")]
[ModelProperty("inline")]
public bool Inline { get; set; }
}
}

+ 4
- 4
src/Discord.Net.Rest/API/Common/EmbedFooter.cs View File

@@ -1,15 +1,15 @@
using System;
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class EmbedFooter
{
[JsonProperty("text")]
[ModelProperty("text")]
public string Text { get; set; }
[JsonProperty("icon_url")]
[ModelProperty("icon_url")]
public string IconUrl { get; set; }
[JsonProperty("proxy_icon_url")]
[ModelProperty("proxy_icon_url")]
public string ProxyIconUrl { get; set; }
}
}

+ 5
- 5
src/Discord.Net.Rest/API/Common/EmbedImage.cs View File

@@ -1,18 +1,18 @@
#pragma warning disable CS1591
using System;
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class EmbedImage
{
[JsonProperty("url")]
[ModelProperty("url")]
public string Url { get; set; }
[JsonProperty("proxy_url")]
[ModelProperty("proxy_url")]
public string ProxyUrl { get; set; }
[JsonProperty("height")]
[ModelProperty("height")]
public Optional<int> Height { get; set; }
[JsonProperty("width")]
[ModelProperty("width")]
public Optional<int> Width { get; set; }
}
}

+ 3
- 3
src/Discord.Net.Rest/API/Common/EmbedProvider.cs View File

@@ -1,14 +1,14 @@
#pragma warning disable CS1591
using System;
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class EmbedProvider
{
[JsonProperty("name")]
[ModelProperty("name")]
public string Name { get; set; }
[JsonProperty("url")]
[ModelProperty("url")]
public string Url { get; set; }
}
}

+ 5
- 5
src/Discord.Net.Rest/API/Common/EmbedThumbnail.cs View File

@@ -1,18 +1,18 @@
#pragma warning disable CS1591
using System;
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class EmbedThumbnail
{
[JsonProperty("url")]
[ModelProperty("url")]
public string Url { get; set; }
[JsonProperty("proxy_url")]
[ModelProperty("proxy_url")]
public string ProxyUrl { get; set; }
[JsonProperty("height")]
[ModelProperty("height")]
public Optional<int> Height { get; set; }
[JsonProperty("width")]
[ModelProperty("width")]
public Optional<int> Width { get; set; }
}
}

+ 4
- 4
src/Discord.Net.Rest/API/Common/EmbedVideo.cs View File

@@ -1,16 +1,16 @@
#pragma warning disable CS1591
using System;
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class EmbedVideo
{
[JsonProperty("url")]
[ModelProperty("url")]
public string Url { get; set; }
[JsonProperty("height")]
[ModelProperty("height")]
public Optional<int> Height { get; set; }
[JsonProperty("width")]
[ModelProperty("width")]
public Optional<int> Width { get; set; }
}
}

+ 6
- 6
src/Discord.Net.Rest/API/Common/Emoji.cs View File

@@ -1,19 +1,19 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class Emoji
{
[JsonProperty("id")]
[ModelProperty("id")]
public ulong? Id { get; set; }
[JsonProperty("name")]
[ModelProperty("name")]
public string Name { get; set; }
[JsonProperty("roles")]
[ModelProperty("roles")]
public ulong[] Roles { get; set; }
[JsonProperty("require_colons")]
[ModelProperty("require_colons")]
public bool RequireColons { get; set; }
[JsonProperty("managed")]
[ModelProperty("managed")]
public bool Managed { get; set; }
}
}

+ 4
- 12
src/Discord.Net.Rest/API/Common/Game.cs View File

@@ -1,23 +1,15 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Runtime.Serialization;
using Discord.Serialization;

namespace Discord.API
{
internal class Game
{
[JsonProperty("name")]
[ModelProperty("name")]
public string Name { get; set; }
[JsonProperty("url")]
[ModelProperty("url")]
public Optional<string> StreamUrl { get; set; }
[JsonProperty("type")]
[ModelProperty("type")]
public Optional<StreamType?> StreamType { get; set; }

[OnError]
internal void OnError(StreamingContext context, ErrorContext errorContext)
{
errorContext.Handled = true;
}
}
}

+ 18
- 18
src/Discord.Net.Rest/API/Common/Guild.cs View File

@@ -1,43 +1,43 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class Guild
{
[JsonProperty("id")]
[ModelProperty("id")]
public ulong Id { get; set; }
[JsonProperty("name")]
[ModelProperty("name")]
public string Name { get; set; }
[JsonProperty("icon")]
[ModelProperty("icon")]
public string Icon { get; set; }
[JsonProperty("splash")]
[ModelProperty("splash")]
public string Splash { get; set; }
[JsonProperty("owner_id")]
[ModelProperty("owner_id")]
public ulong OwnerId { get; set; }
[JsonProperty("region")]
[ModelProperty("region")]
public string Region { get; set; }
[JsonProperty("afk_channel_id")]
[ModelProperty("afk_channel_id")]
public ulong? AFKChannelId { get; set; }
[JsonProperty("afk_timeout")]
[ModelProperty("afk_timeout")]
public int AFKTimeout { get; set; }
[JsonProperty("embed_enabled")]
[ModelProperty("embed_enabled")]
public bool EmbedEnabled { get; set; }
[JsonProperty("embed_channel_id")]
[ModelProperty("embed_channel_id")]
public ulong? EmbedChannelId { get; set; }
[JsonProperty("verification_level")]
[ModelProperty("verification_level")]
public VerificationLevel VerificationLevel { get; set; }
[JsonProperty("voice_states")]
[ModelProperty("voice_states")]
public VoiceState[] VoiceStates { get; set; }
[JsonProperty("roles")]
[ModelProperty("roles")]
public Role[] Roles { get; set; }
[JsonProperty("emojis")]
[ModelProperty("emojis")]
public Emoji[] Emojis { get; set; }
[JsonProperty("features")]
[ModelProperty("features")]
public string[] Features { get; set; }
[JsonProperty("mfa_level")]
[ModelProperty("mfa_level")]
public MfaLevel MfaLevel { get; set; }
[JsonProperty("default_message_notifications")]
[ModelProperty("default_message_notifications")]
public DefaultMessageNotifications DefaultMessageNotifications { get; set; }
}
}

+ 3
- 3
src/Discord.Net.Rest/API/Common/GuildEmbed.cs View File

@@ -1,13 +1,13 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class GuildEmbed
{
[JsonProperty("enabled")]
[ModelProperty("enabled")]
public bool Enabled { get; set; }
[JsonProperty("channel_id")]
[ModelProperty("channel_id")]
public ulong ChannelId { get; set; }
}
}

+ 7
- 7
src/Discord.Net.Rest/API/Common/GuildMember.cs View File

@@ -1,22 +1,22 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;
using System;

namespace Discord.API
{
internal class GuildMember
{
[JsonProperty("user")]
[ModelProperty("user")]
public User User { get; set; }
[JsonProperty("nick")]
[ModelProperty("nick")]
public Optional<string> Nick { get; set; }
[JsonProperty("roles")]
[ModelProperty("roles")]
public Optional<ulong[]> Roles { get; set; }
[JsonProperty("joined_at")]
[ModelProperty("joined_at")]
public Optional<DateTimeOffset> JoinedAt { get; set; }
[JsonProperty("deaf")]
[ModelProperty("deaf")]
public Optional<bool> Deaf { get; set; }
[JsonProperty("mute")]
[ModelProperty("mute")]
public Optional<bool> Mute { get; set; }
}
}

+ 12
- 12
src/Discord.Net.Rest/API/Common/Integration.cs View File

@@ -1,32 +1,32 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;
using System;

namespace Discord.API
{
internal class Integration
{
[JsonProperty("id")]
[ModelProperty("id")]
public ulong Id { get; set; }
[JsonProperty("name")]
[ModelProperty("name")]
public string Name { get; set; }
[JsonProperty("type")]
[ModelProperty("type")]
public string Type { get; set; }
[JsonProperty("enabled")]
[ModelProperty("enabled")]
public bool Enabled { get; set; }
[JsonProperty("syncing")]
[ModelProperty("syncing")]
public bool Syncing { get; set; }
[JsonProperty("role_id")]
[ModelProperty("role_id")]
public ulong RoleId { get; set; }
[JsonProperty("expire_behavior")]
[ModelProperty("expire_behavior")]
public ulong ExpireBehavior { get; set; }
[JsonProperty("expire_grace_period")]
[ModelProperty("expire_grace_period")]
public ulong ExpireGracePeriod { get; set; }
[JsonProperty("user")]
[ModelProperty("user")]
public User User { get; set; }
[JsonProperty("account")]
[ModelProperty("account")]
public IntegrationAccount Account { get; set; }
[JsonProperty("synced_at")]
[ModelProperty("synced_at")]
public DateTimeOffset SyncedAt { get; set; }
}
}

+ 3
- 3
src/Discord.Net.Rest/API/Common/IntegrationAccount.cs View File

@@ -1,13 +1,13 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class IntegrationAccount
{
[JsonProperty("id")]
[ModelProperty("id")]
public ulong Id { get; set; }
[JsonProperty("name")]
[ModelProperty("name")]
public string Name { get; set; }
}
}

+ 4
- 4
src/Discord.Net.Rest/API/Common/Invite.cs View File

@@ -1,15 +1,15 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class Invite
{
[JsonProperty("code")]
[ModelProperty("code")]
public string Code { get; set; }
[JsonProperty("guild")]
[ModelProperty("guild")]
public InviteGuild Guild { get; set; }
[JsonProperty("channel")]
[ModelProperty("channel")]
public InviteChannel Channel { get; set; }
}
}

+ 4
- 4
src/Discord.Net.Rest/API/Common/InviteChannel.cs View File

@@ -1,15 +1,15 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class InviteChannel
{
[JsonProperty("id")]
[ModelProperty("id")]
public ulong Id { get; set; }
[JsonProperty("name")]
[ModelProperty("name")]
public string Name { get; set; }
[JsonProperty("type")]
[ModelProperty("type")]
public string Type { get; set; }
}
}

+ 4
- 4
src/Discord.Net.Rest/API/Common/InviteGuild.cs View File

@@ -1,15 +1,15 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class InviteGuild
{
[JsonProperty("id")]
[ModelProperty("id")]
public ulong Id { get; set; }
[JsonProperty("name")]
[ModelProperty("name")]
public string Name { get; set; }
[JsonProperty("splash_hash")]
[ModelProperty("splash_hash")]
public string SplashHash { get; set; }
}
}

+ 8
- 8
src/Discord.Net.Rest/API/Common/InviteMetadata.cs View File

@@ -1,24 +1,24 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;
using System;

namespace Discord.API
{
internal class InviteMetadata : Invite
{
[JsonProperty("inviter")]
[ModelProperty("inviter")]
public User Inviter { get; set; }
[JsonProperty("uses")]
[ModelProperty("uses")]
public int Uses { get; set; }
[JsonProperty("max_uses")]
[ModelProperty("max_uses")]
public int MaxUses { get; set; }
[JsonProperty("max_age")]
[ModelProperty("max_age")]
public int MaxAge { get; set; }
[JsonProperty("temporary")]
[ModelProperty("temporary")]
public bool Temporary { get; set; }
[JsonProperty("created_at")]
[ModelProperty("created_at")]
public DateTimeOffset CreatedAt { get; set; }
[JsonProperty("revoked")]
[ModelProperty("revoked")]
public bool Revoked { get; set; }
}
}

+ 17
- 17
src/Discord.Net.Rest/API/Common/Message.cs View File

@@ -1,42 +1,42 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;
using System;

namespace Discord.API
{
internal class Message
{
[JsonProperty("id")]
[ModelProperty("id")]
public ulong Id { get; set; }
[JsonProperty("type")]
[ModelProperty("type")]
public MessageType Type { get; set; }
[JsonProperty("channel_id")]
[ModelProperty("channel_id")]
public ulong ChannelId { get; set; }
[JsonProperty("webhook_id")]
[ModelProperty("webhook_id")]
public Optional<ulong> WebhookId { get; set; }
[JsonProperty("author")]
[ModelProperty("author")]
public Optional<User> Author { get; set; }
[JsonProperty("content")]
[ModelProperty("content")]
public Optional<string> Content { get; set; }
[JsonProperty("timestamp")]
[ModelProperty("timestamp")]
public Optional<DateTimeOffset> Timestamp { get; set; }
[JsonProperty("edited_timestamp")]
[ModelProperty("edited_timestamp")]
public Optional<DateTimeOffset?> EditedTimestamp { get; set; }
[JsonProperty("tts")]
[ModelProperty("tts")]
public Optional<bool> IsTextToSpeech { get; set; }
[JsonProperty("mention_everyone")]
[ModelProperty("mention_everyone")]
public Optional<bool> MentionEveryone { get; set; }
[JsonProperty("mentions")]
[ModelProperty("mentions")]
public Optional<EntityOrId<User>[]> UserMentions { get; set; }
[JsonProperty("mention_roles")]
[ModelProperty("mention_roles")]
public Optional<ulong[]> RoleMentions { get; set; }
[JsonProperty("attachments")]
[ModelProperty("attachments")]
public Optional<Attachment[]> Attachments { get; set; }
[JsonProperty("embeds")]
[ModelProperty("embeds")]
public Optional<Embed[]> Embeds { get; set; }
[JsonProperty("pinned")]
[ModelProperty("pinned")]
public Optional<bool> Pinned { get; set; }
[JsonProperty("reactions")]
[ModelProperty("reactions")]
public Optional<Reaction[]> Reactions { get; set; }
}
}

+ 5
- 5
src/Discord.Net.Rest/API/Common/Overwrite.cs View File

@@ -1,17 +1,17 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class Overwrite
{
[JsonProperty("id")]
[ModelProperty("id")]
public ulong TargetId { get; set; }
[JsonProperty("type")]
[ModelProperty("type")]
public PermissionTarget TargetType { get; set; }
[JsonProperty("deny"), Int53]
[ModelProperty("deny"), Int53]
public ulong Deny { get; set; }
[JsonProperty("allow"), Int53]
[ModelProperty("allow"), Int53]
public ulong Allow { get; set; }
}
}

+ 7
- 7
src/Discord.Net.Rest/API/Common/Presence.cs View File

@@ -1,22 +1,22 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class Presence
{
[JsonProperty("user")]
[ModelProperty("user")]
public User User { get; set; }
[JsonProperty("guild_id")]
[ModelProperty("guild_id")]
public Optional<ulong> GuildId { get; set; }
[JsonProperty("status")]
[ModelProperty("status")]
public UserStatus Status { get; set; }
[JsonProperty("game")]
[ModelProperty("game")]
public Game Game { get; set; }

[JsonProperty("roles")]
[ModelProperty("roles")]
public Optional<ulong[]> Roles { get; set; }
[JsonProperty("nick")]
[ModelProperty("nick")]
public Optional<string> Nick { get; set; }
}
}

+ 4
- 4
src/Discord.Net.Rest/API/Common/Reaction.cs View File

@@ -1,14 +1,14 @@
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class Reaction
{
[JsonProperty("count")]
[ModelProperty("count")]
public int Count { get; set; }
[JsonProperty("me")]
[ModelProperty("me")]
public bool Me { get; set; }
[JsonProperty("emoji")]
[ModelProperty("emoji")]
public Emoji Emoji { get; set; }
}
}

+ 4
- 4
src/Discord.Net.Rest/API/Common/ReadState.cs View File

@@ -1,15 +1,15 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class ReadState
{
[JsonProperty("id")]
[ModelProperty("id")]
public ulong Id { get; set; }
[JsonProperty("mention_count")]
[ModelProperty("mention_count")]
public int MentionCount { get; set; }
[JsonProperty("last_message_id")]
[ModelProperty("last_message_id")]
public Optional<ulong> LastMessageId { get; set; }
}
}

+ 4
- 4
src/Discord.Net.Rest/API/Common/Relationship.cs View File

@@ -1,15 +1,15 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class Relationship
{
[JsonProperty("id")]
[ModelProperty("id")]
public ulong Id { get; set; }
[JsonProperty("user")]
[ModelProperty("user")]
public User User { get; set; }
[JsonProperty("type")]
[ModelProperty("type")]
public RelationshipType Type { get; set; }
}
}

+ 9
- 9
src/Discord.Net.Rest/API/Common/Role.cs View File

@@ -1,25 +1,25 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class Role
{
[JsonProperty("id")]
[ModelProperty("id")]
public ulong Id { get; set; }
[JsonProperty("name")]
[ModelProperty("name")]
public string Name { get; set; }
[JsonProperty("color")]
[ModelProperty("color")]
public uint Color { get; set; }
[JsonProperty("hoist")]
[ModelProperty("hoist")]
public bool Hoist { get; set; }
[JsonProperty("mentionable")]
[ModelProperty("mentionable")]
public bool Mentionable { get; set; }
[JsonProperty("position")]
[ModelProperty("position")]
public int Position { get; set; }
[JsonProperty("permissions"), Int53]
[ModelProperty("permissions"), Int53]
public ulong Permissions { get; set; }
[JsonProperty("managed")]
[ModelProperty("managed")]
public bool Managed { get; set; }
}
}

+ 9
- 9
src/Discord.Net.Rest/API/Common/User.cs View File

@@ -1,27 +1,27 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class User
{
[JsonProperty("id")]
[ModelProperty("id")]
public ulong Id { get; set; }
[JsonProperty("username")]
[ModelProperty("username")]
public Optional<string> Username { get; set; }
[JsonProperty("discriminator")]
[ModelProperty("discriminator")]
public Optional<string> Discriminator { get; set; }
[JsonProperty("bot")]
[ModelProperty("bot")]
public Optional<bool> Bot { get; set; }
[JsonProperty("avatar")]
[ModelProperty("avatar")]
public Optional<string> Avatar { get; set; }

//CurrentUser
[JsonProperty("verified")]
[ModelProperty("verified")]
public Optional<bool> Verified { get; set; }
[JsonProperty("email")]
[ModelProperty("email")]
public Optional<string> Email { get; set; }
[JsonProperty("mfa_enabled")]
[ModelProperty("mfa_enabled")]
public Optional<bool> MfaEnabled { get; set; }
}
}

+ 6
- 6
src/Discord.Net.Rest/API/Common/UserGuild.cs View File

@@ -1,19 +1,19 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class UserGuild
{
[JsonProperty("id")]
[ModelProperty("id")]
public ulong Id { get; set; }
[JsonProperty("name")]
[ModelProperty("name")]
public string Name { get; set; }
[JsonProperty("icon")]
[ModelProperty("icon")]
public string Icon { get; set; }
[JsonProperty("owner")]
[ModelProperty("owner")]
public bool Owner { get; set; }
[JsonProperty("permissions"), Int53]
[ModelProperty("permissions"), Int53]
public ulong Permissions { get; set; }
}
}

+ 7
- 7
src/Discord.Net.Rest/API/Common/VoiceRegion.cs View File

@@ -1,21 +1,21 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class VoiceRegion
{
[JsonProperty("id")]
[ModelProperty("id")]
public string Id { get; set; }
[JsonProperty("name")]
[ModelProperty("name")]
public string Name { get; set; }
[JsonProperty("vip")]
[ModelProperty("vip")]
public bool IsVip { get; set; }
[JsonProperty("optimal")]
[ModelProperty("optimal")]
public bool IsOptimal { get; set; }
[JsonProperty("sample_hostname")]
[ModelProperty("sample_hostname")]
public string SampleHostname { get; set; }
[JsonProperty("sample_port")]
[ModelProperty("sample_port")]
public int SamplePort { get; set; }
}
}

+ 10
- 10
src/Discord.Net.Rest/API/Common/VoiceState.cs View File

@@ -1,27 +1,27 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API
{
internal class VoiceState
{
[JsonProperty("guild_id")]
[ModelProperty("guild_id")]
public ulong? GuildId { get; set; }
[JsonProperty("channel_id")]
[ModelProperty("channel_id")]
public ulong? ChannelId { get; set; }
[JsonProperty("user_id")]
[ModelProperty("user_id")]
public ulong UserId { get; set; }
[JsonProperty("session_id")]
[ModelProperty("session_id")]
public string SessionId { get; set; }
[JsonProperty("deaf")]
[ModelProperty("deaf")]
public bool Deaf { get; set; }
[JsonProperty("mute")]
[ModelProperty("mute")]
public bool Mute { get; set; }
[JsonProperty("self_deaf")]
[ModelProperty("self_deaf")]
public bool SelfDeaf { get; set; }
[JsonProperty("self_mute")]
[ModelProperty("self_mute")]
public bool SelfMute { get; set; }
[JsonProperty("suppress")]
[ModelProperty("suppress")]
public bool Suppress { get; set; }
}
}

+ 4
- 1
src/Discord.Net.Rest/API/Image.cs View File

@@ -5,16 +5,19 @@ namespace Discord.API
internal struct Image
{
public Stream Stream { get; }
public ImageFormat StreamFormat { get; }
public string Hash { get; }

public Image(Stream stream)
public Image(Stream stream, ImageFormat format)
{
Stream = stream;
StreamFormat = format;
Hash = null;
}
public Image(string hash)
{
Stream = null;
StreamFormat = ImageFormat.Jpeg;
Hash = hash;
}
}


+ 5
- 6
src/Discord.Net.Rest/API/Rest/CreateChannelInviteParams.cs View File

@@ -1,18 +1,17 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class CreateChannelInviteParams
{
[JsonProperty("max_age")]
[ModelProperty("max_age")]
public Optional<int> MaxAge { get; set; }
[JsonProperty("max_uses")]
[ModelProperty("max_uses")]
public Optional<int> MaxUses { get; set; }
[JsonProperty("temporary")]
[ModelProperty("temporary")]
public Optional<bool> IsTemporary { get; set; }
[JsonProperty("unique")]
[ModelProperty("unique")]
public Optional<bool> IsUnique { get; set; }
}
}

+ 2
- 3
src/Discord.Net.Rest/API/Rest/CreateDMChannelParams.cs View File

@@ -1,12 +1,11 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class CreateDMChannelParams
{
[JsonProperty("recipient_id")]
[ModelProperty("recipient_id")]
public ulong RecipientId { get; }

public CreateDMChannelParams(ulong recipientId)


+ 4
- 5
src/Discord.Net.Rest/API/Rest/CreateGuildChannelParams.cs View File

@@ -1,17 +1,16 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class CreateGuildChannelParams
{
[JsonProperty("name")]
[ModelProperty("name")]
public string Name { get; }
[JsonProperty("type")]
[ModelProperty("type")]
public ChannelType Type { get; }

[JsonProperty("bitrate")]
[ModelProperty("bitrate")]
public Optional<int> Bitrate { get; set; }

public CreateGuildChannelParams(string name, ChannelType type)


+ 3
- 4
src/Discord.Net.Rest/API/Rest/CreateGuildIntegrationParams.cs View File

@@ -1,14 +1,13 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class CreateGuildIntegrationParams
{
[JsonProperty("id")]
[ModelProperty("id")]
public ulong Id { get; }
[JsonProperty("type")]
[ModelProperty("type")]
public string Type { get; }

public CreateGuildIntegrationParams(ulong id, string type)


+ 4
- 5
src/Discord.Net.Rest/API/Rest/CreateGuildParams.cs View File

@@ -1,17 +1,16 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class CreateGuildParams
{
[JsonProperty("name")]
[ModelProperty("name")]
public string Name { get; }
[JsonProperty("region")]
[ModelProperty("region")]
public string RegionId { get; }

[JsonProperty("icon")]
[ModelProperty("icon")]
public Optional<Image?> Icon { get; set; }

public CreateGuildParams(string name, string regionId)


+ 5
- 6
src/Discord.Net.Rest/API/Rest/CreateMessageParams.cs View File

@@ -1,19 +1,18 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class CreateMessageParams
{
[JsonProperty("content")]
[ModelProperty("content")]
public string Content { get; }

[JsonProperty("nonce")]
[ModelProperty("nonce")]
public Optional<string> Nonce { get; set; }
[JsonProperty("tts")]
[ModelProperty("tts")]
public Optional<bool> IsTTS { get; set; }
[JsonProperty("embed")]
[ModelProperty("embed")]
public Optional<Embed> Embed { get; set; }

public CreateMessageParams(string content)


+ 7
- 8
src/Discord.Net.Rest/API/Rest/CreateWebhookMessageParams.cs View File

@@ -1,23 +1,22 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class CreateWebhookMessageParams
{
[JsonProperty("content")]
[ModelProperty("content")]
public string Content { get; }

[JsonProperty("nonce")]
[ModelProperty("nonce")]
public Optional<string> Nonce { get; set; }
[JsonProperty("tts")]
[ModelProperty("tts")]
public Optional<bool> IsTTS { get; set; }
[JsonProperty("embeds")]
[ModelProperty("embeds")]
public Optional<Embed[]> Embeds { get; set; }
[JsonProperty("username")]
[ModelProperty("username")]
public Optional<string> Username { get; set; }
[JsonProperty("avatar_url")]
[ModelProperty("avatar_url")]
public Optional<string> AvatarUrl { get; set; }

public CreateWebhookMessageParams(string content)


+ 2
- 3
src/Discord.Net.Rest/API/Rest/DeleteMessagesParams.cs View File

@@ -1,12 +1,11 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class DeleteMessagesParams
{
[JsonProperty("messages")]
[ModelProperty("messages")]
public ulong[] MessageIds { get; }

public DeleteMessagesParams(ulong[] messageIds)


+ 3
- 3
src/Discord.Net.Rest/API/Rest/GetBotGatewayResponse.cs View File

@@ -1,13 +1,13 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
internal class GetBotGatewayResponse
{
[JsonProperty("url")]
[ModelProperty("url")]
public string Url { get; set; }
[JsonProperty("shards")]
[ModelProperty("shards")]
public int Shards { get; set; }
}
}

+ 2
- 2
src/Discord.Net.Rest/API/Rest/GetGatewayResponse.cs View File

@@ -1,11 +1,11 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
internal class GetGatewayResponse
{
[JsonProperty("url")]
[ModelProperty("url")]
public string Url { get; set; }
}
}

+ 2
- 2
src/Discord.Net.Rest/API/Rest/GetGuildPruneCountResponse.cs View File

@@ -1,11 +1,11 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
internal class GetGuildPruneCountResponse
{
[JsonProperty("pruned")]
[ModelProperty("pruned")]
public int Pruned { get; set; }
}
}

+ 2
- 3
src/Discord.Net.Rest/API/Rest/GuildPruneParams.cs View File

@@ -1,12 +1,11 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class GuildPruneParams
{
[JsonProperty("days")]
[ModelProperty("days")]
public int Days { get; }

public GuildPruneParams(int days)


+ 4
- 5
src/Discord.Net.Rest/API/Rest/ModifyChannelPermissionsParams.cs View File

@@ -1,16 +1,15 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class ModifyChannelPermissionsParams
{
[JsonProperty("type")]
[ModelProperty("type")]
public string Type { get; }
[JsonProperty("allow")]
[ModelProperty("allow")]
public ulong Allow { get; }
[JsonProperty("deny")]
[ModelProperty("deny")]
public ulong Deny { get; }

public ModifyChannelPermissionsParams(string type, ulong allow, ulong deny)


+ 2
- 3
src/Discord.Net.Rest/API/Rest/ModifyCurrentUserNickParams.cs View File

@@ -1,12 +1,11 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class ModifyCurrentUserNickParams
{
[JsonProperty("nick")]
[ModelProperty("nick")]
public string Nickname { get; }

public ModifyCurrentUserNickParams(string nickname)


+ 3
- 4
src/Discord.Net.Rest/API/Rest/ModifyCurrentUserParams.cs View File

@@ -1,14 +1,13 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class ModifyCurrentUserParams
{
[JsonProperty("username")]
[ModelProperty("username")]
public Optional<string> Username { get; set; }
[JsonProperty("avatar")]
[ModelProperty("avatar")]
public Optional<Image?> Avatar { get; set; }
}
}

+ 3
- 4
src/Discord.Net.Rest/API/Rest/ModifyGuildChannelParams.cs View File

@@ -1,14 +1,13 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class ModifyGuildChannelParams
{
[JsonProperty("name")]
[ModelProperty("name")]
public Optional<string> Name { get; set; }
[JsonProperty("position")]
[ModelProperty("position")]
public Optional<int> Position { get; set; }
}
}

+ 3
- 4
src/Discord.Net.Rest/API/Rest/ModifyGuildChannelsParams.cs View File

@@ -1,14 +1,13 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class ModifyGuildChannelsParams
{
[JsonProperty("id")]
[ModelProperty("id")]
public ulong Id { get; }
[JsonProperty("position")]
[ModelProperty("position")]
public int Position { get; }

public ModifyGuildChannelsParams(ulong id, int position)


+ 3
- 4
src/Discord.Net.Rest/API/Rest/ModifyGuildEmbedParams.cs View File

@@ -1,14 +1,13 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class ModifyGuildEmbedParams
{
[JsonProperty("enabled")]
[ModelProperty("enabled")]
public Optional<bool> Enabled { get; set; }
[JsonProperty("channel")]
[ModelProperty("channel")]
public Optional<ulong?> ChannelId { get; set; }
}
}

+ 4
- 5
src/Discord.Net.Rest/API/Rest/ModifyGuildIntegrationParams.cs View File

@@ -1,16 +1,15 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class ModifyGuildIntegrationParams
{
[JsonProperty("expire_behavior")]
[ModelProperty("expire_behavior")]
public Optional<int> ExpireBehavior { get; set; }
[JsonProperty("expire_grace_period")]
[ModelProperty("expire_grace_period")]
public Optional<int> ExpireGracePeriod { get; set; }
[JsonProperty("enable_emoticons")]
[ModelProperty("enable_emoticons")]
public Optional<bool> EnableEmoticons { get; set; }
}
}

+ 6
- 7
src/Discord.Net.Rest/API/Rest/ModifyGuildMemberParams.cs View File

@@ -1,20 +1,19 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class ModifyGuildMemberParams
{
[JsonProperty("mute")]
[ModelProperty("mute")]
public Optional<bool> Mute { get; set; }
[JsonProperty("deaf")]
[ModelProperty("deaf")]
public Optional<bool> Deaf { get; set; }
[JsonProperty("nick")]
[ModelProperty("nick")]
public Optional<string> Nickname { get; set; }
[JsonProperty("roles")]
[ModelProperty("roles")]
public Optional<ulong[]> RoleIds { get; set; }
[JsonProperty("channel_id")]
[ModelProperty("channel_id")]
public Optional<ulong> ChannelId { get; set; }
}
}

+ 11
- 12
src/Discord.Net.Rest/API/Rest/ModifyGuildParams.cs View File

@@ -1,30 +1,29 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class ModifyGuildParams
{
[JsonProperty("username")]
[ModelProperty("username")]
public Optional<string> Username { get; set; }
[JsonProperty("name")]
[ModelProperty("name")]
public Optional<string> Name { get; set; }
[JsonProperty("region")]
[ModelProperty("region")]
public Optional<string> RegionId { get; set; }
[JsonProperty("verification_level")]
[ModelProperty("verification_level")]
public Optional<VerificationLevel> VerificationLevel { get; set; }
[JsonProperty("default_message_notifications")]
[ModelProperty("default_message_notifications")]
public Optional<DefaultMessageNotifications> DefaultMessageNotifications { get; set; }
[JsonProperty("afk_timeout")]
[ModelProperty("afk_timeout")]
public Optional<int> AfkTimeout { get; set; }
[JsonProperty("icon")]
[ModelProperty("icon")]
public Optional<Image?> Icon { get; set; }
[JsonProperty("splash")]
[ModelProperty("splash")]
public Optional<Image?> Splash { get; set; }
[JsonProperty("afk_channel_id")]
[ModelProperty("afk_channel_id")]
public Optional<ulong?> AfkChannelId { get; set; }
[JsonProperty("owner_id")]
[ModelProperty("owner_id")]
public Optional<ulong> OwnerId { get; set; }
}
}

+ 6
- 7
src/Discord.Net.Rest/API/Rest/ModifyGuildRoleParams.cs View File

@@ -1,20 +1,19 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class ModifyGuildRoleParams
{
[JsonProperty("name")]
[ModelProperty("name")]
public Optional<string> Name { get; set; }
[JsonProperty("permissions")]
[ModelProperty("permissions")]
public Optional<ulong> Permissions { get; set; }
[JsonProperty("color")]
[ModelProperty("color")]
public Optional<uint> Color { get; set; }
[JsonProperty("hoist")]
[ModelProperty("hoist")]
public Optional<bool> Hoist { get; set; }
[JsonProperty("mentionable")]
[ModelProperty("mentionable")]
public Optional<bool> Mentionable { get; set; }
}
}

+ 3
- 4
src/Discord.Net.Rest/API/Rest/ModifyGuildRolesParams.cs View File

@@ -1,14 +1,13 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class ModifyGuildRolesParams : ModifyGuildRoleParams
{
[JsonProperty("id")]
[ModelProperty("id")]
public ulong Id { get; }
[JsonProperty("position")]
[ModelProperty("position")]
public int Position { get; }

public ModifyGuildRolesParams(ulong id, int position)


+ 3
- 4
src/Discord.Net.Rest/API/Rest/ModifyMessageParams.cs View File

@@ -1,14 +1,13 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class ModifyMessageParams
{
[JsonProperty("content")]
[ModelProperty("content")]
public Optional<string> Content { get; set; }
[JsonProperty("embed")]
[ModelProperty("embed")]
public Optional<Embed> Embed { get; set; }
}
}

+ 2
- 3
src/Discord.Net.Rest/API/Rest/ModifyTextChannelParams.cs View File

@@ -1,12 +1,11 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class ModifyTextChannelParams : ModifyGuildChannelParams
{
[JsonProperty("topic")]
[ModelProperty("topic")]
public Optional<string> Topic { get; set; }
}
}

+ 3
- 4
src/Discord.Net.Rest/API/Rest/ModifyVoiceChannelParams.cs View File

@@ -1,14 +1,13 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using Discord.Serialization;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class ModifyVoiceChannelParams : ModifyGuildChannelParams
{
[JsonProperty("bitrate")]
[ModelProperty("bitrate")]
public Optional<int> Bitrate { get; set; }
[JsonProperty("user_limit")]
[ModelProperty("user_limit")]
public Optional<int> UserLimit { get; set; }
}
}

+ 6
- 4
src/Discord.Net.Rest/BaseDiscordClient.cs View File

@@ -22,23 +22,25 @@ namespace Discord.Rest
private readonly SemaphoreSlim _stateLock;
private bool _isFirstLogin, _isDisposed;

internal API.DiscordRestApiClient ApiClient { get; }
internal LogManager LogManager { get; }
internal API.DiscordRestApiClient ApiClient { get; private set; }
public LoginState LoginState { get; private set; }
public ISelfUser CurrentUser { get; protected set; }
public TokenType TokenType => ApiClient.AuthTokenType;
/// <summary> Creates a new REST-only discord client. </summary>
internal BaseDiscordClient(DiscordRestConfig config, API.DiscordRestApiClient client)
internal BaseDiscordClient(DiscordRestConfig config)
{
ApiClient = client;
LogManager = new LogManager(config.LogLevel);
LogManager.Message += async msg => await _logEvent.InvokeAsync(msg).ConfigureAwait(false);

_stateLock = new SemaphoreSlim(1, 1);
_restLogger = LogManager.CreateLogger("Rest");
_isFirstLogin = config.DisplayInitialLog;

}
internal void SetApiClient(API.DiscordRestApiClient client)
{
ApiClient = client;
ApiClient.RequestQueue.RateLimitTriggered += async (id, info) =>
{
if (info == null)


+ 9
- 0
src/Discord.Net.Rest/Discord.Net.Rest.csproj View File

@@ -7,7 +7,16 @@
<TargetFrameworks>net45;netstandard1.1;netstandard1.3</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Serialization\System.Buffers\**" />
<Compile Remove="_corefxlab\**" />
<EmbeddedResource Remove="Serialization\System.Buffers\**" />
<EmbeddedResource Remove="_corefxlab\**" />
<None Remove="Serialization\System.Buffers\**" />
<None Remove="_corefxlab\**" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Discord.Net.Core\Discord.Net.Core.csproj" />
<ProjectReference Include="..\Discord.Net.Serialization\Discord.Net.Serialization.csproj" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' != 'net45' ">
<PackageReference Include="System.Net.Http" Version="4.3.2" /> <!-- https://github.com/dotnet/corefx/issues/19535 -->


+ 61
- 51
src/Discord.Net.Rest/DiscordRestApiClient.cs View File

@@ -1,21 +1,19 @@
#pragma warning disable CS1591
using Discord.API.Rest;
using Discord.Net;
using Discord.Net.Converters;
using Discord.Net.Queue;
using Discord.Net.Rest;
using Newtonsoft.Json;
using Discord.Serialization;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.Formatting;
using System.Threading;
using System.Threading.Tasks;

@@ -27,9 +25,10 @@ namespace Discord.API

public event Func<string, string, double, Task> SentRequest { add { _sentRequestEvent.Add(value); } remove { _sentRequestEvent.Remove(value); } }
private readonly AsyncEvent<Func<string, string, double, Task>> _sentRequestEvent = new AsyncEvent<Func<string, string, double, Task>>();

protected readonly JsonSerializer _serializer;
protected readonly SemaphoreSlim _stateLock;
protected readonly Serializer _serializer;
protected readonly Pool<ArrayFormatter> _formatters;
private readonly RestClientProvider _restClientProvider;

protected bool _isDisposed;
@@ -45,16 +44,16 @@ namespace Discord.API
internal IRestClient RestClient { get; private set; }
internal ulong? CurrentUserId { get; set;}

public DiscordRestApiClient(RestClientProvider restClientProvider, string userAgent, RetryMode defaultRetryMode = RetryMode.AlwaysRetry,
JsonSerializer serializer = null)
public DiscordRestApiClient(RestClientProvider restClientProvider, string userAgent, Serializer serializer, RetryMode defaultRetryMode = RetryMode.AlwaysRetry)
{
_restClientProvider = restClientProvider;
UserAgent = userAgent;
_serializer = serializer;
DefaultRetryMode = defaultRetryMode;
_serializer = serializer ?? new JsonSerializer { DateFormatString = "yyyy-MM-ddTHH:mm:ssZ", ContractResolver = new DiscordContractResolver() };

RequestQueue = new RequestQueue();
_stateLock = new SemaphoreSlim(1, 1);
_formatters = new Pool<ArrayFormatter>(() => new ArrayFormatter(128, SymbolTable.InvariantUtf8));

SetBaseUrl(DiscordConfig.APIUrl);
}
@@ -188,10 +187,18 @@ namespace Discord.API
options.HeaderOnly = true;
options.BucketId = AuthTokenType == TokenType.User ? ClientBucket.Get(clientBucket).Id : bucketId;
options.IsClientBucket = AuthTokenType == TokenType.User;

string json = payload != null ? SerializeJson(payload) : null;
var request = new JsonRestRequest(RestClient, method, endpoint, json, options);
await SendInternalAsync(method, endpoint, request).ConfigureAwait(false);
var data = _formatters.Rent();
try
{
var request = new JsonRestRequest(RestClient, method, endpoint, SerializeJson(data, payload), options);
await SendInternalAsync(method, endpoint, request).ConfigureAwait(false);
}
finally
{
data.Clear();
_formatters.Return(data);
}
}

internal Task SendMultipartAsync(string method, Expression<Func<string>> endpointExpr, IReadOnlyDictionary<string, object> multipartArgs, BucketIds ids,
@@ -210,10 +217,10 @@ namespace Discord.API
}

internal Task<TResponse> SendAsync<TResponse>(string method, Expression<Func<string>> endpointExpr, BucketIds ids,
ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null) where TResponse : class
ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null) where TResponse : class, new()
=> SendAsync<TResponse>(method, GetEndpoint(endpointExpr), GetBucketId(ids, endpointExpr, AuthTokenType, funcName), clientBucket, options);
public async Task<TResponse> SendAsync<TResponse>(string method, string endpoint,
string bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null) where TResponse : class
string bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null) where TResponse : class, new()
{
options = options ?? new RequestOptions();
options.BucketId = AuthTokenType == TokenType.User ? ClientBucket.Get(clientBucket).Id : bucketId;
@@ -224,25 +231,33 @@ namespace Discord.API
}

internal Task<TResponse> SendJsonAsync<TResponse>(string method, Expression<Func<string>> endpointExpr, object payload, BucketIds ids,
ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null) where TResponse : class
ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null) where TResponse : class, new()
=> SendJsonAsync<TResponse>(method, GetEndpoint(endpointExpr), payload, GetBucketId(ids, endpointExpr, AuthTokenType, funcName), clientBucket, options);
public async Task<TResponse> SendJsonAsync<TResponse>(string method, string endpoint, object payload,
string bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null) where TResponse : class
string bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null) where TResponse : class, new()
{
options = options ?? new RequestOptions();
options.BucketId = AuthTokenType == TokenType.User ? ClientBucket.Get(clientBucket).Id : bucketId;
options.IsClientBucket = AuthTokenType == TokenType.User;

string json = payload != null ? SerializeJson(payload) : null;
var request = new JsonRestRequest(RestClient, method, endpoint, json, options);
return DeserializeJson<TResponse>(await SendInternalAsync(method, endpoint, request).ConfigureAwait(false));
var data = _formatters.Rent();
try
{
var request = new JsonRestRequest(RestClient, method, endpoint, SerializeJson(data, payload), options);
return DeserializeJson<TResponse>(await SendInternalAsync(method, endpoint, request).ConfigureAwait(false));
}
finally
{
data.Clear();
_formatters.Return(data);
}
}

internal Task<TResponse> SendMultipartAsync<TResponse>(string method, Expression<Func<string>> endpointExpr, IReadOnlyDictionary<string, object> multipartArgs, BucketIds ids,
ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null)
ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null) where TResponse : class, new()
=> SendMultipartAsync<TResponse>(method, GetEndpoint(endpointExpr), multipartArgs, GetBucketId(ids, endpointExpr, AuthTokenType, funcName), clientBucket, options);
public async Task<TResponse> SendMultipartAsync<TResponse>(string method, string endpoint, IReadOnlyDictionary<string, object> multipartArgs,
string bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null)
string bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null) where TResponse : class, new()
{
options = options ?? new RequestOptions();
options.BucketId = AuthTokenType == TokenType.User ? ClientBucket.Get(clientBucket).Id : bucketId;
@@ -252,7 +267,7 @@ namespace Discord.API
return DeserializeJson<TResponse>(await SendInternalAsync(method, endpoint, request).ConfigureAwait(false));
}

private async Task<Stream> SendInternalAsync(string method, string endpoint, RestRequest request)
private async Task<ReadOnlyBuffer<byte>> SendInternalAsync(string method, string endpoint, RestRequest request)
{
if (!request.Options.IgnoreState)
CheckState();
@@ -260,13 +275,13 @@ namespace Discord.API
request.Options.RetryMode = DefaultRetryMode;

var stopwatch = Stopwatch.StartNew();
var responseStream = await RequestQueue.SendAsync(request).ConfigureAwait(false);
var response = await RequestQueue.SendAsync(request).ConfigureAwait(false);
stopwatch.Stop();

double milliseconds = ToMilliseconds(stopwatch);
await _sentRequestEvent.InvokeAsync(method, endpoint, milliseconds).ConfigureAwait(false);

return responseStream;
return response;
}

//Auth
@@ -311,7 +326,7 @@ namespace Discord.API
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(guildId: guildId);
return await SendAsync<IReadOnlyCollection<Channel>>("GET", () => $"guilds/{guildId}/channels", ids, options: options).ConfigureAwait(false);
return await SendAsync<List<Channel>>("GET", () => $"guilds/{guildId}/channels", ids, options: options).ConfigureAwait(false);
}
public async Task<Channel> CreateGuildChannelAsync(ulong guildId, CreateGuildChannelParams args, RequestOptions options = null)
{
@@ -454,7 +469,7 @@ namespace Discord.API
endpoint = () => $"channels/{channelId}/messages?limit={limit}&{relativeDir}={relativeId}";
else
endpoint = () => $"channels/{channelId}/messages?limit={limit}";
return await SendAsync<IReadOnlyCollection<Message>>("GET", endpoint, ids, options: options).ConfigureAwait(false);
return await SendAsync<List<Message>>("GET", endpoint, ids, options: options).ConfigureAwait(false);
}
public async Task<Message> CreateMessageAsync(ulong channelId, CreateMessageParams args, RequestOptions options = null)
{
@@ -620,7 +635,7 @@ namespace Discord.API

var ids = new BucketIds(channelId: channelId);
Expression<Func<string>> endpoint = () => $"channels/{channelId}/messages/{messageId}/reactions/{emoji}";
return await SendAsync<IReadOnlyCollection<User>>("GET", endpoint, ids, options: options).ConfigureAwait(false);
return await SendAsync<List<User>>("GET", endpoint, ids, options: options).ConfigureAwait(false);
}
public async Task AckMessageAsync(ulong channelId, ulong messageId, RequestOptions options = null)
{
@@ -687,7 +702,7 @@ namespace Discord.API
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(channelId: channelId);
return await SendAsync<IReadOnlyCollection<Message>>("GET", () => $"channels/{channelId}/pins", ids, options: options).ConfigureAwait(false);
return await SendAsync<List<Message>>("GET", () => $"channels/{channelId}/pins", ids, options: options).ConfigureAwait(false);
}

//Channel Recipients
@@ -791,7 +806,7 @@ namespace Discord.API
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(guildId: guildId);
return await SendAsync<IReadOnlyCollection<Ban>>("GET", () => $"guilds/{guildId}/bans", ids, options: options).ConfigureAwait(false);
return await SendAsync<List<Ban>>("GET", () => $"guilds/{guildId}/bans", ids, options: options).ConfigureAwait(false);
}
public async Task CreateGuildBanAsync(ulong guildId, ulong userId, CreateGuildBanParams args, RequestOptions options = null)
{
@@ -846,7 +861,7 @@ namespace Discord.API
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(guildId: guildId);
return await SendAsync<IReadOnlyCollection<Integration>>("GET", () => $"guilds/{guildId}/integrations", ids, options: options).ConfigureAwait(false);
return await SendAsync<List<Integration>>("GET", () => $"guilds/{guildId}/integrations", ids, options: options).ConfigureAwait(false);
}
public async Task<Integration> CreateGuildIntegrationAsync(ulong guildId, CreateGuildIntegrationParams args, RequestOptions options = null)
{
@@ -915,7 +930,7 @@ namespace Discord.API
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(guildId: guildId);
return await SendAsync<IReadOnlyCollection<InviteMetadata>>("GET", () => $"guilds/{guildId}/invites", ids, options: options).ConfigureAwait(false);
return await SendAsync< List<InviteMetadata>>("GET", () => $"guilds/{guildId}/invites", ids, options: options).ConfigureAwait(false);
}
public async Task<IReadOnlyCollection<InviteMetadata>> GetChannelInvitesAsync(ulong channelId, RequestOptions options = null)
{
@@ -923,7 +938,7 @@ namespace Discord.API
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(channelId: channelId);
return await SendAsync<IReadOnlyCollection<InviteMetadata>>("GET", () => $"channels/{channelId}/invites", ids, options: options).ConfigureAwait(false);
return await SendAsync<List<InviteMetadata>>("GET", () => $"channels/{channelId}/invites", ids, options: options).ConfigureAwait(false);
}
public async Task<InviteMetadata> CreateChannelInviteAsync(ulong channelId, CreateChannelInviteParams args, RequestOptions options = null)
{
@@ -979,7 +994,7 @@ namespace Discord.API

var ids = new BucketIds(guildId: guildId);
Expression<Func<string>> endpoint = () => $"guilds/{guildId}/members?limit={limit}&after={afterUserId}";
return await SendAsync<IReadOnlyCollection<GuildMember>>("GET", endpoint, ids, options: options).ConfigureAwait(false);
return await SendAsync< List<GuildMember>>("GET", endpoint, ids, options: options).ConfigureAwait(false);
}
public async Task RemoveGuildMemberAsync(ulong guildId, ulong userId, string reason, RequestOptions options = null)
{
@@ -1020,7 +1035,7 @@ namespace Discord.API
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(guildId: guildId);
return await SendAsync<IReadOnlyCollection<Role>>("GET", () => $"guilds/{guildId}/roles", ids, options: options).ConfigureAwait(false);
return await SendAsync<List<Role>>("GET", () => $"guilds/{guildId}/roles", ids, options: options).ConfigureAwait(false);
}
public async Task<Role> CreateGuildRoleAsync(ulong guildId, RequestOptions options = null)
{
@@ -1058,7 +1073,7 @@ namespace Discord.API
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(guildId: guildId);
return await SendJsonAsync<IReadOnlyCollection<Role>>("PATCH", () => $"guilds/{guildId}/roles", args, ids, options: options).ConfigureAwait(false);
return await SendJsonAsync<List<Role>>("PATCH", () => $"guilds/{guildId}/roles", args, ids, options: options).ConfigureAwait(false);
}

//Users
@@ -1083,12 +1098,12 @@ namespace Discord.API
public async Task<IReadOnlyCollection<Connection>> GetMyConnectionsAsync(RequestOptions options = null)
{
options = RequestOptions.CreateOrClone(options);
return await SendAsync<IReadOnlyCollection<Connection>>("GET", () => "users/@me/connections", new BucketIds(), options: options).ConfigureAwait(false);
return await SendAsync<List<Connection>>("GET", () => "users/@me/connections", new BucketIds(), options: options).ConfigureAwait(false);
}
public async Task<IReadOnlyCollection<Channel>> GetMyPrivateChannelsAsync(RequestOptions options = null)
{
options = RequestOptions.CreateOrClone(options);
return await SendAsync<IReadOnlyCollection<Channel>>("GET", () => "users/@me/channels", new BucketIds(), options: options).ConfigureAwait(false);
return await SendAsync<List<Channel>>("GET", () => "users/@me/channels", new BucketIds(), options: options).ConfigureAwait(false);
}
public async Task<IReadOnlyCollection<UserGuild>> GetMyGuildsAsync(GetGuildSummariesParams args, RequestOptions options = null)
{
@@ -1101,7 +1116,7 @@ namespace Discord.API
int limit = args.Limit.GetValueOrDefault(int.MaxValue);
ulong afterGuildId = args.AfterGuildId.GetValueOrDefault(0);
return await SendAsync<IReadOnlyCollection<UserGuild>>("GET", () => $"users/@me/guilds?limit={limit}&after={afterGuildId}", new BucketIds(), options: options).ConfigureAwait(false);
return await SendAsync<List<UserGuild>>("GET", () => $"users/@me/guilds?limit={limit}&after={afterGuildId}", new BucketIds(), options: options).ConfigureAwait(false);
}
public async Task<Application> GetMyApplicationAsync(RequestOptions options = null)
{
@@ -1138,7 +1153,7 @@ namespace Discord.API
public async Task<IReadOnlyCollection<VoiceRegion>> GetVoiceRegionsAsync(RequestOptions options = null)
{
options = RequestOptions.CreateOrClone(options);
return await SendAsync<IReadOnlyCollection<VoiceRegion>>("GET", () => "voice/regions", new BucketIds(), options: options).ConfigureAwait(false);
return await SendAsync<List<VoiceRegion>>("GET", () => "voice/regions", new BucketIds(), options: options).ConfigureAwait(false);
}
public async Task<IReadOnlyCollection<VoiceRegion>> GetGuildVoiceRegionsAsync(ulong guildId, RequestOptions options = null)
{
@@ -1146,7 +1161,7 @@ namespace Discord.API
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(guildId: guildId);
return await SendAsync<IReadOnlyCollection<VoiceRegion>>("GET", () => $"guilds/{guildId}/regions", ids, options: options).ConfigureAwait(false);
return await SendAsync<List<VoiceRegion>>("GET", () => $"guilds/{guildId}/regions", ids, options: options).ConfigureAwait(false);
}

//Helpers
@@ -1156,19 +1171,14 @@ namespace Discord.API
throw new InvalidOperationException("Client is not logged in.");
}
protected static double ToMilliseconds(Stopwatch stopwatch) => Math.Round((double)stopwatch.ElapsedTicks / (double)Stopwatch.Frequency * 1000.0, 2);
protected string SerializeJson(object value)
protected ReadOnlyBuffer<byte> SerializeJson<T>(ArrayFormatter data, T value)
{
var sb = new StringBuilder(256);
using (TextWriter text = new StringWriter(sb, CultureInfo.InvariantCulture))
using (JsonWriter writer = new JsonTextWriter(text))
_serializer.Serialize(writer, value);
return sb.ToString();
_serializer.Write(data, value);
return new ReadOnlyBuffer<byte>(data.Formatted.Array, 0, data.Formatted.Count);
}
protected T DeserializeJson<T>(Stream jsonStream)
protected T DeserializeJson<T>(ReadOnlyBuffer<byte> data)
{
using (TextReader text = new StreamReader(jsonStream))
using (JsonReader reader = new JsonTextReader(text))
return _serializer.Deserialize<T>(reader);
return _serializer.Read<T>(data);
}

internal class BucketIds


+ 20
- 4
src/Discord.Net.Rest/DiscordRestClient.cs View File

@@ -1,4 +1,6 @@
using System.Collections.Generic;
using Discord.Serialization;
using Discord.Serialization.Json;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Threading.Tasks;
@@ -7,15 +9,29 @@ namespace Discord.Rest
{
public class DiscordRestClient : BaseDiscordClient, IDiscordClient
{
private readonly Serializer _serializer;
private RestApplication _applicationInfo;

public new RestSelfUser CurrentUser => base.CurrentUser as RestSelfUser;

public DiscordRestClient() : this(new DiscordRestConfig()) { }
public DiscordRestClient(DiscordRestConfig config) : base(config, CreateApiClient(config)) { }
public DiscordRestClient(DiscordRestConfig config) : base(config)
{
_serializer = DiscordRestJsonSerializer.Global.CreateScope();
if (config.LogLevel >= LogSeverity.Warning)
{
_serializer.ModelError += (path, ex)
=> _restLogger.WarningAsync($"Failed to deserialize {path}", ex).GetAwaiter().GetResult();
}
if (config.LogLevel >= LogSeverity.Debug)
{
_serializer.UnmappedProperty += path
=> _restLogger.DebugAsync($"Unmapped property: {path}");
}

SetApiClient(new API.DiscordRestApiClient(config.RestClientProvider, DiscordConfig.UserAgent, _serializer, config.DefaultRetryMode));
}

private static API.DiscordRestApiClient CreateApiClient(DiscordRestConfig config)
=> new API.DiscordRestApiClient(config.RestClientProvider, DiscordRestConfig.UserAgent);
internal override void Dispose(bool disposing)
{
if (disposing)


+ 1
- 1
src/Discord.Net.Rest/Extensions/EntityExtensions.cs View File

@@ -114,7 +114,7 @@ namespace Discord.Rest

public static API.Image ToModel(this Image entity)
{
return new API.Image(entity.Stream);
return new API.Image(entity.Stream, entity.Format);
}

public static Overwrite ToEntity(this API.Overwrite model)


+ 25
- 0
src/Discord.Net.Rest/Extensions/StreamExtensions.cs View File

@@ -0,0 +1,25 @@
using System;
using System.IO;

namespace Discord
{
internal static class StreamExtensions
{
#if MSTRYBUFFER
public static byte[] GetBuffer(this MemoryStream stream)
{
if (stream.TryGetBuffer(out var streamBuffer))
return streamBuffer.Array;
else
return stream.ToArray();
}
#elif !MSBUFFER
public static byte[] GetBuffer(this MemoryStream stream) => stream.ToArray();
#endif

public static ReadOnlyBuffer<byte> ToReadOnlyBuffer(this MemoryStream stream)
=> new ReadOnlyBuffer<byte>(stream.GetBuffer(), 0, (int)stream.Length);
public static ReadOnlySpan<byte> ToSpan(this MemoryStream stream)
=> new ReadOnlySpan<byte>(stream.GetBuffer(), 0, (int)stream.Length);
}
}

+ 0
- 59
src/Discord.Net.Rest/Net/Converters/ArrayConverter.cs View File

@@ -1,59 +0,0 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;

namespace Discord.Net.Converters
{
internal class ArrayConverter<T> : JsonConverter
{
private readonly JsonConverter _innerConverter;

public override bool CanConvert(Type objectType) => true;
public override bool CanRead => true;
public override bool CanWrite => true;

public ArrayConverter(JsonConverter innerConverter)
{
_innerConverter = innerConverter;
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var result = new List<T>();
if (reader.TokenType == JsonToken.StartArray)
{
reader.Read();
while (reader.TokenType != JsonToken.EndArray)
{
T obj;
if (_innerConverter != null)
obj = (T)_innerConverter.ReadJson(reader, typeof(T), null, serializer);
else
obj = serializer.Deserialize<T>(reader);
result.Add(obj);
reader.Read();
}
}
return result.ToArray();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value != null)
{
writer.WriteStartArray();
var a = (T[])value;
for (int i = 0; i < a.Length; i++)
{
if (_innerConverter != null)
_innerConverter.WriteJson(writer, a[i], serializer);
else
serializer.Serialize(writer, a[i], typeof(T));
}

writer.WriteEndArray();
}
else
writer.WriteNull();
}
}
}

+ 0
- 102
src/Discord.Net.Rest/Net/Converters/DiscordContractResolver.cs View File

@@ -1,102 +0,0 @@
using Discord.API;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace Discord.Net.Converters
{
internal class DiscordContractResolver : DefaultContractResolver
{
private static readonly TypeInfo _ienumerable = typeof(IEnumerable<ulong[]>).GetTypeInfo();
private static readonly MethodInfo _shouldSerialize = typeof(DiscordContractResolver).GetTypeInfo().GetDeclaredMethod("ShouldSerialize");
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (property.Ignored)
return property;

if (member is PropertyInfo propInfo)
{
var converter = GetConverter(property, propInfo, propInfo.PropertyType, 0);
if (converter != null)
{
property.Converter = converter;
property.MemberConverter = converter;
}
}
else
throw new InvalidOperationException($"{member.DeclaringType.FullName}.{member.Name} is not a property.");
return property;
}

private static JsonConverter GetConverter(JsonProperty property, PropertyInfo propInfo, Type type, int depth)
{
if (type.IsArray)
return MakeGenericConverter(property, propInfo, typeof(ArrayConverter<>), type.GetElementType(), depth);
if (type.IsConstructedGenericType)
{
Type genericType = type.GetGenericTypeDefinition();
if (depth == 0 && genericType == typeof(Optional<>))
{
var typeInput = propInfo.DeclaringType;
var innerTypeOutput = type.GenericTypeArguments[0];

var getter = typeof(Func<,>).MakeGenericType(typeInput, type);
var getterDelegate = propInfo.GetMethod.CreateDelegate(getter);
var shouldSerialize = _shouldSerialize.MakeGenericMethod(typeInput, innerTypeOutput);
var shouldSerializeDelegate = (Func<object, Delegate, bool>)shouldSerialize.CreateDelegate(typeof(Func<object, Delegate, bool>));
property.ShouldSerialize = x => shouldSerializeDelegate(x, getterDelegate);

return MakeGenericConverter(property, propInfo, typeof(OptionalConverter<>), innerTypeOutput, depth);
}
else if (genericType == typeof(Nullable<>))
return MakeGenericConverter(property, propInfo, typeof(NullableConverter<>), type.GenericTypeArguments[0], depth);
else if (genericType == typeof(EntityOrId<>))
return MakeGenericConverter(property, propInfo, typeof(UInt64EntityOrIdConverter<>), type.GenericTypeArguments[0], depth);
}

//Primitives
bool hasInt53 = propInfo.GetCustomAttribute<Int53Attribute>() != null;
if (!hasInt53)
{
if (type == typeof(ulong))
return UInt64Converter.Instance;
}

//Enums
if (type == typeof(PermissionTarget))
return PermissionTargetConverter.Instance;
if (type == typeof(UserStatus))
return UserStatusConverter.Instance;

//Special
if (type == typeof(API.Image))
return ImageConverter.Instance;

//Entities
var typeInfo = type.GetTypeInfo();
if (typeInfo.ImplementedInterfaces.Any(x => x == typeof(IEntity<ulong>)))
return UInt64EntityConverter.Instance;
if (typeInfo.ImplementedInterfaces.Any(x => x == typeof(IEntity<string>)))
return StringEntityConverter.Instance;

return null;
}

private static bool ShouldSerialize<TOwner, TValue>(object owner, Delegate getter)
{
return (getter as Func<TOwner, Optional<TValue>>)((TOwner)owner).IsSpecified;
}

private static JsonConverter MakeGenericConverter(JsonProperty property, PropertyInfo propInfo, Type converterType, Type innerType, int depth)
{
var genericType = converterType.MakeGenericType(innerType).GetTypeInfo();
var innerConverter = GetConverter(property, propInfo, innerType, depth + 1);
return genericType.DeclaredConstructors.First().Invoke(new object[] { innerConverter }) as JsonConverter;
}
}
}

+ 0
- 36
src/Discord.Net.Rest/Net/Converters/ImageConverter.cs View File

@@ -1,36 +0,0 @@
using Newtonsoft.Json;
using System;
using Model = Discord.API.Image;

namespace Discord.Net.Converters
{
internal class ImageConverter : JsonConverter
{
public static readonly ImageConverter Instance = new ImageConverter();

public override bool CanConvert(Type objectType) => true;
public override bool CanRead => true;
public override bool CanWrite => true;

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new InvalidOperationException();
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var image = (Model)value;

if (image.Stream != null)
{
byte[] bytes = new byte[image.Stream.Length - image.Stream.Position];
image.Stream.Read(bytes, 0, bytes.Length);

string base64 = Convert.ToBase64String(bytes);
writer.WriteValue($"data:image/jpeg;base64,{base64}");
}
else if (image.Hash != null)
writer.WriteValue(image.Hash);
}
}
}

+ 0
- 50
src/Discord.Net.Rest/Net/Converters/NullableConverter.cs View File

@@ -1,50 +0,0 @@
using Newtonsoft.Json;
using System;

namespace Discord.Net.Converters
{
internal class NullableConverter<T> : JsonConverter
where T : struct
{
private readonly JsonConverter _innerConverter;

public override bool CanConvert(Type objectType) => true;
public override bool CanRead => true;
public override bool CanWrite => true;

public NullableConverter(JsonConverter innerConverter)
{
_innerConverter = innerConverter;
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
object value = reader.Value;
if (value == null)
return null;
else
{
T obj;
if (_innerConverter != null)
obj = (T)_innerConverter.ReadJson(reader, typeof(T), null, serializer);
else
obj = serializer.Deserialize<T>(reader);
return obj;
}
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null)
writer.WriteNull();
else
{
var nullable = (T?)value;
if (_innerConverter != null)
_innerConverter.WriteJson(writer, nullable.Value, serializer);
else
serializer.Serialize(writer, nullable.Value, typeof(T));
}
}
}
}

+ 0
- 38
src/Discord.Net.Rest/Net/Converters/OptionalConverter.cs View File

@@ -1,38 +0,0 @@
using Newtonsoft.Json;
using System;

namespace Discord.Net.Converters
{
internal class OptionalConverter<T> : JsonConverter
{
private readonly JsonConverter _innerConverter;

public override bool CanConvert(Type objectType) => true;
public override bool CanRead => true;
public override bool CanWrite => true;

public OptionalConverter(JsonConverter innerConverter)
{
_innerConverter = innerConverter;
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
T obj;
if (_innerConverter != null)
obj = (T)_innerConverter.ReadJson(reader, typeof(T), null, serializer);
else
obj = serializer.Deserialize<T>(reader);
return new Optional<T>(obj);
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
value = ((Optional<T>)value).Value;
if (_innerConverter != null)
_innerConverter.WriteJson(writer, value, serializer);
else
serializer.Serialize(writer, value, typeof(T));
}
}
}

+ 0
- 42
src/Discord.Net.Rest/Net/Converters/PermissionTargetConverter.cs View File

@@ -1,42 +0,0 @@
using Newtonsoft.Json;
using System;

namespace Discord.Net.Converters
{
internal class PermissionTargetConverter : JsonConverter
{
public static readonly PermissionTargetConverter Instance = new PermissionTargetConverter();

public override bool CanConvert(Type objectType) => true;
public override bool CanRead => true;
public override bool CanWrite => true;

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
switch ((string)reader.Value)
{
case "member":
return PermissionTarget.User;
case "role":
return PermissionTarget.Role;
default:
throw new JsonSerializationException("Unknown permission target");
}
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
switch ((PermissionTarget)value)
{
case PermissionTarget.User:
writer.WriteValue("member");
break;
case PermissionTarget.Role:
writer.WriteValue("role");
break;
default:
throw new JsonSerializationException("Invalid permission target");
}
}
}
}

+ 0
- 27
src/Discord.Net.Rest/Net/Converters/StringEntityConverter.cs View File

@@ -1,27 +0,0 @@
using Newtonsoft.Json;
using System;

namespace Discord.Net.Converters
{
internal class StringEntityConverter : JsonConverter
{
public static readonly StringEntityConverter Instance = new StringEntityConverter();

public override bool CanConvert(Type objectType) => true;
public override bool CanRead => false;
public override bool CanWrite => true;

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new InvalidOperationException();
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value != null)
writer.WriteValue((value as IEntity<string>).Id);
else
writer.WriteNull();
}
}
}

+ 0
- 25
src/Discord.Net.Rest/Net/Converters/UInt64Converter.cs View File

@@ -1,25 +0,0 @@
using Newtonsoft.Json;
using System;
using System.Globalization;

namespace Discord.Net.Converters
{
internal class UInt64Converter : JsonConverter
{
public static readonly UInt64Converter Instance = new UInt64Converter();

public override bool CanConvert(Type objectType) => true;
public override bool CanRead => true;
public override bool CanWrite => true;

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return ulong.Parse((string)reader.Value, NumberStyles.None, CultureInfo.InvariantCulture);
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(((ulong)value).ToString(CultureInfo.InvariantCulture));
}
}
}

+ 0
- 28
src/Discord.Net.Rest/Net/Converters/UInt64EntityConverter.cs View File

@@ -1,28 +0,0 @@
using Newtonsoft.Json;
using System;
using System.Globalization;

namespace Discord.Net.Converters
{
internal class UInt64EntityConverter : JsonConverter
{
public static readonly UInt64EntityConverter Instance = new UInt64EntityConverter();

public override bool CanConvert(Type objectType) => true;
public override bool CanRead => false;
public override bool CanWrite => true;

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new InvalidOperationException();
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value != null)
writer.WriteValue((value as IEntity<ulong>).Id.ToString(CultureInfo.InvariantCulture));
else
writer.WriteNull();
}
}
}

+ 0
- 42
src/Discord.Net.Rest/Net/Converters/UInt64EntityOrIdConverter.cs View File

@@ -1,42 +0,0 @@
using Discord.API;
using Newtonsoft.Json;
using System;

namespace Discord.Net.Converters
{
internal class UInt64EntityOrIdConverter<T> : JsonConverter
{
private readonly JsonConverter _innerConverter;

public override bool CanConvert(Type objectType) => true;
public override bool CanRead => true;
public override bool CanWrite => false;

public UInt64EntityOrIdConverter(JsonConverter innerConverter)
{
_innerConverter = innerConverter;
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
switch (reader.TokenType)
{
case JsonToken.String:
case JsonToken.Integer:
return new EntityOrId<T>(ulong.Parse(reader.ReadAsString()));
default:
T obj;
if (_innerConverter != null)
obj = (T)_innerConverter.ReadJson(reader, typeof(T), null, serializer);
else
obj = serializer.Deserialize<T>(reader);
return new EntityOrId<T>(obj);
}
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new InvalidOperationException();
}
}
}

+ 0
- 58
src/Discord.Net.Rest/Net/Converters/UserStatusConverter.cs View File

@@ -1,58 +0,0 @@
using Newtonsoft.Json;
using System;

namespace Discord.Net.Converters
{
internal class UserStatusConverter : JsonConverter
{
public static readonly UserStatusConverter Instance = new UserStatusConverter();

public override bool CanConvert(Type objectType) => true;
public override bool CanRead => true;
public override bool CanWrite => true;

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
switch ((string)reader.Value)
{
case "online":
return UserStatus.Online;
case "idle":
return UserStatus.Idle;
case "dnd":
return UserStatus.DoNotDisturb;
case "invisible":
return UserStatus.Invisible; //Should never happen
case "offline":
return UserStatus.Offline;
default:
throw new JsonSerializationException("Unknown user status");
}
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
switch ((UserStatus)value)
{
case UserStatus.Online:
writer.WriteValue("online");
break;
case UserStatus.Idle:
case UserStatus.AFK:
writer.WriteValue("idle");
break;
case UserStatus.DoNotDisturb:
writer.WriteValue("dnd");
break;
case UserStatus.Invisible:
writer.WriteValue("invisible");
break;
case UserStatus.Offline:
writer.WriteValue("offline");
break;
default:
throw new JsonSerializationException("Invalid user status");
}
}
}
}

+ 8
- 8
src/Discord.Net.Rest/Net/DefaultRestClient.cs View File

@@ -1,11 +1,11 @@
using Newtonsoft.Json;
using System;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -18,7 +18,6 @@ namespace Discord.Net.Rest

private readonly HttpClient _client;
private readonly string _baseUrl;
private readonly JsonSerializer _errorDeserializer;
private CancellationToken _cancelToken;
private bool _isDisposed;

@@ -35,7 +34,6 @@ namespace Discord.Net.Rest
SetHeader("accept-encoding", "gzip, deflate");

_cancelToken = CancellationToken.None;
_errorDeserializer = new JsonSerializer();
}
private void Dispose(bool disposing)
{
@@ -71,13 +69,15 @@ namespace Discord.Net.Rest
return await SendInternalAsync(restRequest, cancelToken, headerOnly).ConfigureAwait(false);
}
}
public async Task<RestResponse> SendAsync(string method, string endpoint, string json, CancellationToken cancelToken, bool headerOnly, string reason = null)
public async Task<RestResponse> SendAsync(string method, string endpoint, ReadOnlyBuffer<byte> json, CancellationToken cancelToken, bool headerOnly, string reason = null)
{
string uri = Path.Combine(_baseUrl, endpoint);
using (var restRequest = new HttpRequestMessage(GetMethod(method), uri))
{
if (reason != null) restRequest.Headers.Add("X-Audit-Log-Reason", Uri.EscapeDataString(reason));
restRequest.Content = new StringContent(json, Encoding.UTF8, "application/json");
var content = new ByteArrayContent(json.ToArray());
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
restRequest.Content = content;
return await SendInternalAsync(restRequest, cancelToken, headerOnly).ConfigureAwait(false);
}
}
@@ -125,9 +125,9 @@ namespace Discord.Net.Rest
HttpResponseMessage response = await _client.SendAsync(request, cancelToken).ConfigureAwait(false);
var headers = response.Headers.ToDictionary(x => x.Key, x => x.Value.FirstOrDefault(), StringComparer.OrdinalIgnoreCase);
var stream = !headerOnly ? await response.Content.ReadAsStreamAsync().ConfigureAwait(false) : null;
var data = !headerOnly ? await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false) : null;

return new RestResponse(response.StatusCode, headers, stream);
return new RestResponse(response.StatusCode, headers, new ReadOnlyBuffer<byte>(data));
}

private static readonly HttpMethod _patch = new HttpMethod("PATCH");


+ 1
- 1
src/Discord.Net.Rest/Net/Queue/RequestQueue.cs View File

@@ -63,7 +63,7 @@ namespace Discord.Net.Queue
finally { _tokenLock.Release(); }
}

public async Task<Stream> SendAsync(RestRequest request)
public async Task<ReadOnlyBuffer<byte>> SendAsync(RestRequest request)
{
if (request.Options.CancelToken.CanBeCanceled)
request.Options.CancelToken = CancellationTokenSource.CreateLinkedTokenSource(_requestCancelToken, request.Options.CancelToken).Token;


+ 22
- 16
src/Discord.Net.Rest/Net/Queue/RequestQueueBucket.cs View File

@@ -1,5 +1,6 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Discord.Rest;
using Discord.Serialization;
using Discord.Serialization.Json;
using System;
#if DEBUG_LIMITS
using System.Diagnostics;
@@ -13,6 +14,16 @@ namespace Discord.Net.Queue
{
internal class RequestBucket
{
private class Error
{
[ModelProperty("code")]
public int Code { get; set; }
[ModelProperty("message")]
public string Message { get; set; }
}

private static int _nextId = 0;

private readonly object _lock;
private readonly RequestQueue _queue;
private int _semaphore;
@@ -38,10 +49,9 @@ namespace Discord.Net.Queue
LastAttemptAt = DateTimeOffset.UtcNow;
}
static int nextId = 0;
public async Task<Stream> SendAsync(RestRequest request)
public async Task<ReadOnlyBuffer<byte>> SendAsync(RestRequest request)
{
int id = Interlocked.Increment(ref nextId);
int id = Interlocked.Increment(ref _nextId);
#if DEBUG_LIMITS
Debug.WriteLine($"[{id}] Start");
#endif
@@ -54,7 +64,7 @@ namespace Discord.Net.Queue
#if DEBUG_LIMITS
Debug.WriteLine($"[{id}] Sending...");
#endif
RateLimitInfo info = default(RateLimitInfo);
var info = default(RateLimitInfo);
try
{
var response = await request.SendAsync().ConfigureAwait(false);
@@ -92,17 +102,13 @@ namespace Discord.Net.Queue
default:
int? code = null;
string reason = null;
if (response.Stream != null)
if (response.Data.Length > 0)
{
try
{
using (var reader = new StreamReader(response.Stream))
using (var jsonReader = new JsonTextReader(reader))
{
var json = JToken.Load(jsonReader);
try { code = json.Value<int>("code"); } catch { };
try { reason = json.Value<string>("message"); } catch { };
}
var error = DiscordRestJsonSerializer.Global.Read<Error>(response.Data);
code = error.Code;
reason = error.Message;
}
catch { }
}
@@ -114,7 +120,7 @@ namespace Discord.Net.Queue
#if DEBUG_LIMITS
Debug.WriteLine($"[{id}] Success");
#endif
return response.Stream;
return response.Data;
}
}
//catch (HttpException) { throw; } //Pass through
@@ -231,7 +237,7 @@ namespace Discord.Net.Queue
#endif
}

var now = DateTimeUtils.ToUnixSeconds(DateTimeOffset.UtcNow);
long now = DateTimeUtils.ToUnixSeconds(DateTimeOffset.UtcNow);
DateTimeOffset? resetTick = null;

//Using X-RateLimit-Remaining causes a race condition


+ 5
- 4
src/Discord.Net.Rest/Net/Queue/Requests/JsonRestRequest.cs View File

@@ -1,21 +1,22 @@
using Discord.Net.Rest;
using System;
using System.Threading.Tasks;

namespace Discord.Net.Queue
{
public class JsonRestRequest : RestRequest
{
public string Json { get; }
public ReadOnlyBuffer<byte> Payload { get; }

public JsonRestRequest(IRestClient client, string method, string endpoint, string json, RequestOptions options)
public JsonRestRequest(IRestClient client, string method, string endpoint, ReadOnlyBuffer<byte> payload, RequestOptions options)
: base(client, method, endpoint, options)
{
Json = json;
Payload = payload;
}

public override async Task<RestResponse> SendAsync()
{
return await Client.SendAsync(Method, Endpoint, Json, Options.CancelToken, Options.HeaderOnly, Options.AuditLogReason).ConfigureAwait(false);
return await Client.SendAsync(Method, Endpoint, Payload, Options.CancelToken, Options.HeaderOnly, Options.AuditLogReason).ConfigureAwait(false);
}
}
}

+ 3
- 3
src/Discord.Net.Rest/Net/Queue/Requests/WebSocketRequest.cs View File

@@ -10,14 +10,14 @@ namespace Discord.Net.Queue
{
public IWebSocketClient Client { get; }
public string BucketId { get; }
public byte[] Data { get; }
public ReadOnlyBuffer<byte> Data { get; }
public bool IsText { get; }
public DateTimeOffset? TimeoutAt { get; }
public TaskCompletionSource<Stream> Promise { get; }
public RequestOptions Options { get; }
public CancellationToken CancelToken { get; internal set; }

public WebSocketRequest(IWebSocketClient client, string bucketId, byte[] data, bool isText, RequestOptions options)
public WebSocketRequest(IWebSocketClient client, string bucketId, ReadOnlyBuffer<byte> data, bool isText, RequestOptions options)
{
Preconditions.NotNull(options, nameof(options));

@@ -32,7 +32,7 @@ namespace Discord.Net.Queue

public async Task SendAsync()
{
await Client.SendAsync(Data, 0, Data.Length, IsText).ConfigureAwait(false);
await Client.SendAsync(Data, IsText).ConfigureAwait(false);
}
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save