| @@ -1,6 +1,6 @@ | |||||
| Microsoft Visual Studio Solution File, Format Version 12.00 | Microsoft Visual Studio Solution File, Format Version 12.00 | ||||
| # Visual Studio 15 | # Visual Studio 15 | ||||
| VisualStudioVersion = 15.0.26228.4 | |||||
| VisualStudioVersion = 15.0.26711.1 | |||||
| MinimumVisualStudioVersion = 10.0.40219.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}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Core", "src\Discord.Net.Core\Discord.Net.Core.csproj", "{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}" | ||||
| EndProject | EndProject | ||||
| @@ -14,8 +14,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Commands", "src | |||||
| EndProject | EndProject | ||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.WebSocket", "src\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj", "{688FD1D8-7F01-4539-B2E9-F473C5D699C7}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.WebSocket", "src\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj", "{688FD1D8-7F01-4539-B2E9-F473C5D699C7}" | ||||
| EndProject | 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}" | 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 | EndProject | ||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions", "Extensions", "{CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}" | 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 | EndProject | ||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Webhook", "src\Discord.Net.Webhook\Discord.Net.Webhook.csproj", "{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Webhook", "src\Discord.Net.Webhook\Discord.Net.Webhook.csproj", "{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}" | ||||
| EndProject | 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 | Global | ||||
| GlobalSection(SolutionConfigurationPlatforms) = preSolution | GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||
| Debug|Any CPU = Debug|Any CPU | 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|x64.Build.0 = Release|Any CPU | ||||
| {9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Release|x86.ActiveCfg = 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 | {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 | EndGlobalSection | ||||
| GlobalSection(SolutionProperties) = preSolution | GlobalSection(SolutionProperties) = preSolution | ||||
| HideSolutionNode = FALSE | HideSolutionNode = FALSE | ||||
| @@ -139,7 +153,11 @@ Global | |||||
| {5688A353-121E-40A1-8BFA-B17B91FB48FB} = {288C363D-A636-4EAE-9AC1-4698B641B26E} | {5688A353-121E-40A1-8BFA-B17B91FB48FB} = {288C363D-A636-4EAE-9AC1-4698B641B26E} | ||||
| {078DD7E6-943D-4D09-AFC2-D2BA58B76C9C} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A} | {078DD7E6-943D-4D09-AFC2-D2BA58B76C9C} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A} | ||||
| {688FD1D8-7F01-4539-B2E9-F473C5D699C7} = {288C363D-A636-4EAE-9AC1-4698B641B26E} | {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} | {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 | EndGlobalSection | ||||
| EndGlobal | EndGlobal | ||||
| @@ -1,7 +1,8 @@ | |||||
| <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||||
| <PropertyGroup> | <PropertyGroup> | ||||
| <VersionPrefix>1.0.2</VersionPrefix> | |||||
| <VersionPrefix>1.1.0-alpha</VersionPrefix> | |||||
| <VersionSuffix></VersionSuffix> | <VersionSuffix></VersionSuffix> | ||||
| <LangVersion>latest</LangVersion> | |||||
| <Authors>RogueException</Authors> | <Authors>RogueException</Authors> | ||||
| <PackageTags>discord;discordapp</PackageTags> | <PackageTags>discord;discordapp</PackageTags> | ||||
| <PackageProjectUrl>https://github.com/RogueException/Discord.Net</PackageProjectUrl> | <PackageProjectUrl>https://github.com/RogueException/Discord.Net</PackageProjectUrl> | ||||
| @@ -18,7 +19,7 @@ | |||||
| <VersionSuffix Condition=" '$(VersionSuffix)' == '' ">build-$(BuildNumber)</VersionSuffix> | <VersionSuffix Condition=" '$(VersionSuffix)' == '' ">build-$(BuildNumber)</VersionSuffix> | ||||
| </PropertyGroup> | </PropertyGroup> | ||||
| <PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' Or '$(TargetFramework)' == 'net45' "> | <PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' Or '$(TargetFramework)' == 'net45' "> | ||||
| <DefineConstants>$(DefineConstants);FILESYSTEM;DEFAULTUDPCLIENT;DEFAULTWEBSOCKET</DefineConstants> | |||||
| <DefineConstants>$(DefineConstants);FILESYSTEM;DEFAULTUDPCLIENT;DEFAULTWEBSOCKET;MSBUFFER</DefineConstants> | |||||
| </PropertyGroup> | </PropertyGroup> | ||||
| <PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' "> | <PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' "> | ||||
| <DefineConstants>$(DefineConstants);FORMATSTR;UNIXTIME;MSTRYBUFFER;UDPDISPOSE</DefineConstants> | <DefineConstants>$(DefineConstants);FORMATSTR;UNIXTIME;MSTRYBUFFER;UDPDISPOSE</DefineConstants> | ||||
| @@ -309,14 +309,14 @@ namespace Discord.Commands | |||||
| if (match.Command.Parameters.Count > 0) | 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; | argValuesScore = argValuesSum / match.Command.Parameters.Count; | ||||
| paramValuesScore = paramValuesSum / 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; | return match.Command.Priority + totalArgsScore * 0.99f; | ||||
| } | } | ||||
| @@ -31,5 +31,8 @@ namespace Discord.Audio | |||||
| AudioOutStream CreatePCMStream(AudioApplication application, int? bitrate = null, int bufferMillis = 1000, int packetLoss = 30); | 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> | /// <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); | 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); | |||||
| } | } | ||||
| } | } | ||||
| @@ -5,7 +5,7 @@ namespace Discord.Audio | |||||
| public readonly ushort Sequence; | public readonly ushort Sequence; | ||||
| public readonly uint Timestamp; | public readonly uint Timestamp; | ||||
| public readonly byte[] Payload; | public readonly byte[] Payload; | ||||
| public readonly bool Missed; | |||||
| public readonly bool Missed; | |||||
| public RTPFrame(ushort sequence, uint timestamp, byte[] payload, bool missed) | public RTPFrame(ushort sequence, uint timestamp, byte[] payload, bool missed) | ||||
| { | { | ||||
| @@ -7,8 +7,13 @@ | |||||
| <TargetFrameworks>net45;netstandard1.1;netstandard1.3</TargetFrameworks> | <TargetFrameworks>net45;netstandard1.1;netstandard1.3</TargetFrameworks> | ||||
| </PropertyGroup> | </PropertyGroup> | ||||
| <ItemGroup> | <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.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> | </ItemGroup> | ||||
| </Project> | </Project> | ||||
| @@ -1,8 +1,13 @@ | |||||
| namespace Discord | |||||
| using Discord.Serialization; | |||||
| namespace Discord | |||||
| { | { | ||||
| [ModelStringEnum] | |||||
| public enum PermissionTarget | public enum PermissionTarget | ||||
| { | { | ||||
| [ModelEnumValue("role")] | |||||
| Role, | Role, | ||||
| [ModelEnumValue("member")] | |||||
| User | User | ||||
| } | } | ||||
| } | } | ||||
| @@ -7,13 +7,16 @@ namespace Discord | |||||
| public struct Image | public struct Image | ||||
| { | { | ||||
| public Stream Stream { get; } | public Stream Stream { get; } | ||||
| public ImageFormat Format { get; } | |||||
| /// <summary> | /// <summary> | ||||
| /// Create the image with a Stream. | /// Create the image with a Stream. | ||||
| /// </summary> | /// </summary> | ||||
| /// <param name="stream">This must be some type of stream with the contents of a file in it.</param> | /// <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; | Stream = stream; | ||||
| Format = format; | |||||
| } | } | ||||
| #if FILESYSTEM | #if FILESYSTEM | ||||
| /// <summary> | /// <summary> | ||||
| @@ -23,9 +26,10 @@ namespace Discord | |||||
| /// This file path is NOT validated, and is passed directly into a <see cref="File.OpenRead(string)"/> | /// This file path is NOT validated, and is passed directly into a <see cref="File.OpenRead(string)"/> | ||||
| /// </remarks> | /// </remarks> | ||||
| /// <param name="path">The path to the file.</param> | /// <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); | Stream = File.OpenRead(path); | ||||
| Format = format; | |||||
| } | } | ||||
| #endif | #endif | ||||
| } | } | ||||
| @@ -1,13 +1,16 @@ | |||||
| namespace Discord | |||||
| using Discord.Serialization; | |||||
| namespace Discord | |||||
| { | { | ||||
| [ModelStringEnum] | |||||
| public enum EmbedType | 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 | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,4 +1,6 @@ | |||||
| namespace Discord | |||||
| using Discord.Serialization; | |||||
| namespace Discord | |||||
| { | { | ||||
| public struct Overwrite | public struct Overwrite | ||||
| { | { | ||||
| @@ -1,12 +1,21 @@ | |||||
| namespace Discord | |||||
| using Discord.Serialization; | |||||
| namespace Discord | |||||
| { | { | ||||
| [ModelStringEnum] | |||||
| public enum UserStatus | public enum UserStatus | ||||
| { | { | ||||
| [ModelEnumValue("offline", EnumValueType.ReadOnly)] | |||||
| Offline, | Offline, | ||||
| [ModelEnumValue("online")] | |||||
| Online, | Online, | ||||
| [ModelEnumValue("idle")] | |||||
| Idle, | Idle, | ||||
| [ModelEnumValue("idle", EnumValueType.WriteOnly)] | |||||
| AFK, | AFK, | ||||
| [ModelEnumValue("dnd")] | |||||
| DoNotDisturb, | DoNotDisturb, | ||||
| [ModelEnumValue("invisible", EnumValueType.WriteOnly)] | |||||
| Invisible, | Invisible, | ||||
| } | } | ||||
| } | } | ||||
| @@ -3,7 +3,7 @@ | |||||
| public static class Format | public static class Format | ||||
| { | { | ||||
| // Characters which need escaping | // Characters which need escaping | ||||
| private static string[] SensitiveCharacters = { "\\", "*", "_", "~", "`" }; | |||||
| private static string[] _sensitiveCharacters = { "\\", "*", "_", "~", "`" }; | |||||
| /// <summary> Returns a markdown-formatted string with bold formatting. </summary> | /// <summary> Returns a markdown-formatted string with bold formatting. </summary> | ||||
| public static string Bold(string text) => $"**{text}**"; | public static string Bold(string text) => $"**{text}**"; | ||||
| @@ -26,7 +26,7 @@ | |||||
| /// <summary> Sanitizes the string, safely escaping any Markdown sequences. </summary> | /// <summary> Sanitizes the string, safely escaping any Markdown sequences. </summary> | ||||
| public static string Sanitize(string text) | public static string Sanitize(string text) | ||||
| { | { | ||||
| foreach (string unsafeChar in SensitiveCharacters) | |||||
| foreach (string unsafeChar in _sensitiveCharacters) | |||||
| text = text.Replace(unsafeChar, $"\\{unsafeChar}"); | text = text.Replace(unsafeChar, $"\\{unsafeChar}"); | ||||
| return text; | return text; | ||||
| } | } | ||||
| @@ -1,3 +1,4 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Threading; | using System.Threading; | ||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| @@ -10,7 +11,7 @@ namespace Discord.Net.Rest | |||||
| void SetCancelToken(CancellationToken cancelToken); | 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, 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); | Task<RestResponse> SendAsync(string method, string endpoint, IReadOnlyDictionary<string, object> multipartParams, CancellationToken cancelToken, bool headerOnly = false, string reason = null); | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,5 +1,5 @@ | |||||
| using System.Collections.Generic; | |||||
| using System.IO; | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Net; | using System.Net; | ||||
| namespace Discord.Net.Rest | namespace Discord.Net.Rest | ||||
| @@ -8,13 +8,13 @@ namespace Discord.Net.Rest | |||||
| { | { | ||||
| public HttpStatusCode StatusCode { get; } | public HttpStatusCode StatusCode { get; } | ||||
| public Dictionary<string, string> Headers { 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; | StatusCode = statusCode; | ||||
| Headers = headers; | Headers = headers; | ||||
| Stream = stream; | |||||
| Data = data; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -6,8 +6,7 @@ namespace Discord.Net.WebSockets | |||||
| { | { | ||||
| public interface IWebSocketClient | 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; | event Func<Exception, Task> Closed; | ||||
| void SetHeader(string key, string value); | void SetHeader(string key, string value); | ||||
| @@ -16,6 +15,6 @@ namespace Discord.Net.WebSockets | |||||
| Task ConnectAsync(string host); | Task ConnectAsync(string host); | ||||
| Task DisconnectAsync(); | Task DisconnectAsync(); | ||||
| Task SendAsync(byte[] data, int index, int count, bool isText); | |||||
| Task SendAsync(ReadOnlyBuffer<byte> data, bool isText); | |||||
| } | } | ||||
| } | } | ||||
| @@ -3,6 +3,7 @@ using System; | |||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Linq; | using System.Linq; | ||||
| using System.Text; | using System.Text; | ||||
| using System.Text.Utf8; | |||||
| using System.Threading; | using System.Threading; | ||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| using WebSocket4Net; | using WebSocket4Net; | ||||
| @@ -12,8 +13,7 @@ namespace Discord.Net.Providers.WS4Net | |||||
| { | { | ||||
| internal class WS4NetClient : IWebSocketClient, IDisposable | 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; | public event Func<Exception, Task> Closed; | ||||
| private readonly SemaphoreSlim _lock; | private readonly SemaphoreSlim _lock; | ||||
| @@ -129,15 +129,20 @@ namespace Discord.Net.Providers.WS4Net | |||||
| _cancelToken = CancellationTokenSource.CreateLinkedTokenSource(_parentToken, _cancelTokenSource.Token).Token; | _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); | await _lock.WaitAsync(_cancelToken).ConfigureAwait(false); | ||||
| try | try | ||||
| { | { | ||||
| if (isText) | if (isText) | ||||
| _client.Send(Encoding.UTF8.GetString(data, index, count)); | |||||
| _client.Send(new Utf8String(data.Span).ToString()); | |||||
| else | 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 | finally | ||||
| { | { | ||||
| @@ -147,11 +152,12 @@ namespace Discord.Net.Providers.WS4Net | |||||
| private void OnTextMessage(object sender, MessageReceivedEventArgs e) | 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) | 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) | private void OnConnected(object sender, object e) | ||||
| { | { | ||||
| @@ -1,24 +1,24 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class Application | internal class Application | ||||
| { | { | ||||
| [JsonProperty("description")] | |||||
| [ModelProperty("description")] | |||||
| public string Description { get; set; } | public string Description { get; set; } | ||||
| [JsonProperty("rpc_origins")] | |||||
| [ModelProperty("rpc_origins")] | |||||
| public string[] RPCOrigins { get; set; } | public string[] RPCOrigins { get; set; } | ||||
| [JsonProperty("name")] | |||||
| [ModelProperty("name")] | |||||
| public string Name { get; set; } | public string Name { get; set; } | ||||
| [JsonProperty("id")] | |||||
| [ModelProperty("id")] | |||||
| public ulong Id { get; set; } | public ulong Id { get; set; } | ||||
| [JsonProperty("icon")] | |||||
| [ModelProperty("icon")] | |||||
| public string Icon { get; set; } | public string Icon { get; set; } | ||||
| [JsonProperty("flags"), Int53] | |||||
| [ModelProperty("flags"), Int53] | |||||
| public Optional<ulong> Flags { get; set; } | public Optional<ulong> Flags { get; set; } | ||||
| [JsonProperty("owner")] | |||||
| [ModelProperty("owner")] | |||||
| public Optional<User> Owner { get; set; } | public Optional<User> Owner { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,23 +1,23 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class Attachment | internal class Attachment | ||||
| { | { | ||||
| [JsonProperty("id")] | |||||
| [ModelProperty("id")] | |||||
| public ulong Id { get; set; } | public ulong Id { get; set; } | ||||
| [JsonProperty("filename")] | |||||
| [ModelProperty("filename")] | |||||
| public string Filename { get; set; } | public string Filename { get; set; } | ||||
| [JsonProperty("size")] | |||||
| [ModelProperty("size")] | |||||
| public int Size { get; set; } | public int Size { get; set; } | ||||
| [JsonProperty("url")] | |||||
| [ModelProperty("url")] | |||||
| public string Url { get; set; } | public string Url { get; set; } | ||||
| [JsonProperty("proxy_url")] | |||||
| [ModelProperty("proxy_url")] | |||||
| public string ProxyUrl { get; set; } | public string ProxyUrl { get; set; } | ||||
| [JsonProperty("height")] | |||||
| [ModelProperty("height")] | |||||
| public Optional<int> Height { get; set; } | public Optional<int> Height { get; set; } | ||||
| [JsonProperty("width")] | |||||
| [ModelProperty("width")] | |||||
| public Optional<int> Width { get; set; } | public Optional<int> Width { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,13 +1,13 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class Ban | internal class Ban | ||||
| { | { | ||||
| [JsonProperty("user")] | |||||
| [ModelProperty("user")] | |||||
| public User User { get; set; } | public User User { get; set; } | ||||
| [JsonProperty("reason")] | |||||
| [ModelProperty("reason")] | |||||
| public string Reason { get; set; } | public string Reason { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,5 +1,5 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| using System; | using System; | ||||
| namespace Discord.API | namespace Discord.API | ||||
| @@ -7,41 +7,41 @@ namespace Discord.API | |||||
| internal class Channel | internal class Channel | ||||
| { | { | ||||
| //Shared | //Shared | ||||
| [JsonProperty("id")] | |||||
| [ModelProperty("id")] | |||||
| public ulong Id { get; set; } | public ulong Id { get; set; } | ||||
| [JsonProperty("type")] | |||||
| [ModelProperty("type")] | |||||
| public ChannelType Type { get; set; } | public ChannelType Type { get; set; } | ||||
| [JsonProperty("last_message_id")] | |||||
| [ModelProperty("last_message_id")] | |||||
| public ulong? LastMessageId { get; set; } | public ulong? LastMessageId { get; set; } | ||||
| //GuildChannel | //GuildChannel | ||||
| [JsonProperty("guild_id")] | |||||
| [ModelProperty("guild_id")] | |||||
| public Optional<ulong> GuildId { get; set; } | public Optional<ulong> GuildId { get; set; } | ||||
| [JsonProperty("name")] | |||||
| [ModelProperty("name")] | |||||
| public Optional<string> Name { get; set; } | public Optional<string> Name { get; set; } | ||||
| [JsonProperty("position")] | |||||
| [ModelProperty("position")] | |||||
| public Optional<int> Position { get; set; } | public Optional<int> Position { get; set; } | ||||
| [JsonProperty("permission_overwrites")] | |||||
| [ModelProperty("permission_overwrites")] | |||||
| public Optional<Overwrite[]> PermissionOverwrites { get; set; } | public Optional<Overwrite[]> PermissionOverwrites { get; set; } | ||||
| //TextChannel | //TextChannel | ||||
| [JsonProperty("topic")] | |||||
| [ModelProperty("topic")] | |||||
| public Optional<string> Topic { get; set; } | public Optional<string> Topic { get; set; } | ||||
| [JsonProperty("last_pin_timestamp")] | |||||
| [ModelProperty("last_pin_timestamp")] | |||||
| public Optional<DateTimeOffset?> LastPinTimestamp { get; set; } | public Optional<DateTimeOffset?> LastPinTimestamp { get; set; } | ||||
| //VoiceChannel | //VoiceChannel | ||||
| [JsonProperty("bitrate")] | |||||
| [ModelProperty("bitrate")] | |||||
| public Optional<int> Bitrate { get; set; } | public Optional<int> Bitrate { get; set; } | ||||
| [JsonProperty("user_limit")] | |||||
| [ModelProperty("user_limit")] | |||||
| public Optional<int> UserLimit { get; set; } | public Optional<int> UserLimit { get; set; } | ||||
| //PrivateChannel | //PrivateChannel | ||||
| [JsonProperty("recipients")] | |||||
| [ModelProperty("recipients")] | |||||
| public Optional<User[]> Recipients { get; set; } | public Optional<User[]> Recipients { get; set; } | ||||
| //GroupChannel | //GroupChannel | ||||
| [JsonProperty("icon")] | |||||
| [ModelProperty("icon")] | |||||
| public Optional<string> Icon { get; set; } | public Optional<string> Icon { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,21 +1,21 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class Connection | internal class Connection | ||||
| { | { | ||||
| [JsonProperty("id")] | |||||
| [ModelProperty("id")] | |||||
| public string Id { get; set; } | public string Id { get; set; } | ||||
| [JsonProperty("type")] | |||||
| [ModelProperty("type")] | |||||
| public string Type { get; set; } | public string Type { get; set; } | ||||
| [JsonProperty("name")] | |||||
| [ModelProperty("name")] | |||||
| public string Name { get; set; } | public string Name { get; set; } | ||||
| [JsonProperty("revoked")] | |||||
| [ModelProperty("revoked")] | |||||
| public bool Revoked { get; set; } | public bool Revoked { get; set; } | ||||
| [JsonProperty("integrations")] | |||||
| [ModelProperty("integrations")] | |||||
| public IReadOnlyCollection<ulong> Integrations { get; set; } | public IReadOnlyCollection<ulong> Integrations { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,37 +1,36 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using System; | using System; | ||||
| using Newtonsoft.Json; | |||||
| using Newtonsoft.Json.Converters; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class Embed | internal class Embed | ||||
| { | { | ||||
| [JsonProperty("title")] | |||||
| [ModelProperty("title")] | |||||
| public string Title { get; set; } | public string Title { get; set; } | ||||
| [JsonProperty("description")] | |||||
| [ModelProperty("description")] | |||||
| public string Description { get; set; } | public string Description { get; set; } | ||||
| [JsonProperty("url")] | |||||
| [ModelProperty("url")] | |||||
| public string Url { get; set; } | public string Url { get; set; } | ||||
| [JsonProperty("color")] | |||||
| [ModelProperty("color")] | |||||
| public uint? Color { get; set; } | public uint? Color { get; set; } | ||||
| [JsonProperty("type"), JsonConverter(typeof(StringEnumConverter))] | |||||
| [ModelProperty("type")] | |||||
| public EmbedType Type { get; set; } | public EmbedType Type { get; set; } | ||||
| [JsonProperty("timestamp")] | |||||
| [ModelProperty("timestamp")] | |||||
| public DateTimeOffset? Timestamp { get; set; } | public DateTimeOffset? Timestamp { get; set; } | ||||
| [JsonProperty("author")] | |||||
| [ModelProperty("author")] | |||||
| public Optional<EmbedAuthor> Author { get; set; } | public Optional<EmbedAuthor> Author { get; set; } | ||||
| [JsonProperty("footer")] | |||||
| [ModelProperty("footer")] | |||||
| public Optional<EmbedFooter> Footer { get; set; } | public Optional<EmbedFooter> Footer { get; set; } | ||||
| [JsonProperty("video")] | |||||
| [ModelProperty("video")] | |||||
| public Optional<EmbedVideo> Video { get; set; } | public Optional<EmbedVideo> Video { get; set; } | ||||
| [JsonProperty("thumbnail")] | |||||
| [ModelProperty("thumbnail")] | |||||
| public Optional<EmbedThumbnail> Thumbnail { get; set; } | public Optional<EmbedThumbnail> Thumbnail { get; set; } | ||||
| [JsonProperty("image")] | |||||
| [ModelProperty("image")] | |||||
| public Optional<EmbedImage> Image { get; set; } | public Optional<EmbedImage> Image { get; set; } | ||||
| [JsonProperty("provider")] | |||||
| [ModelProperty("provider")] | |||||
| public Optional<EmbedProvider> Provider { get; set; } | public Optional<EmbedProvider> Provider { get; set; } | ||||
| [JsonProperty("fields")] | |||||
| [ModelProperty("fields")] | |||||
| public Optional<EmbedField[]> Fields { get; set; } | public Optional<EmbedField[]> Fields { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,17 +1,17 @@ | |||||
| using System; | using System; | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class EmbedAuthor | internal class EmbedAuthor | ||||
| { | { | ||||
| [JsonProperty("name")] | |||||
| [ModelProperty("name")] | |||||
| public string Name { get; set; } | public string Name { get; set; } | ||||
| [JsonProperty("url")] | |||||
| [ModelProperty("url")] | |||||
| public string Url { get; set; } | public string Url { get; set; } | ||||
| [JsonProperty("icon_url")] | |||||
| [ModelProperty("icon_url")] | |||||
| public string IconUrl { get; set; } | public string IconUrl { get; set; } | ||||
| [JsonProperty("proxy_icon_url")] | |||||
| [ModelProperty("proxy_icon_url")] | |||||
| public string ProxyIconUrl { get; set; } | public string ProxyIconUrl { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,14 +1,14 @@ | |||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class EmbedField | internal class EmbedField | ||||
| { | { | ||||
| [JsonProperty("name")] | |||||
| [ModelProperty("name")] | |||||
| public string Name { get; set; } | public string Name { get; set; } | ||||
| [JsonProperty("value")] | |||||
| [ModelProperty("value")] | |||||
| public string Value { get; set; } | public string Value { get; set; } | ||||
| [JsonProperty("inline")] | |||||
| [ModelProperty("inline")] | |||||
| public bool Inline { get; set; } | public bool Inline { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,15 +1,15 @@ | |||||
| using System; | using System; | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class EmbedFooter | internal class EmbedFooter | ||||
| { | { | ||||
| [JsonProperty("text")] | |||||
| [ModelProperty("text")] | |||||
| public string Text { get; set; } | public string Text { get; set; } | ||||
| [JsonProperty("icon_url")] | |||||
| [ModelProperty("icon_url")] | |||||
| public string IconUrl { get; set; } | public string IconUrl { get; set; } | ||||
| [JsonProperty("proxy_icon_url")] | |||||
| [ModelProperty("proxy_icon_url")] | |||||
| public string ProxyIconUrl { get; set; } | public string ProxyIconUrl { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,18 +1,18 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using System; | using System; | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class EmbedImage | internal class EmbedImage | ||||
| { | { | ||||
| [JsonProperty("url")] | |||||
| [ModelProperty("url")] | |||||
| public string Url { get; set; } | public string Url { get; set; } | ||||
| [JsonProperty("proxy_url")] | |||||
| [ModelProperty("proxy_url")] | |||||
| public string ProxyUrl { get; set; } | public string ProxyUrl { get; set; } | ||||
| [JsonProperty("height")] | |||||
| [ModelProperty("height")] | |||||
| public Optional<int> Height { get; set; } | public Optional<int> Height { get; set; } | ||||
| [JsonProperty("width")] | |||||
| [ModelProperty("width")] | |||||
| public Optional<int> Width { get; set; } | public Optional<int> Width { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,14 +1,14 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using System; | using System; | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class EmbedProvider | internal class EmbedProvider | ||||
| { | { | ||||
| [JsonProperty("name")] | |||||
| [ModelProperty("name")] | |||||
| public string Name { get; set; } | public string Name { get; set; } | ||||
| [JsonProperty("url")] | |||||
| [ModelProperty("url")] | |||||
| public string Url { get; set; } | public string Url { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,18 +1,18 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using System; | using System; | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class EmbedThumbnail | internal class EmbedThumbnail | ||||
| { | { | ||||
| [JsonProperty("url")] | |||||
| [ModelProperty("url")] | |||||
| public string Url { get; set; } | public string Url { get; set; } | ||||
| [JsonProperty("proxy_url")] | |||||
| [ModelProperty("proxy_url")] | |||||
| public string ProxyUrl { get; set; } | public string ProxyUrl { get; set; } | ||||
| [JsonProperty("height")] | |||||
| [ModelProperty("height")] | |||||
| public Optional<int> Height { get; set; } | public Optional<int> Height { get; set; } | ||||
| [JsonProperty("width")] | |||||
| [ModelProperty("width")] | |||||
| public Optional<int> Width { get; set; } | public Optional<int> Width { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,16 +1,16 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using System; | using System; | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class EmbedVideo | internal class EmbedVideo | ||||
| { | { | ||||
| [JsonProperty("url")] | |||||
| [ModelProperty("url")] | |||||
| public string Url { get; set; } | public string Url { get; set; } | ||||
| [JsonProperty("height")] | |||||
| [ModelProperty("height")] | |||||
| public Optional<int> Height { get; set; } | public Optional<int> Height { get; set; } | ||||
| [JsonProperty("width")] | |||||
| [ModelProperty("width")] | |||||
| public Optional<int> Width { get; set; } | public Optional<int> Width { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,19 +1,19 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class Emoji | internal class Emoji | ||||
| { | { | ||||
| [JsonProperty("id")] | |||||
| [ModelProperty("id")] | |||||
| public ulong? Id { get; set; } | public ulong? Id { get; set; } | ||||
| [JsonProperty("name")] | |||||
| [ModelProperty("name")] | |||||
| public string Name { get; set; } | public string Name { get; set; } | ||||
| [JsonProperty("roles")] | |||||
| [ModelProperty("roles")] | |||||
| public ulong[] Roles { get; set; } | public ulong[] Roles { get; set; } | ||||
| [JsonProperty("require_colons")] | |||||
| [ModelProperty("require_colons")] | |||||
| public bool RequireColons { get; set; } | public bool RequireColons { get; set; } | ||||
| [JsonProperty("managed")] | |||||
| [ModelProperty("managed")] | |||||
| public bool Managed { get; set; } | public bool Managed { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,23 +1,15 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Newtonsoft.Json.Serialization; | |||||
| using System.Runtime.Serialization; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class Game | internal class Game | ||||
| { | { | ||||
| [JsonProperty("name")] | |||||
| [ModelProperty("name")] | |||||
| public string Name { get; set; } | public string Name { get; set; } | ||||
| [JsonProperty("url")] | |||||
| [ModelProperty("url")] | |||||
| public Optional<string> StreamUrl { get; set; } | public Optional<string> StreamUrl { get; set; } | ||||
| [JsonProperty("type")] | |||||
| [ModelProperty("type")] | |||||
| public Optional<StreamType?> StreamType { get; set; } | public Optional<StreamType?> StreamType { get; set; } | ||||
| [OnError] | |||||
| internal void OnError(StreamingContext context, ErrorContext errorContext) | |||||
| { | |||||
| errorContext.Handled = true; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,43 +1,43 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class Guild | internal class Guild | ||||
| { | { | ||||
| [JsonProperty("id")] | |||||
| [ModelProperty("id")] | |||||
| public ulong Id { get; set; } | public ulong Id { get; set; } | ||||
| [JsonProperty("name")] | |||||
| [ModelProperty("name")] | |||||
| public string Name { get; set; } | public string Name { get; set; } | ||||
| [JsonProperty("icon")] | |||||
| [ModelProperty("icon")] | |||||
| public string Icon { get; set; } | public string Icon { get; set; } | ||||
| [JsonProperty("splash")] | |||||
| [ModelProperty("splash")] | |||||
| public string Splash { get; set; } | public string Splash { get; set; } | ||||
| [JsonProperty("owner_id")] | |||||
| [ModelProperty("owner_id")] | |||||
| public ulong OwnerId { get; set; } | public ulong OwnerId { get; set; } | ||||
| [JsonProperty("region")] | |||||
| [ModelProperty("region")] | |||||
| public string Region { get; set; } | public string Region { get; set; } | ||||
| [JsonProperty("afk_channel_id")] | |||||
| [ModelProperty("afk_channel_id")] | |||||
| public ulong? AFKChannelId { get; set; } | public ulong? AFKChannelId { get; set; } | ||||
| [JsonProperty("afk_timeout")] | |||||
| [ModelProperty("afk_timeout")] | |||||
| public int AFKTimeout { get; set; } | public int AFKTimeout { get; set; } | ||||
| [JsonProperty("embed_enabled")] | |||||
| [ModelProperty("embed_enabled")] | |||||
| public bool EmbedEnabled { get; set; } | public bool EmbedEnabled { get; set; } | ||||
| [JsonProperty("embed_channel_id")] | |||||
| [ModelProperty("embed_channel_id")] | |||||
| public ulong? EmbedChannelId { get; set; } | public ulong? EmbedChannelId { get; set; } | ||||
| [JsonProperty("verification_level")] | |||||
| [ModelProperty("verification_level")] | |||||
| public VerificationLevel VerificationLevel { get; set; } | public VerificationLevel VerificationLevel { get; set; } | ||||
| [JsonProperty("voice_states")] | |||||
| [ModelProperty("voice_states")] | |||||
| public VoiceState[] VoiceStates { get; set; } | public VoiceState[] VoiceStates { get; set; } | ||||
| [JsonProperty("roles")] | |||||
| [ModelProperty("roles")] | |||||
| public Role[] Roles { get; set; } | public Role[] Roles { get; set; } | ||||
| [JsonProperty("emojis")] | |||||
| [ModelProperty("emojis")] | |||||
| public Emoji[] Emojis { get; set; } | public Emoji[] Emojis { get; set; } | ||||
| [JsonProperty("features")] | |||||
| [ModelProperty("features")] | |||||
| public string[] Features { get; set; } | public string[] Features { get; set; } | ||||
| [JsonProperty("mfa_level")] | |||||
| [ModelProperty("mfa_level")] | |||||
| public MfaLevel MfaLevel { get; set; } | public MfaLevel MfaLevel { get; set; } | ||||
| [JsonProperty("default_message_notifications")] | |||||
| [ModelProperty("default_message_notifications")] | |||||
| public DefaultMessageNotifications DefaultMessageNotifications { get; set; } | public DefaultMessageNotifications DefaultMessageNotifications { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,13 +1,13 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class GuildEmbed | internal class GuildEmbed | ||||
| { | { | ||||
| [JsonProperty("enabled")] | |||||
| [ModelProperty("enabled")] | |||||
| public bool Enabled { get; set; } | public bool Enabled { get; set; } | ||||
| [JsonProperty("channel_id")] | |||||
| [ModelProperty("channel_id")] | |||||
| public ulong ChannelId { get; set; } | public ulong ChannelId { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,22 +1,22 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| using System; | using System; | ||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class GuildMember | internal class GuildMember | ||||
| { | { | ||||
| [JsonProperty("user")] | |||||
| [ModelProperty("user")] | |||||
| public User User { get; set; } | public User User { get; set; } | ||||
| [JsonProperty("nick")] | |||||
| [ModelProperty("nick")] | |||||
| public Optional<string> Nick { get; set; } | public Optional<string> Nick { get; set; } | ||||
| [JsonProperty("roles")] | |||||
| [ModelProperty("roles")] | |||||
| public Optional<ulong[]> Roles { get; set; } | public Optional<ulong[]> Roles { get; set; } | ||||
| [JsonProperty("joined_at")] | |||||
| [ModelProperty("joined_at")] | |||||
| public Optional<DateTimeOffset> JoinedAt { get; set; } | public Optional<DateTimeOffset> JoinedAt { get; set; } | ||||
| [JsonProperty("deaf")] | |||||
| [ModelProperty("deaf")] | |||||
| public Optional<bool> Deaf { get; set; } | public Optional<bool> Deaf { get; set; } | ||||
| [JsonProperty("mute")] | |||||
| [ModelProperty("mute")] | |||||
| public Optional<bool> Mute { get; set; } | public Optional<bool> Mute { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,32 +1,32 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| using System; | using System; | ||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class Integration | internal class Integration | ||||
| { | { | ||||
| [JsonProperty("id")] | |||||
| [ModelProperty("id")] | |||||
| public ulong Id { get; set; } | public ulong Id { get; set; } | ||||
| [JsonProperty("name")] | |||||
| [ModelProperty("name")] | |||||
| public string Name { get; set; } | public string Name { get; set; } | ||||
| [JsonProperty("type")] | |||||
| [ModelProperty("type")] | |||||
| public string Type { get; set; } | public string Type { get; set; } | ||||
| [JsonProperty("enabled")] | |||||
| [ModelProperty("enabled")] | |||||
| public bool Enabled { get; set; } | public bool Enabled { get; set; } | ||||
| [JsonProperty("syncing")] | |||||
| [ModelProperty("syncing")] | |||||
| public bool Syncing { get; set; } | public bool Syncing { get; set; } | ||||
| [JsonProperty("role_id")] | |||||
| [ModelProperty("role_id")] | |||||
| public ulong RoleId { get; set; } | public ulong RoleId { get; set; } | ||||
| [JsonProperty("expire_behavior")] | |||||
| [ModelProperty("expire_behavior")] | |||||
| public ulong ExpireBehavior { get; set; } | public ulong ExpireBehavior { get; set; } | ||||
| [JsonProperty("expire_grace_period")] | |||||
| [ModelProperty("expire_grace_period")] | |||||
| public ulong ExpireGracePeriod { get; set; } | public ulong ExpireGracePeriod { get; set; } | ||||
| [JsonProperty("user")] | |||||
| [ModelProperty("user")] | |||||
| public User User { get; set; } | public User User { get; set; } | ||||
| [JsonProperty("account")] | |||||
| [ModelProperty("account")] | |||||
| public IntegrationAccount Account { get; set; } | public IntegrationAccount Account { get; set; } | ||||
| [JsonProperty("synced_at")] | |||||
| [ModelProperty("synced_at")] | |||||
| public DateTimeOffset SyncedAt { get; set; } | public DateTimeOffset SyncedAt { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,13 +1,13 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class IntegrationAccount | internal class IntegrationAccount | ||||
| { | { | ||||
| [JsonProperty("id")] | |||||
| [ModelProperty("id")] | |||||
| public ulong Id { get; set; } | public ulong Id { get; set; } | ||||
| [JsonProperty("name")] | |||||
| [ModelProperty("name")] | |||||
| public string Name { get; set; } | public string Name { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,15 +1,15 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class Invite | internal class Invite | ||||
| { | { | ||||
| [JsonProperty("code")] | |||||
| [ModelProperty("code")] | |||||
| public string Code { get; set; } | public string Code { get; set; } | ||||
| [JsonProperty("guild")] | |||||
| [ModelProperty("guild")] | |||||
| public InviteGuild Guild { get; set; } | public InviteGuild Guild { get; set; } | ||||
| [JsonProperty("channel")] | |||||
| [ModelProperty("channel")] | |||||
| public InviteChannel Channel { get; set; } | public InviteChannel Channel { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,15 +1,15 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class InviteChannel | internal class InviteChannel | ||||
| { | { | ||||
| [JsonProperty("id")] | |||||
| [ModelProperty("id")] | |||||
| public ulong Id { get; set; } | public ulong Id { get; set; } | ||||
| [JsonProperty("name")] | |||||
| [ModelProperty("name")] | |||||
| public string Name { get; set; } | public string Name { get; set; } | ||||
| [JsonProperty("type")] | |||||
| [ModelProperty("type")] | |||||
| public string Type { get; set; } | public string Type { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,15 +1,15 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class InviteGuild | internal class InviteGuild | ||||
| { | { | ||||
| [JsonProperty("id")] | |||||
| [ModelProperty("id")] | |||||
| public ulong Id { get; set; } | public ulong Id { get; set; } | ||||
| [JsonProperty("name")] | |||||
| [ModelProperty("name")] | |||||
| public string Name { get; set; } | public string Name { get; set; } | ||||
| [JsonProperty("splash_hash")] | |||||
| [ModelProperty("splash_hash")] | |||||
| public string SplashHash { get; set; } | public string SplashHash { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,24 +1,24 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| using System; | using System; | ||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class InviteMetadata : Invite | internal class InviteMetadata : Invite | ||||
| { | { | ||||
| [JsonProperty("inviter")] | |||||
| [ModelProperty("inviter")] | |||||
| public User Inviter { get; set; } | public User Inviter { get; set; } | ||||
| [JsonProperty("uses")] | |||||
| [ModelProperty("uses")] | |||||
| public int Uses { get; set; } | public int Uses { get; set; } | ||||
| [JsonProperty("max_uses")] | |||||
| [ModelProperty("max_uses")] | |||||
| public int MaxUses { get; set; } | public int MaxUses { get; set; } | ||||
| [JsonProperty("max_age")] | |||||
| [ModelProperty("max_age")] | |||||
| public int MaxAge { get; set; } | public int MaxAge { get; set; } | ||||
| [JsonProperty("temporary")] | |||||
| [ModelProperty("temporary")] | |||||
| public bool Temporary { get; set; } | public bool Temporary { get; set; } | ||||
| [JsonProperty("created_at")] | |||||
| [ModelProperty("created_at")] | |||||
| public DateTimeOffset CreatedAt { get; set; } | public DateTimeOffset CreatedAt { get; set; } | ||||
| [JsonProperty("revoked")] | |||||
| [ModelProperty("revoked")] | |||||
| public bool Revoked { get; set; } | public bool Revoked { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,42 +1,42 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| using System; | using System; | ||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class Message | internal class Message | ||||
| { | { | ||||
| [JsonProperty("id")] | |||||
| [ModelProperty("id")] | |||||
| public ulong Id { get; set; } | public ulong Id { get; set; } | ||||
| [JsonProperty("type")] | |||||
| [ModelProperty("type")] | |||||
| public MessageType Type { get; set; } | public MessageType Type { get; set; } | ||||
| [JsonProperty("channel_id")] | |||||
| [ModelProperty("channel_id")] | |||||
| public ulong ChannelId { get; set; } | public ulong ChannelId { get; set; } | ||||
| [JsonProperty("webhook_id")] | |||||
| [ModelProperty("webhook_id")] | |||||
| public Optional<ulong> WebhookId { get; set; } | public Optional<ulong> WebhookId { get; set; } | ||||
| [JsonProperty("author")] | |||||
| [ModelProperty("author")] | |||||
| public Optional<User> Author { get; set; } | public Optional<User> Author { get; set; } | ||||
| [JsonProperty("content")] | |||||
| [ModelProperty("content")] | |||||
| public Optional<string> Content { get; set; } | public Optional<string> Content { get; set; } | ||||
| [JsonProperty("timestamp")] | |||||
| [ModelProperty("timestamp")] | |||||
| public Optional<DateTimeOffset> Timestamp { get; set; } | public Optional<DateTimeOffset> Timestamp { get; set; } | ||||
| [JsonProperty("edited_timestamp")] | |||||
| [ModelProperty("edited_timestamp")] | |||||
| public Optional<DateTimeOffset?> EditedTimestamp { get; set; } | public Optional<DateTimeOffset?> EditedTimestamp { get; set; } | ||||
| [JsonProperty("tts")] | |||||
| [ModelProperty("tts")] | |||||
| public Optional<bool> IsTextToSpeech { get; set; } | public Optional<bool> IsTextToSpeech { get; set; } | ||||
| [JsonProperty("mention_everyone")] | |||||
| [ModelProperty("mention_everyone")] | |||||
| public Optional<bool> MentionEveryone { get; set; } | public Optional<bool> MentionEveryone { get; set; } | ||||
| [JsonProperty("mentions")] | |||||
| [ModelProperty("mentions")] | |||||
| public Optional<EntityOrId<User>[]> UserMentions { get; set; } | public Optional<EntityOrId<User>[]> UserMentions { get; set; } | ||||
| [JsonProperty("mention_roles")] | |||||
| [ModelProperty("mention_roles")] | |||||
| public Optional<ulong[]> RoleMentions { get; set; } | public Optional<ulong[]> RoleMentions { get; set; } | ||||
| [JsonProperty("attachments")] | |||||
| [ModelProperty("attachments")] | |||||
| public Optional<Attachment[]> Attachments { get; set; } | public Optional<Attachment[]> Attachments { get; set; } | ||||
| [JsonProperty("embeds")] | |||||
| [ModelProperty("embeds")] | |||||
| public Optional<Embed[]> Embeds { get; set; } | public Optional<Embed[]> Embeds { get; set; } | ||||
| [JsonProperty("pinned")] | |||||
| [ModelProperty("pinned")] | |||||
| public Optional<bool> Pinned { get; set; } | public Optional<bool> Pinned { get; set; } | ||||
| [JsonProperty("reactions")] | |||||
| [ModelProperty("reactions")] | |||||
| public Optional<Reaction[]> Reactions { get; set; } | public Optional<Reaction[]> Reactions { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,17 +1,17 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class Overwrite | internal class Overwrite | ||||
| { | { | ||||
| [JsonProperty("id")] | |||||
| [ModelProperty("id")] | |||||
| public ulong TargetId { get; set; } | public ulong TargetId { get; set; } | ||||
| [JsonProperty("type")] | |||||
| [ModelProperty("type")] | |||||
| public PermissionTarget TargetType { get; set; } | public PermissionTarget TargetType { get; set; } | ||||
| [JsonProperty("deny"), Int53] | |||||
| [ModelProperty("deny"), Int53] | |||||
| public ulong Deny { get; set; } | public ulong Deny { get; set; } | ||||
| [JsonProperty("allow"), Int53] | |||||
| [ModelProperty("allow"), Int53] | |||||
| public ulong Allow { get; set; } | public ulong Allow { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,22 +1,22 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class Presence | internal class Presence | ||||
| { | { | ||||
| [JsonProperty("user")] | |||||
| [ModelProperty("user")] | |||||
| public User User { get; set; } | public User User { get; set; } | ||||
| [JsonProperty("guild_id")] | |||||
| [ModelProperty("guild_id")] | |||||
| public Optional<ulong> GuildId { get; set; } | public Optional<ulong> GuildId { get; set; } | ||||
| [JsonProperty("status")] | |||||
| [ModelProperty("status")] | |||||
| public UserStatus Status { get; set; } | public UserStatus Status { get; set; } | ||||
| [JsonProperty("game")] | |||||
| [ModelProperty("game")] | |||||
| public Game Game { get; set; } | public Game Game { get; set; } | ||||
| [JsonProperty("roles")] | |||||
| [ModelProperty("roles")] | |||||
| public Optional<ulong[]> Roles { get; set; } | public Optional<ulong[]> Roles { get; set; } | ||||
| [JsonProperty("nick")] | |||||
| [ModelProperty("nick")] | |||||
| public Optional<string> Nick { get; set; } | public Optional<string> Nick { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,14 +1,14 @@ | |||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class Reaction | internal class Reaction | ||||
| { | { | ||||
| [JsonProperty("count")] | |||||
| [ModelProperty("count")] | |||||
| public int Count { get; set; } | public int Count { get; set; } | ||||
| [JsonProperty("me")] | |||||
| [ModelProperty("me")] | |||||
| public bool Me { get; set; } | public bool Me { get; set; } | ||||
| [JsonProperty("emoji")] | |||||
| [ModelProperty("emoji")] | |||||
| public Emoji Emoji { get; set; } | public Emoji Emoji { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,15 +1,15 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class ReadState | internal class ReadState | ||||
| { | { | ||||
| [JsonProperty("id")] | |||||
| [ModelProperty("id")] | |||||
| public ulong Id { get; set; } | public ulong Id { get; set; } | ||||
| [JsonProperty("mention_count")] | |||||
| [ModelProperty("mention_count")] | |||||
| public int MentionCount { get; set; } | public int MentionCount { get; set; } | ||||
| [JsonProperty("last_message_id")] | |||||
| [ModelProperty("last_message_id")] | |||||
| public Optional<ulong> LastMessageId { get; set; } | public Optional<ulong> LastMessageId { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,15 +1,15 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class Relationship | internal class Relationship | ||||
| { | { | ||||
| [JsonProperty("id")] | |||||
| [ModelProperty("id")] | |||||
| public ulong Id { get; set; } | public ulong Id { get; set; } | ||||
| [JsonProperty("user")] | |||||
| [ModelProperty("user")] | |||||
| public User User { get; set; } | public User User { get; set; } | ||||
| [JsonProperty("type")] | |||||
| [ModelProperty("type")] | |||||
| public RelationshipType Type { get; set; } | public RelationshipType Type { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,25 +1,25 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class Role | internal class Role | ||||
| { | { | ||||
| [JsonProperty("id")] | |||||
| [ModelProperty("id")] | |||||
| public ulong Id { get; set; } | public ulong Id { get; set; } | ||||
| [JsonProperty("name")] | |||||
| [ModelProperty("name")] | |||||
| public string Name { get; set; } | public string Name { get; set; } | ||||
| [JsonProperty("color")] | |||||
| [ModelProperty("color")] | |||||
| public uint Color { get; set; } | public uint Color { get; set; } | ||||
| [JsonProperty("hoist")] | |||||
| [ModelProperty("hoist")] | |||||
| public bool Hoist { get; set; } | public bool Hoist { get; set; } | ||||
| [JsonProperty("mentionable")] | |||||
| [ModelProperty("mentionable")] | |||||
| public bool Mentionable { get; set; } | public bool Mentionable { get; set; } | ||||
| [JsonProperty("position")] | |||||
| [ModelProperty("position")] | |||||
| public int Position { get; set; } | public int Position { get; set; } | ||||
| [JsonProperty("permissions"), Int53] | |||||
| [ModelProperty("permissions"), Int53] | |||||
| public ulong Permissions { get; set; } | public ulong Permissions { get; set; } | ||||
| [JsonProperty("managed")] | |||||
| [ModelProperty("managed")] | |||||
| public bool Managed { get; set; } | public bool Managed { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,27 +1,27 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class User | internal class User | ||||
| { | { | ||||
| [JsonProperty("id")] | |||||
| [ModelProperty("id")] | |||||
| public ulong Id { get; set; } | public ulong Id { get; set; } | ||||
| [JsonProperty("username")] | |||||
| [ModelProperty("username")] | |||||
| public Optional<string> Username { get; set; } | public Optional<string> Username { get; set; } | ||||
| [JsonProperty("discriminator")] | |||||
| [ModelProperty("discriminator")] | |||||
| public Optional<string> Discriminator { get; set; } | public Optional<string> Discriminator { get; set; } | ||||
| [JsonProperty("bot")] | |||||
| [ModelProperty("bot")] | |||||
| public Optional<bool> Bot { get; set; } | public Optional<bool> Bot { get; set; } | ||||
| [JsonProperty("avatar")] | |||||
| [ModelProperty("avatar")] | |||||
| public Optional<string> Avatar { get; set; } | public Optional<string> Avatar { get; set; } | ||||
| //CurrentUser | //CurrentUser | ||||
| [JsonProperty("verified")] | |||||
| [ModelProperty("verified")] | |||||
| public Optional<bool> Verified { get; set; } | public Optional<bool> Verified { get; set; } | ||||
| [JsonProperty("email")] | |||||
| [ModelProperty("email")] | |||||
| public Optional<string> Email { get; set; } | public Optional<string> Email { get; set; } | ||||
| [JsonProperty("mfa_enabled")] | |||||
| [ModelProperty("mfa_enabled")] | |||||
| public Optional<bool> MfaEnabled { get; set; } | public Optional<bool> MfaEnabled { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,19 +1,19 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class UserGuild | internal class UserGuild | ||||
| { | { | ||||
| [JsonProperty("id")] | |||||
| [ModelProperty("id")] | |||||
| public ulong Id { get; set; } | public ulong Id { get; set; } | ||||
| [JsonProperty("name")] | |||||
| [ModelProperty("name")] | |||||
| public string Name { get; set; } | public string Name { get; set; } | ||||
| [JsonProperty("icon")] | |||||
| [ModelProperty("icon")] | |||||
| public string Icon { get; set; } | public string Icon { get; set; } | ||||
| [JsonProperty("owner")] | |||||
| [ModelProperty("owner")] | |||||
| public bool Owner { get; set; } | public bool Owner { get; set; } | ||||
| [JsonProperty("permissions"), Int53] | |||||
| [ModelProperty("permissions"), Int53] | |||||
| public ulong Permissions { get; set; } | public ulong Permissions { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,21 +1,21 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class VoiceRegion | internal class VoiceRegion | ||||
| { | { | ||||
| [JsonProperty("id")] | |||||
| [ModelProperty("id")] | |||||
| public string Id { get; set; } | public string Id { get; set; } | ||||
| [JsonProperty("name")] | |||||
| [ModelProperty("name")] | |||||
| public string Name { get; set; } | public string Name { get; set; } | ||||
| [JsonProperty("vip")] | |||||
| [ModelProperty("vip")] | |||||
| public bool IsVip { get; set; } | public bool IsVip { get; set; } | ||||
| [JsonProperty("optimal")] | |||||
| [ModelProperty("optimal")] | |||||
| public bool IsOptimal { get; set; } | public bool IsOptimal { get; set; } | ||||
| [JsonProperty("sample_hostname")] | |||||
| [ModelProperty("sample_hostname")] | |||||
| public string SampleHostname { get; set; } | public string SampleHostname { get; set; } | ||||
| [JsonProperty("sample_port")] | |||||
| [ModelProperty("sample_port")] | |||||
| public int SamplePort { get; set; } | public int SamplePort { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,27 +1,27 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API | namespace Discord.API | ||||
| { | { | ||||
| internal class VoiceState | internal class VoiceState | ||||
| { | { | ||||
| [JsonProperty("guild_id")] | |||||
| [ModelProperty("guild_id")] | |||||
| public ulong? GuildId { get; set; } | public ulong? GuildId { get; set; } | ||||
| [JsonProperty("channel_id")] | |||||
| [ModelProperty("channel_id")] | |||||
| public ulong? ChannelId { get; set; } | public ulong? ChannelId { get; set; } | ||||
| [JsonProperty("user_id")] | |||||
| [ModelProperty("user_id")] | |||||
| public ulong UserId { get; set; } | public ulong UserId { get; set; } | ||||
| [JsonProperty("session_id")] | |||||
| [ModelProperty("session_id")] | |||||
| public string SessionId { get; set; } | public string SessionId { get; set; } | ||||
| [JsonProperty("deaf")] | |||||
| [ModelProperty("deaf")] | |||||
| public bool Deaf { get; set; } | public bool Deaf { get; set; } | ||||
| [JsonProperty("mute")] | |||||
| [ModelProperty("mute")] | |||||
| public bool Mute { get; set; } | public bool Mute { get; set; } | ||||
| [JsonProperty("self_deaf")] | |||||
| [ModelProperty("self_deaf")] | |||||
| public bool SelfDeaf { get; set; } | public bool SelfDeaf { get; set; } | ||||
| [JsonProperty("self_mute")] | |||||
| [ModelProperty("self_mute")] | |||||
| public bool SelfMute { get; set; } | public bool SelfMute { get; set; } | ||||
| [JsonProperty("suppress")] | |||||
| [ModelProperty("suppress")] | |||||
| public bool Suppress { get; set; } | public bool Suppress { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -5,16 +5,19 @@ namespace Discord.API | |||||
| internal struct Image | internal struct Image | ||||
| { | { | ||||
| public Stream Stream { get; } | public Stream Stream { get; } | ||||
| public ImageFormat StreamFormat { get; } | |||||
| public string Hash { get; } | public string Hash { get; } | ||||
| public Image(Stream stream) | |||||
| public Image(Stream stream, ImageFormat format) | |||||
| { | { | ||||
| Stream = stream; | Stream = stream; | ||||
| StreamFormat = format; | |||||
| Hash = null; | Hash = null; | ||||
| } | } | ||||
| public Image(string hash) | public Image(string hash) | ||||
| { | { | ||||
| Stream = null; | Stream = null; | ||||
| StreamFormat = ImageFormat.Jpeg; | |||||
| Hash = hash; | Hash = hash; | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,18 +1,17 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class CreateChannelInviteParams | internal class CreateChannelInviteParams | ||||
| { | { | ||||
| [JsonProperty("max_age")] | |||||
| [ModelProperty("max_age")] | |||||
| public Optional<int> MaxAge { get; set; } | public Optional<int> MaxAge { get; set; } | ||||
| [JsonProperty("max_uses")] | |||||
| [ModelProperty("max_uses")] | |||||
| public Optional<int> MaxUses { get; set; } | public Optional<int> MaxUses { get; set; } | ||||
| [JsonProperty("temporary")] | |||||
| [ModelProperty("temporary")] | |||||
| public Optional<bool> IsTemporary { get; set; } | public Optional<bool> IsTemporary { get; set; } | ||||
| [JsonProperty("unique")] | |||||
| [ModelProperty("unique")] | |||||
| public Optional<bool> IsUnique { get; set; } | public Optional<bool> IsUnique { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,12 +1,11 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class CreateDMChannelParams | internal class CreateDMChannelParams | ||||
| { | { | ||||
| [JsonProperty("recipient_id")] | |||||
| [ModelProperty("recipient_id")] | |||||
| public ulong RecipientId { get; } | public ulong RecipientId { get; } | ||||
| public CreateDMChannelParams(ulong recipientId) | public CreateDMChannelParams(ulong recipientId) | ||||
| @@ -1,17 +1,16 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class CreateGuildChannelParams | internal class CreateGuildChannelParams | ||||
| { | { | ||||
| [JsonProperty("name")] | |||||
| [ModelProperty("name")] | |||||
| public string Name { get; } | public string Name { get; } | ||||
| [JsonProperty("type")] | |||||
| [ModelProperty("type")] | |||||
| public ChannelType Type { get; } | public ChannelType Type { get; } | ||||
| [JsonProperty("bitrate")] | |||||
| [ModelProperty("bitrate")] | |||||
| public Optional<int> Bitrate { get; set; } | public Optional<int> Bitrate { get; set; } | ||||
| public CreateGuildChannelParams(string name, ChannelType type) | public CreateGuildChannelParams(string name, ChannelType type) | ||||
| @@ -1,14 +1,13 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class CreateGuildIntegrationParams | internal class CreateGuildIntegrationParams | ||||
| { | { | ||||
| [JsonProperty("id")] | |||||
| [ModelProperty("id")] | |||||
| public ulong Id { get; } | public ulong Id { get; } | ||||
| [JsonProperty("type")] | |||||
| [ModelProperty("type")] | |||||
| public string Type { get; } | public string Type { get; } | ||||
| public CreateGuildIntegrationParams(ulong id, string type) | public CreateGuildIntegrationParams(ulong id, string type) | ||||
| @@ -1,17 +1,16 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class CreateGuildParams | internal class CreateGuildParams | ||||
| { | { | ||||
| [JsonProperty("name")] | |||||
| [ModelProperty("name")] | |||||
| public string Name { get; } | public string Name { get; } | ||||
| [JsonProperty("region")] | |||||
| [ModelProperty("region")] | |||||
| public string RegionId { get; } | public string RegionId { get; } | ||||
| [JsonProperty("icon")] | |||||
| [ModelProperty("icon")] | |||||
| public Optional<Image?> Icon { get; set; } | public Optional<Image?> Icon { get; set; } | ||||
| public CreateGuildParams(string name, string regionId) | public CreateGuildParams(string name, string regionId) | ||||
| @@ -1,19 +1,18 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class CreateMessageParams | internal class CreateMessageParams | ||||
| { | { | ||||
| [JsonProperty("content")] | |||||
| [ModelProperty("content")] | |||||
| public string Content { get; } | public string Content { get; } | ||||
| [JsonProperty("nonce")] | |||||
| [ModelProperty("nonce")] | |||||
| public Optional<string> Nonce { get; set; } | public Optional<string> Nonce { get; set; } | ||||
| [JsonProperty("tts")] | |||||
| [ModelProperty("tts")] | |||||
| public Optional<bool> IsTTS { get; set; } | public Optional<bool> IsTTS { get; set; } | ||||
| [JsonProperty("embed")] | |||||
| [ModelProperty("embed")] | |||||
| public Optional<Embed> Embed { get; set; } | public Optional<Embed> Embed { get; set; } | ||||
| public CreateMessageParams(string content) | public CreateMessageParams(string content) | ||||
| @@ -1,23 +1,22 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class CreateWebhookMessageParams | internal class CreateWebhookMessageParams | ||||
| { | { | ||||
| [JsonProperty("content")] | |||||
| [ModelProperty("content")] | |||||
| public string Content { get; } | public string Content { get; } | ||||
| [JsonProperty("nonce")] | |||||
| [ModelProperty("nonce")] | |||||
| public Optional<string> Nonce { get; set; } | public Optional<string> Nonce { get; set; } | ||||
| [JsonProperty("tts")] | |||||
| [ModelProperty("tts")] | |||||
| public Optional<bool> IsTTS { get; set; } | public Optional<bool> IsTTS { get; set; } | ||||
| [JsonProperty("embeds")] | |||||
| [ModelProperty("embeds")] | |||||
| public Optional<Embed[]> Embeds { get; set; } | public Optional<Embed[]> Embeds { get; set; } | ||||
| [JsonProperty("username")] | |||||
| [ModelProperty("username")] | |||||
| public Optional<string> Username { get; set; } | public Optional<string> Username { get; set; } | ||||
| [JsonProperty("avatar_url")] | |||||
| [ModelProperty("avatar_url")] | |||||
| public Optional<string> AvatarUrl { get; set; } | public Optional<string> AvatarUrl { get; set; } | ||||
| public CreateWebhookMessageParams(string content) | public CreateWebhookMessageParams(string content) | ||||
| @@ -1,12 +1,11 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class DeleteMessagesParams | internal class DeleteMessagesParams | ||||
| { | { | ||||
| [JsonProperty("messages")] | |||||
| [ModelProperty("messages")] | |||||
| public ulong[] MessageIds { get; } | public ulong[] MessageIds { get; } | ||||
| public DeleteMessagesParams(ulong[] messageIds) | public DeleteMessagesParams(ulong[] messageIds) | ||||
| @@ -1,13 +1,13 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| internal class GetBotGatewayResponse | internal class GetBotGatewayResponse | ||||
| { | { | ||||
| [JsonProperty("url")] | |||||
| [ModelProperty("url")] | |||||
| public string Url { get; set; } | public string Url { get; set; } | ||||
| [JsonProperty("shards")] | |||||
| [ModelProperty("shards")] | |||||
| public int Shards { get; set; } | public int Shards { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,11 +1,11 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| internal class GetGatewayResponse | internal class GetGatewayResponse | ||||
| { | { | ||||
| [JsonProperty("url")] | |||||
| [ModelProperty("url")] | |||||
| public string Url { get; set; } | public string Url { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,11 +1,11 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| internal class GetGuildPruneCountResponse | internal class GetGuildPruneCountResponse | ||||
| { | { | ||||
| [JsonProperty("pruned")] | |||||
| [ModelProperty("pruned")] | |||||
| public int Pruned { get; set; } | public int Pruned { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,12 +1,11 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class GuildPruneParams | internal class GuildPruneParams | ||||
| { | { | ||||
| [JsonProperty("days")] | |||||
| [ModelProperty("days")] | |||||
| public int Days { get; } | public int Days { get; } | ||||
| public GuildPruneParams(int days) | public GuildPruneParams(int days) | ||||
| @@ -1,16 +1,15 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class ModifyChannelPermissionsParams | internal class ModifyChannelPermissionsParams | ||||
| { | { | ||||
| [JsonProperty("type")] | |||||
| [ModelProperty("type")] | |||||
| public string Type { get; } | public string Type { get; } | ||||
| [JsonProperty("allow")] | |||||
| [ModelProperty("allow")] | |||||
| public ulong Allow { get; } | public ulong Allow { get; } | ||||
| [JsonProperty("deny")] | |||||
| [ModelProperty("deny")] | |||||
| public ulong Deny { get; } | public ulong Deny { get; } | ||||
| public ModifyChannelPermissionsParams(string type, ulong allow, ulong deny) | public ModifyChannelPermissionsParams(string type, ulong allow, ulong deny) | ||||
| @@ -1,12 +1,11 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class ModifyCurrentUserNickParams | internal class ModifyCurrentUserNickParams | ||||
| { | { | ||||
| [JsonProperty("nick")] | |||||
| [ModelProperty("nick")] | |||||
| public string Nickname { get; } | public string Nickname { get; } | ||||
| public ModifyCurrentUserNickParams(string nickname) | public ModifyCurrentUserNickParams(string nickname) | ||||
| @@ -1,14 +1,13 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class ModifyCurrentUserParams | internal class ModifyCurrentUserParams | ||||
| { | { | ||||
| [JsonProperty("username")] | |||||
| [ModelProperty("username")] | |||||
| public Optional<string> Username { get; set; } | public Optional<string> Username { get; set; } | ||||
| [JsonProperty("avatar")] | |||||
| [ModelProperty("avatar")] | |||||
| public Optional<Image?> Avatar { get; set; } | public Optional<Image?> Avatar { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,14 +1,13 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class ModifyGuildChannelParams | internal class ModifyGuildChannelParams | ||||
| { | { | ||||
| [JsonProperty("name")] | |||||
| [ModelProperty("name")] | |||||
| public Optional<string> Name { get; set; } | public Optional<string> Name { get; set; } | ||||
| [JsonProperty("position")] | |||||
| [ModelProperty("position")] | |||||
| public Optional<int> Position { get; set; } | public Optional<int> Position { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,14 +1,13 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class ModifyGuildChannelsParams | internal class ModifyGuildChannelsParams | ||||
| { | { | ||||
| [JsonProperty("id")] | |||||
| [ModelProperty("id")] | |||||
| public ulong Id { get; } | public ulong Id { get; } | ||||
| [JsonProperty("position")] | |||||
| [ModelProperty("position")] | |||||
| public int Position { get; } | public int Position { get; } | ||||
| public ModifyGuildChannelsParams(ulong id, int position) | public ModifyGuildChannelsParams(ulong id, int position) | ||||
| @@ -1,14 +1,13 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class ModifyGuildEmbedParams | internal class ModifyGuildEmbedParams | ||||
| { | { | ||||
| [JsonProperty("enabled")] | |||||
| [ModelProperty("enabled")] | |||||
| public Optional<bool> Enabled { get; set; } | public Optional<bool> Enabled { get; set; } | ||||
| [JsonProperty("channel")] | |||||
| [ModelProperty("channel")] | |||||
| public Optional<ulong?> ChannelId { get; set; } | public Optional<ulong?> ChannelId { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,16 +1,15 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class ModifyGuildIntegrationParams | internal class ModifyGuildIntegrationParams | ||||
| { | { | ||||
| [JsonProperty("expire_behavior")] | |||||
| [ModelProperty("expire_behavior")] | |||||
| public Optional<int> ExpireBehavior { get; set; } | public Optional<int> ExpireBehavior { get; set; } | ||||
| [JsonProperty("expire_grace_period")] | |||||
| [ModelProperty("expire_grace_period")] | |||||
| public Optional<int> ExpireGracePeriod { get; set; } | public Optional<int> ExpireGracePeriod { get; set; } | ||||
| [JsonProperty("enable_emoticons")] | |||||
| [ModelProperty("enable_emoticons")] | |||||
| public Optional<bool> EnableEmoticons { get; set; } | public Optional<bool> EnableEmoticons { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,20 +1,19 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class ModifyGuildMemberParams | internal class ModifyGuildMemberParams | ||||
| { | { | ||||
| [JsonProperty("mute")] | |||||
| [ModelProperty("mute")] | |||||
| public Optional<bool> Mute { get; set; } | public Optional<bool> Mute { get; set; } | ||||
| [JsonProperty("deaf")] | |||||
| [ModelProperty("deaf")] | |||||
| public Optional<bool> Deaf { get; set; } | public Optional<bool> Deaf { get; set; } | ||||
| [JsonProperty("nick")] | |||||
| [ModelProperty("nick")] | |||||
| public Optional<string> Nickname { get; set; } | public Optional<string> Nickname { get; set; } | ||||
| [JsonProperty("roles")] | |||||
| [ModelProperty("roles")] | |||||
| public Optional<ulong[]> RoleIds { get; set; } | public Optional<ulong[]> RoleIds { get; set; } | ||||
| [JsonProperty("channel_id")] | |||||
| [ModelProperty("channel_id")] | |||||
| public Optional<ulong> ChannelId { get; set; } | public Optional<ulong> ChannelId { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,30 +1,29 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class ModifyGuildParams | internal class ModifyGuildParams | ||||
| { | { | ||||
| [JsonProperty("username")] | |||||
| [ModelProperty("username")] | |||||
| public Optional<string> Username { get; set; } | public Optional<string> Username { get; set; } | ||||
| [JsonProperty("name")] | |||||
| [ModelProperty("name")] | |||||
| public Optional<string> Name { get; set; } | public Optional<string> Name { get; set; } | ||||
| [JsonProperty("region")] | |||||
| [ModelProperty("region")] | |||||
| public Optional<string> RegionId { get; set; } | public Optional<string> RegionId { get; set; } | ||||
| [JsonProperty("verification_level")] | |||||
| [ModelProperty("verification_level")] | |||||
| public Optional<VerificationLevel> VerificationLevel { get; set; } | public Optional<VerificationLevel> VerificationLevel { get; set; } | ||||
| [JsonProperty("default_message_notifications")] | |||||
| [ModelProperty("default_message_notifications")] | |||||
| public Optional<DefaultMessageNotifications> DefaultMessageNotifications { get; set; } | public Optional<DefaultMessageNotifications> DefaultMessageNotifications { get; set; } | ||||
| [JsonProperty("afk_timeout")] | |||||
| [ModelProperty("afk_timeout")] | |||||
| public Optional<int> AfkTimeout { get; set; } | public Optional<int> AfkTimeout { get; set; } | ||||
| [JsonProperty("icon")] | |||||
| [ModelProperty("icon")] | |||||
| public Optional<Image?> Icon { get; set; } | public Optional<Image?> Icon { get; set; } | ||||
| [JsonProperty("splash")] | |||||
| [ModelProperty("splash")] | |||||
| public Optional<Image?> Splash { get; set; } | public Optional<Image?> Splash { get; set; } | ||||
| [JsonProperty("afk_channel_id")] | |||||
| [ModelProperty("afk_channel_id")] | |||||
| public Optional<ulong?> AfkChannelId { get; set; } | public Optional<ulong?> AfkChannelId { get; set; } | ||||
| [JsonProperty("owner_id")] | |||||
| [ModelProperty("owner_id")] | |||||
| public Optional<ulong> OwnerId { get; set; } | public Optional<ulong> OwnerId { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,20 +1,19 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class ModifyGuildRoleParams | internal class ModifyGuildRoleParams | ||||
| { | { | ||||
| [JsonProperty("name")] | |||||
| [ModelProperty("name")] | |||||
| public Optional<string> Name { get; set; } | public Optional<string> Name { get; set; } | ||||
| [JsonProperty("permissions")] | |||||
| [ModelProperty("permissions")] | |||||
| public Optional<ulong> Permissions { get; set; } | public Optional<ulong> Permissions { get; set; } | ||||
| [JsonProperty("color")] | |||||
| [ModelProperty("color")] | |||||
| public Optional<uint> Color { get; set; } | public Optional<uint> Color { get; set; } | ||||
| [JsonProperty("hoist")] | |||||
| [ModelProperty("hoist")] | |||||
| public Optional<bool> Hoist { get; set; } | public Optional<bool> Hoist { get; set; } | ||||
| [JsonProperty("mentionable")] | |||||
| [ModelProperty("mentionable")] | |||||
| public Optional<bool> Mentionable { get; set; } | public Optional<bool> Mentionable { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,14 +1,13 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class ModifyGuildRolesParams : ModifyGuildRoleParams | internal class ModifyGuildRolesParams : ModifyGuildRoleParams | ||||
| { | { | ||||
| [JsonProperty("id")] | |||||
| [ModelProperty("id")] | |||||
| public ulong Id { get; } | public ulong Id { get; } | ||||
| [JsonProperty("position")] | |||||
| [ModelProperty("position")] | |||||
| public int Position { get; } | public int Position { get; } | ||||
| public ModifyGuildRolesParams(ulong id, int position) | public ModifyGuildRolesParams(ulong id, int position) | ||||
| @@ -1,14 +1,13 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class ModifyMessageParams | internal class ModifyMessageParams | ||||
| { | { | ||||
| [JsonProperty("content")] | |||||
| [ModelProperty("content")] | |||||
| public Optional<string> Content { get; set; } | public Optional<string> Content { get; set; } | ||||
| [JsonProperty("embed")] | |||||
| [ModelProperty("embed")] | |||||
| public Optional<Embed> Embed { get; set; } | public Optional<Embed> Embed { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,12 +1,11 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class ModifyTextChannelParams : ModifyGuildChannelParams | internal class ModifyTextChannelParams : ModifyGuildChannelParams | ||||
| { | { | ||||
| [JsonProperty("topic")] | |||||
| [ModelProperty("topic")] | |||||
| public Optional<string> Topic { get; set; } | public Optional<string> Topic { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,14 +1,13 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
| { | { | ||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class ModifyVoiceChannelParams : ModifyGuildChannelParams | internal class ModifyVoiceChannelParams : ModifyGuildChannelParams | ||||
| { | { | ||||
| [JsonProperty("bitrate")] | |||||
| [ModelProperty("bitrate")] | |||||
| public Optional<int> Bitrate { get; set; } | public Optional<int> Bitrate { get; set; } | ||||
| [JsonProperty("user_limit")] | |||||
| [ModelProperty("user_limit")] | |||||
| public Optional<int> UserLimit { get; set; } | public Optional<int> UserLimit { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -22,23 +22,25 @@ namespace Discord.Rest | |||||
| private readonly SemaphoreSlim _stateLock; | private readonly SemaphoreSlim _stateLock; | ||||
| private bool _isFirstLogin, _isDisposed; | private bool _isFirstLogin, _isDisposed; | ||||
| internal API.DiscordRestApiClient ApiClient { get; } | |||||
| internal LogManager LogManager { get; } | internal LogManager LogManager { get; } | ||||
| internal API.DiscordRestApiClient ApiClient { get; private set; } | |||||
| public LoginState LoginState { get; private set; } | public LoginState LoginState { get; private set; } | ||||
| public ISelfUser CurrentUser { get; protected set; } | public ISelfUser CurrentUser { get; protected set; } | ||||
| public TokenType TokenType => ApiClient.AuthTokenType; | public TokenType TokenType => ApiClient.AuthTokenType; | ||||
| /// <summary> Creates a new REST-only discord client. </summary> | /// <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 = new LogManager(config.LogLevel); | ||||
| LogManager.Message += async msg => await _logEvent.InvokeAsync(msg).ConfigureAwait(false); | LogManager.Message += async msg => await _logEvent.InvokeAsync(msg).ConfigureAwait(false); | ||||
| _stateLock = new SemaphoreSlim(1, 1); | _stateLock = new SemaphoreSlim(1, 1); | ||||
| _restLogger = LogManager.CreateLogger("Rest"); | _restLogger = LogManager.CreateLogger("Rest"); | ||||
| _isFirstLogin = config.DisplayInitialLog; | _isFirstLogin = config.DisplayInitialLog; | ||||
| } | |||||
| internal void SetApiClient(API.DiscordRestApiClient client) | |||||
| { | |||||
| ApiClient = client; | |||||
| ApiClient.RequestQueue.RateLimitTriggered += async (id, info) => | ApiClient.RequestQueue.RateLimitTriggered += async (id, info) => | ||||
| { | { | ||||
| if (info == null) | if (info == null) | ||||
| @@ -6,8 +6,17 @@ | |||||
| <Description>A core Discord.Net library containing the REST client and models.</Description> | <Description>A core Discord.Net library containing the REST client and models.</Description> | ||||
| <TargetFrameworks>net45;netstandard1.1;netstandard1.3</TargetFrameworks> | <TargetFrameworks>net45;netstandard1.1;netstandard1.3</TargetFrameworks> | ||||
| </PropertyGroup> | </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> | <ItemGroup> | ||||
| <ProjectReference Include="..\Discord.Net.Core\Discord.Net.Core.csproj" /> | <ProjectReference Include="..\Discord.Net.Core\Discord.Net.Core.csproj" /> | ||||
| <ProjectReference Include="..\Discord.Net.Serialization\Discord.Net.Serialization.csproj" /> | |||||
| </ItemGroup> | </ItemGroup> | ||||
| <ItemGroup Condition=" '$(TargetFramework)' != 'net45' "> | <ItemGroup Condition=" '$(TargetFramework)' != 'net45' "> | ||||
| <PackageReference Include="System.Net.Http" Version="4.3.2" /> <!-- https://github.com/dotnet/corefx/issues/19535 --> | <PackageReference Include="System.Net.Http" Version="4.3.2" /> <!-- https://github.com/dotnet/corefx/issues/19535 --> | ||||
| @@ -1,21 +1,19 @@ | |||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
| using Discord.API.Rest; | using Discord.API.Rest; | ||||
| using Discord.Net; | using Discord.Net; | ||||
| using Discord.Net.Converters; | |||||
| using Discord.Net.Queue; | using Discord.Net.Queue; | ||||
| using Discord.Net.Rest; | using Discord.Net.Rest; | ||||
| using Newtonsoft.Json; | |||||
| using Discord.Serialization; | |||||
| using System; | using System; | ||||
| using System.Collections.Concurrent; | using System.Collections.Concurrent; | ||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Diagnostics; | using System.Diagnostics; | ||||
| using System.Globalization; | |||||
| using System.IO; | |||||
| using System.Linq; | using System.Linq; | ||||
| using System.Linq.Expressions; | using System.Linq.Expressions; | ||||
| using System.Net; | using System.Net; | ||||
| using System.Runtime.CompilerServices; | using System.Runtime.CompilerServices; | ||||
| using System.Text; | using System.Text; | ||||
| using System.Text.Formatting; | |||||
| using System.Threading; | using System.Threading; | ||||
| using System.Threading.Tasks; | 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); } } | 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>>(); | 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 SemaphoreSlim _stateLock; | ||||
| protected readonly Serializer _serializer; | |||||
| protected readonly Pool<ArrayFormatter> _formatters; | |||||
| private readonly RestClientProvider _restClientProvider; | private readonly RestClientProvider _restClientProvider; | ||||
| protected bool _isDisposed; | protected bool _isDisposed; | ||||
| @@ -45,16 +44,16 @@ namespace Discord.API | |||||
| internal IRestClient RestClient { get; private set; } | internal IRestClient RestClient { get; private set; } | ||||
| internal ulong? CurrentUserId { get; 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; | _restClientProvider = restClientProvider; | ||||
| UserAgent = userAgent; | UserAgent = userAgent; | ||||
| _serializer = serializer; | |||||
| DefaultRetryMode = defaultRetryMode; | DefaultRetryMode = defaultRetryMode; | ||||
| _serializer = serializer ?? new JsonSerializer { DateFormatString = "yyyy-MM-ddTHH:mm:ssZ", ContractResolver = new DiscordContractResolver() }; | |||||
| RequestQueue = new RequestQueue(); | RequestQueue = new RequestQueue(); | ||||
| _stateLock = new SemaphoreSlim(1, 1); | _stateLock = new SemaphoreSlim(1, 1); | ||||
| _formatters = new Pool<ArrayFormatter>(() => new ArrayFormatter(128, SymbolTable.InvariantUtf8)); | |||||
| SetBaseUrl(DiscordConfig.APIUrl); | SetBaseUrl(DiscordConfig.APIUrl); | ||||
| } | } | ||||
| @@ -188,10 +187,18 @@ namespace Discord.API | |||||
| options.HeaderOnly = true; | options.HeaderOnly = true; | ||||
| options.BucketId = AuthTokenType == TokenType.User ? ClientBucket.Get(clientBucket).Id : bucketId; | options.BucketId = AuthTokenType == TokenType.User ? ClientBucket.Get(clientBucket).Id : bucketId; | ||||
| options.IsClientBucket = AuthTokenType == TokenType.User; | 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, | 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, | 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); | => SendAsync<TResponse>(method, GetEndpoint(endpointExpr), GetBucketId(ids, endpointExpr, AuthTokenType, funcName), clientBucket, options); | ||||
| public async Task<TResponse> SendAsync<TResponse>(string method, string endpoint, | 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 = options ?? new RequestOptions(); | ||||
| options.BucketId = AuthTokenType == TokenType.User ? ClientBucket.Get(clientBucket).Id : bucketId; | 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, | 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); | => 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, | 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 = options ?? new RequestOptions(); | ||||
| options.BucketId = AuthTokenType == TokenType.User ? ClientBucket.Get(clientBucket).Id : bucketId; | options.BucketId = AuthTokenType == TokenType.User ? ClientBucket.Get(clientBucket).Id : bucketId; | ||||
| options.IsClientBucket = AuthTokenType == TokenType.User; | 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, | 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); | => 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, | 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 = options ?? new RequestOptions(); | ||||
| options.BucketId = AuthTokenType == TokenType.User ? ClientBucket.Get(clientBucket).Id : bucketId; | 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)); | 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) | if (!request.Options.IgnoreState) | ||||
| CheckState(); | CheckState(); | ||||
| @@ -260,13 +275,13 @@ namespace Discord.API | |||||
| request.Options.RetryMode = DefaultRetryMode; | request.Options.RetryMode = DefaultRetryMode; | ||||
| var stopwatch = Stopwatch.StartNew(); | var stopwatch = Stopwatch.StartNew(); | ||||
| var responseStream = await RequestQueue.SendAsync(request).ConfigureAwait(false); | |||||
| var response = await RequestQueue.SendAsync(request).ConfigureAwait(false); | |||||
| stopwatch.Stop(); | stopwatch.Stop(); | ||||
| double milliseconds = ToMilliseconds(stopwatch); | double milliseconds = ToMilliseconds(stopwatch); | ||||
| await _sentRequestEvent.InvokeAsync(method, endpoint, milliseconds).ConfigureAwait(false); | await _sentRequestEvent.InvokeAsync(method, endpoint, milliseconds).ConfigureAwait(false); | ||||
| return responseStream; | |||||
| return response; | |||||
| } | } | ||||
| //Auth | //Auth | ||||
| @@ -311,7 +326,7 @@ namespace Discord.API | |||||
| options = RequestOptions.CreateOrClone(options); | options = RequestOptions.CreateOrClone(options); | ||||
| var ids = new BucketIds(guildId: guildId); | 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) | 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}"; | endpoint = () => $"channels/{channelId}/messages?limit={limit}&{relativeDir}={relativeId}"; | ||||
| else | else | ||||
| endpoint = () => $"channels/{channelId}/messages?limit={limit}"; | 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) | 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); | var ids = new BucketIds(channelId: channelId); | ||||
| Expression<Func<string>> endpoint = () => $"channels/{channelId}/messages/{messageId}/reactions/{emoji}"; | 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) | public async Task AckMessageAsync(ulong channelId, ulong messageId, RequestOptions options = null) | ||||
| { | { | ||||
| @@ -687,7 +702,7 @@ namespace Discord.API | |||||
| options = RequestOptions.CreateOrClone(options); | options = RequestOptions.CreateOrClone(options); | ||||
| var ids = new BucketIds(channelId: channelId); | 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 | //Channel Recipients | ||||
| @@ -791,7 +806,7 @@ namespace Discord.API | |||||
| options = RequestOptions.CreateOrClone(options); | options = RequestOptions.CreateOrClone(options); | ||||
| var ids = new BucketIds(guildId: guildId); | 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) | public async Task CreateGuildBanAsync(ulong guildId, ulong userId, CreateGuildBanParams args, RequestOptions options = null) | ||||
| { | { | ||||
| @@ -846,7 +861,7 @@ namespace Discord.API | |||||
| options = RequestOptions.CreateOrClone(options); | options = RequestOptions.CreateOrClone(options); | ||||
| var ids = new BucketIds(guildId: guildId); | 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) | public async Task<Integration> CreateGuildIntegrationAsync(ulong guildId, CreateGuildIntegrationParams args, RequestOptions options = null) | ||||
| { | { | ||||
| @@ -915,7 +930,7 @@ namespace Discord.API | |||||
| options = RequestOptions.CreateOrClone(options); | options = RequestOptions.CreateOrClone(options); | ||||
| var ids = new BucketIds(guildId: guildId); | 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) | public async Task<IReadOnlyCollection<InviteMetadata>> GetChannelInvitesAsync(ulong channelId, RequestOptions options = null) | ||||
| { | { | ||||
| @@ -923,7 +938,7 @@ namespace Discord.API | |||||
| options = RequestOptions.CreateOrClone(options); | options = RequestOptions.CreateOrClone(options); | ||||
| var ids = new BucketIds(channelId: channelId); | 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) | 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); | var ids = new BucketIds(guildId: guildId); | ||||
| Expression<Func<string>> endpoint = () => $"guilds/{guildId}/members?limit={limit}&after={afterUserId}"; | 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) | public async Task RemoveGuildMemberAsync(ulong guildId, ulong userId, string reason, RequestOptions options = null) | ||||
| { | { | ||||
| @@ -1020,7 +1035,7 @@ namespace Discord.API | |||||
| options = RequestOptions.CreateOrClone(options); | options = RequestOptions.CreateOrClone(options); | ||||
| var ids = new BucketIds(guildId: guildId); | 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) | public async Task<Role> CreateGuildRoleAsync(ulong guildId, RequestOptions options = null) | ||||
| { | { | ||||
| @@ -1058,7 +1073,7 @@ namespace Discord.API | |||||
| options = RequestOptions.CreateOrClone(options); | options = RequestOptions.CreateOrClone(options); | ||||
| var ids = new BucketIds(guildId: guildId); | 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 | //Users | ||||
| @@ -1083,12 +1098,12 @@ namespace Discord.API | |||||
| public async Task<IReadOnlyCollection<Connection>> GetMyConnectionsAsync(RequestOptions options = null) | public async Task<IReadOnlyCollection<Connection>> GetMyConnectionsAsync(RequestOptions options = null) | ||||
| { | { | ||||
| options = RequestOptions.CreateOrClone(options); | 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) | public async Task<IReadOnlyCollection<Channel>> GetMyPrivateChannelsAsync(RequestOptions options = null) | ||||
| { | { | ||||
| options = RequestOptions.CreateOrClone(options); | 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) | 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); | int limit = args.Limit.GetValueOrDefault(int.MaxValue); | ||||
| ulong afterGuildId = args.AfterGuildId.GetValueOrDefault(0); | 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) | public async Task<Application> GetMyApplicationAsync(RequestOptions options = null) | ||||
| { | { | ||||
| @@ -1138,7 +1153,7 @@ namespace Discord.API | |||||
| public async Task<IReadOnlyCollection<VoiceRegion>> GetVoiceRegionsAsync(RequestOptions options = null) | public async Task<IReadOnlyCollection<VoiceRegion>> GetVoiceRegionsAsync(RequestOptions options = null) | ||||
| { | { | ||||
| options = RequestOptions.CreateOrClone(options); | 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) | public async Task<IReadOnlyCollection<VoiceRegion>> GetGuildVoiceRegionsAsync(ulong guildId, RequestOptions options = null) | ||||
| { | { | ||||
| @@ -1146,7 +1161,7 @@ namespace Discord.API | |||||
| options = RequestOptions.CreateOrClone(options); | options = RequestOptions.CreateOrClone(options); | ||||
| var ids = new BucketIds(guildId: guildId); | 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 | //Helpers | ||||
| @@ -1156,19 +1171,14 @@ namespace Discord.API | |||||
| throw new InvalidOperationException("Client is not logged in."); | 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 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 | internal class BucketIds | ||||
| @@ -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.Collections.Immutable; | ||||
| using System.IO; | using System.IO; | ||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| @@ -7,15 +9,29 @@ namespace Discord.Rest | |||||
| { | { | ||||
| public class DiscordRestClient : BaseDiscordClient, IDiscordClient | public class DiscordRestClient : BaseDiscordClient, IDiscordClient | ||||
| { | { | ||||
| private readonly Serializer _serializer; | |||||
| private RestApplication _applicationInfo; | private RestApplication _applicationInfo; | ||||
| public new RestSelfUser CurrentUser => base.CurrentUser as RestSelfUser; | public new RestSelfUser CurrentUser => base.CurrentUser as RestSelfUser; | ||||
| public DiscordRestClient() : this(new DiscordRestConfig()) { } | 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) | internal override void Dispose(bool disposing) | ||||
| { | { | ||||
| if (disposing) | if (disposing) | ||||
| @@ -114,7 +114,7 @@ namespace Discord.Rest | |||||
| public static API.Image ToModel(this Image entity) | 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) | public static Overwrite ToEntity(this API.Overwrite model) | ||||
| @@ -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); | |||||
| } | |||||
| } | |||||
| @@ -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(); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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)); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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)); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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"); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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(); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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)); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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(); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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(); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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"); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,11 +1,11 @@ | |||||
| using Newtonsoft.Json; | |||||
| using System; | |||||
| using System; | |||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Globalization; | using System.Globalization; | ||||
| using System.IO; | using System.IO; | ||||
| using System.Linq; | using System.Linq; | ||||
| using System.Net; | using System.Net; | ||||
| using System.Net.Http; | using System.Net.Http; | ||||
| using System.Net.Http.Headers; | |||||
| using System.Text; | using System.Text; | ||||
| using System.Threading; | using System.Threading; | ||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| @@ -18,7 +18,6 @@ namespace Discord.Net.Rest | |||||
| private readonly HttpClient _client; | private readonly HttpClient _client; | ||||
| private readonly string _baseUrl; | private readonly string _baseUrl; | ||||
| private readonly JsonSerializer _errorDeserializer; | |||||
| private CancellationToken _cancelToken; | private CancellationToken _cancelToken; | ||||
| private bool _isDisposed; | private bool _isDisposed; | ||||
| @@ -35,7 +34,6 @@ namespace Discord.Net.Rest | |||||
| SetHeader("accept-encoding", "gzip, deflate"); | SetHeader("accept-encoding", "gzip, deflate"); | ||||
| _cancelToken = CancellationToken.None; | _cancelToken = CancellationToken.None; | ||||
| _errorDeserializer = new JsonSerializer(); | |||||
| } | } | ||||
| private void Dispose(bool disposing) | private void Dispose(bool disposing) | ||||
| { | { | ||||
| @@ -71,13 +69,15 @@ namespace Discord.Net.Rest | |||||
| return await SendInternalAsync(restRequest, cancelToken, headerOnly).ConfigureAwait(false); | 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); | string uri = Path.Combine(_baseUrl, endpoint); | ||||
| using (var restRequest = new HttpRequestMessage(GetMethod(method), uri)) | using (var restRequest = new HttpRequestMessage(GetMethod(method), uri)) | ||||
| { | { | ||||
| if (reason != null) restRequest.Headers.Add("X-Audit-Log-Reason", Uri.EscapeDataString(reason)); | 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); | 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); | HttpResponseMessage response = await _client.SendAsync(request, cancelToken).ConfigureAwait(false); | ||||
| var headers = response.Headers.ToDictionary(x => x.Key, x => x.Value.FirstOrDefault(), StringComparer.OrdinalIgnoreCase); | 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"); | private static readonly HttpMethod _patch = new HttpMethod("PATCH"); | ||||
| @@ -63,7 +63,7 @@ namespace Discord.Net.Queue | |||||
| finally { _tokenLock.Release(); } | finally { _tokenLock.Release(); } | ||||
| } | } | ||||
| public async Task<Stream> SendAsync(RestRequest request) | |||||
| public async Task<ReadOnlyBuffer<byte>> SendAsync(RestRequest request) | |||||
| { | { | ||||
| if (request.Options.CancelToken.CanBeCanceled) | if (request.Options.CancelToken.CanBeCanceled) | ||||
| request.Options.CancelToken = CancellationTokenSource.CreateLinkedTokenSource(_requestCancelToken, request.Options.CancelToken).Token; | request.Options.CancelToken = CancellationTokenSource.CreateLinkedTokenSource(_requestCancelToken, request.Options.CancelToken).Token; | ||||
| @@ -1,5 +1,6 @@ | |||||
| using Newtonsoft.Json; | |||||
| using Newtonsoft.Json.Linq; | |||||
| using Discord.Rest; | |||||
| using Discord.Serialization; | |||||
| using Discord.Serialization.Json; | |||||
| using System; | using System; | ||||
| #if DEBUG_LIMITS | #if DEBUG_LIMITS | ||||
| using System.Diagnostics; | using System.Diagnostics; | ||||
| @@ -13,6 +14,16 @@ namespace Discord.Net.Queue | |||||
| { | { | ||||
| internal class RequestBucket | 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 object _lock; | ||||
| private readonly RequestQueue _queue; | private readonly RequestQueue _queue; | ||||
| private int _semaphore; | private int _semaphore; | ||||
| @@ -38,10 +49,9 @@ namespace Discord.Net.Queue | |||||
| LastAttemptAt = DateTimeOffset.UtcNow; | 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 | #if DEBUG_LIMITS | ||||
| Debug.WriteLine($"[{id}] Start"); | Debug.WriteLine($"[{id}] Start"); | ||||
| #endif | #endif | ||||
| @@ -54,7 +64,7 @@ namespace Discord.Net.Queue | |||||
| #if DEBUG_LIMITS | #if DEBUG_LIMITS | ||||
| Debug.WriteLine($"[{id}] Sending..."); | Debug.WriteLine($"[{id}] Sending..."); | ||||
| #endif | #endif | ||||
| RateLimitInfo info = default(RateLimitInfo); | |||||
| var info = default(RateLimitInfo); | |||||
| try | try | ||||
| { | { | ||||
| var response = await request.SendAsync().ConfigureAwait(false); | var response = await request.SendAsync().ConfigureAwait(false); | ||||
| @@ -92,17 +102,13 @@ namespace Discord.Net.Queue | |||||
| default: | default: | ||||
| int? code = null; | int? code = null; | ||||
| string reason = null; | string reason = null; | ||||
| if (response.Stream != null) | |||||
| if (response.Data.Length > 0) | |||||
| { | { | ||||
| try | 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 { } | catch { } | ||||
| } | } | ||||
| @@ -114,7 +120,7 @@ namespace Discord.Net.Queue | |||||
| #if DEBUG_LIMITS | #if DEBUG_LIMITS | ||||
| Debug.WriteLine($"[{id}] Success"); | Debug.WriteLine($"[{id}] Success"); | ||||
| #endif | #endif | ||||
| return response.Stream; | |||||
| return response.Data; | |||||
| } | } | ||||
| } | } | ||||
| //catch (HttpException) { throw; } //Pass through | //catch (HttpException) { throw; } //Pass through | ||||
| @@ -231,7 +237,7 @@ namespace Discord.Net.Queue | |||||
| #endif | #endif | ||||
| } | } | ||||
| var now = DateTimeUtils.ToUnixSeconds(DateTimeOffset.UtcNow); | |||||
| long now = DateTimeUtils.ToUnixSeconds(DateTimeOffset.UtcNow); | |||||
| DateTimeOffset? resetTick = null; | DateTimeOffset? resetTick = null; | ||||
| //Using X-RateLimit-Remaining causes a race condition | //Using X-RateLimit-Remaining causes a race condition | ||||
| @@ -1,21 +1,22 @@ | |||||
| using Discord.Net.Rest; | using Discord.Net.Rest; | ||||
| using System; | |||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| namespace Discord.Net.Queue | namespace Discord.Net.Queue | ||||
| { | { | ||||
| public class JsonRestRequest : RestRequest | 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) | : base(client, method, endpoint, options) | ||||
| { | { | ||||
| Json = json; | |||||
| Payload = payload; | |||||
| } | } | ||||
| public override async Task<RestResponse> SendAsync() | 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); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -10,14 +10,14 @@ namespace Discord.Net.Queue | |||||
| { | { | ||||
| public IWebSocketClient Client { get; } | public IWebSocketClient Client { get; } | ||||
| public string BucketId { get; } | public string BucketId { get; } | ||||
| public byte[] Data { get; } | |||||
| public ReadOnlyBuffer<byte> Data { get; } | |||||
| public bool IsText { get; } | public bool IsText { get; } | ||||
| public DateTimeOffset? TimeoutAt { get; } | public DateTimeOffset? TimeoutAt { get; } | ||||
| public TaskCompletionSource<Stream> Promise { get; } | public TaskCompletionSource<Stream> Promise { get; } | ||||
| public RequestOptions Options { get; } | public RequestOptions Options { get; } | ||||
| public CancellationToken CancelToken { get; internal set; } | 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)); | Preconditions.NotNull(options, nameof(options)); | ||||
| @@ -32,7 +32,7 @@ namespace Discord.Net.Queue | |||||
| public async Task SendAsync() | public async Task SendAsync() | ||||
| { | { | ||||
| await Client.SendAsync(Data, 0, Data.Length, IsText).ConfigureAwait(false); | |||||
| await Client.SendAsync(Data, IsText).ConfigureAwait(false); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||