Merge branch 'dev' into feature/reactions

This commit is contained in:
RogueException
2016-11-27 00:30:46 -04:00
112 changed files with 2808 additions and 1191 deletions

View File

@@ -1,4 +1,5 @@
#pragma warning disable CS1591
using System;
using Newtonsoft.Json;
namespace Discord.API
@@ -13,9 +14,23 @@ namespace Discord.API
public string Description { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("color")]
public uint? Color { get; set; }
[JsonProperty("timestamp")]
public DateTimeOffset? Timestamp { get; set; }
[JsonProperty("author")]
public Optional<EmbedAuthor> Author { get; set; }
[JsonProperty("footer")]
public Optional<EmbedFooter> Footer { get; set; }
[JsonProperty("video")]
public Optional<EmbedVideo> Video { get; set; }
[JsonProperty("thumbnail")]
public Optional<EmbedThumbnail> Thumbnail { get; set; }
[JsonProperty("image")]
public Optional<EmbedImage> Image { get; set; }
[JsonProperty("provider")]
public Optional<EmbedProvider> Provider { get; set; }
[JsonProperty("fields")]
public Optional<EmbedField[]> Fields { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
using Newtonsoft.Json;
namespace Discord.API
{
public class EmbedAuthor
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("icon_url")]
public string IconUrl { get; set; }
[JsonProperty("proxy_icon_url")]
public string ProxyIconUrl { get; set; }
}
}

View File

@@ -0,0 +1,14 @@
using Newtonsoft.Json;
namespace Discord.API
{
public class EmbedField
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("value")]
public string Value { get; set; }
[JsonProperty("inline")]
public bool Inline { get; set; }
}
}

View File

@@ -0,0 +1,14 @@
using Newtonsoft.Json;
namespace Discord.API
{
public class EmbedFooter
{
[JsonProperty("text")]
public string Text { get; set; }
[JsonProperty("icon_url")]
public string IconUrl { get; set; }
[JsonProperty("proxy_icon_url")]
public string ProxyIconUrl { get; set; }
}
}

View File

@@ -0,0 +1,17 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class EmbedImage
{
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("proxy_url")]
public string ProxyUrl { get; set; }
[JsonProperty("height")]
public Optional<int> Height { get; set; }
[JsonProperty("width")]
public Optional<int> Width { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
namespace Discord.API
{
public class EmbedVideo
{
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("height")]
public Optional<int> Height { get; set; }
[JsonProperty("width")]
public Optional<int> Width { get; set; }
}
}

View File

@@ -49,7 +49,7 @@ namespace Discord.API
{
_restClientProvider = restClientProvider;
_userAgent = userAgent;
_serializer = serializer ?? new JsonSerializer { ContractResolver = new DiscordContractResolver() };
_serializer = serializer ?? new JsonSerializer { DateFormatString = "yyyy-MM-ddTHH:mm:ssZ", ContractResolver = new DiscordContractResolver() };
RequestQueue = requestQueue;
FetchCurrentUser = true;
@@ -165,30 +165,30 @@ namespace Discord.API
//Core
internal Task SendAsync(string method, Expression<Func<string>> endpointExpr, BucketIds ids,
string clientBucketId = null, RequestOptions options = null, [CallerMemberName] string funcName = null)
=> SendAsync(method, GetEndpoint(endpointExpr), GetBucketId(ids, endpointExpr, AuthTokenType, funcName), clientBucketId, options);
ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null)
=> SendAsync(method, GetEndpoint(endpointExpr), GetBucketId(ids, endpointExpr, AuthTokenType, funcName), clientBucket, options);
public async Task SendAsync(string method, string endpoint,
string bucketId = null, string clientBucketId = null, RequestOptions options = null)
string bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null)
{
options = options ?? new RequestOptions();
options.HeaderOnly = true;
options.BucketId = bucketId;
options.ClientBucketId = AuthTokenType == TokenType.User ? clientBucketId : null;
options.BucketId = AuthTokenType == TokenType.User ? ClientBucket.Get(clientBucket).Id : bucketId;
options.IsClientBucket = AuthTokenType == TokenType.User;
var request = new RestRequest(_restClient, method, endpoint, options);
await SendInternalAsync(method, endpoint, request).ConfigureAwait(false);
}
internal Task SendJsonAsync(string method, Expression<Func<string>> endpointExpr, object payload, BucketIds ids,
string clientBucketId = null, RequestOptions options = null, [CallerMemberName] string funcName = null)
=> SendJsonAsync(method, GetEndpoint(endpointExpr), payload, GetBucketId(ids, endpointExpr, AuthTokenType, funcName), clientBucketId, options);
ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null)
=> SendJsonAsync(method, GetEndpoint(endpointExpr), payload, GetBucketId(ids, endpointExpr, AuthTokenType, funcName), clientBucket, options);
public async Task SendJsonAsync(string method, string endpoint, object payload,
string bucketId = null, string clientBucketId = null, RequestOptions options = null)
string bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null)
{
options = options ?? new RequestOptions();
options.HeaderOnly = true;
options.BucketId = bucketId;
options.ClientBucketId = AuthTokenType == TokenType.User ? clientBucketId : null;
options.BucketId = AuthTokenType == TokenType.User ? ClientBucket.Get(clientBucket).Id : bucketId;
options.IsClientBucket = AuthTokenType == TokenType.User;
var json = payload != null ? SerializeJson(payload) : null;
var request = new JsonRestRequest(_restClient, method, endpoint, json, options);
@@ -196,43 +196,43 @@ namespace Discord.API
}
internal Task SendMultipartAsync(string method, Expression<Func<string>> endpointExpr, IReadOnlyDictionary<string, object> multipartArgs, BucketIds ids,
string clientBucketId = null, RequestOptions options = null, [CallerMemberName] string funcName = null)
=> SendMultipartAsync(method, GetEndpoint(endpointExpr), multipartArgs, GetBucketId(ids, endpointExpr, AuthTokenType, funcName), clientBucketId, options);
ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null)
=> SendMultipartAsync(method, GetEndpoint(endpointExpr), multipartArgs, GetBucketId(ids, endpointExpr, AuthTokenType, funcName), clientBucket, options);
public async Task SendMultipartAsync(string method, string endpoint, IReadOnlyDictionary<string, object> multipartArgs,
string bucketId = null, string clientBucketId = null, RequestOptions options = null)
string bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null)
{
options = options ?? new RequestOptions();
options.HeaderOnly = true;
options.BucketId = bucketId;
options.ClientBucketId = AuthTokenType == TokenType.User ? clientBucketId : null;
options.BucketId = AuthTokenType == TokenType.User ? ClientBucket.Get(clientBucket).Id : bucketId;
options.IsClientBucket = AuthTokenType == TokenType.User;
var request = new MultipartRestRequest(_restClient, method, endpoint, multipartArgs, options);
await SendInternalAsync(method, endpoint, request).ConfigureAwait(false);
}
internal Task<TResponse> SendAsync<TResponse>(string method, Expression<Func<string>> endpointExpr, BucketIds ids,
string clientBucketId = null, RequestOptions options = null, [CallerMemberName] string funcName = null) where TResponse : class
=> SendAsync<TResponse>(method, GetEndpoint(endpointExpr), GetBucketId(ids, endpointExpr, AuthTokenType, funcName), clientBucketId, options);
ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null) where TResponse : class
=> SendAsync<TResponse>(method, GetEndpoint(endpointExpr), GetBucketId(ids, endpointExpr, AuthTokenType, funcName), clientBucket, options);
public async Task<TResponse> SendAsync<TResponse>(string method, string endpoint,
string bucketId = null, string clientBucketId = null, RequestOptions options = null) where TResponse : class
string bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null) where TResponse : class
{
options = options ?? new RequestOptions();
options.BucketId = bucketId;
options.ClientBucketId = AuthTokenType == TokenType.User ? clientBucketId : null;
options.BucketId = AuthTokenType == TokenType.User ? ClientBucket.Get(clientBucket).Id : bucketId;
options.IsClientBucket = AuthTokenType == TokenType.User;
var request = new RestRequest(_restClient, method, endpoint, options);
return DeserializeJson<TResponse>(await SendInternalAsync(method, endpoint, request).ConfigureAwait(false));
}
internal Task<TResponse> SendJsonAsync<TResponse>(string method, Expression<Func<string>> endpointExpr, object payload, BucketIds ids,
string clientBucketId = null, RequestOptions options = null, [CallerMemberName] string funcName = null) where TResponse : class
=> SendJsonAsync<TResponse>(method, GetEndpoint(endpointExpr), payload, GetBucketId(ids, endpointExpr, AuthTokenType, funcName), clientBucketId, options);
ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null) where TResponse : class
=> SendJsonAsync<TResponse>(method, GetEndpoint(endpointExpr), payload, GetBucketId(ids, endpointExpr, AuthTokenType, funcName), clientBucket, options);
public async Task<TResponse> SendJsonAsync<TResponse>(string method, string endpoint, object payload,
string bucketId = null, string clientBucketId = null, RequestOptions options = null) where TResponse : class
string bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null) where TResponse : class
{
options = options ?? new RequestOptions();
options.BucketId = bucketId;
options.ClientBucketId = AuthTokenType == TokenType.User ? clientBucketId : null;
options.BucketId = AuthTokenType == TokenType.User ? ClientBucket.Get(clientBucket).Id : bucketId;
options.IsClientBucket = AuthTokenType == TokenType.User;
var json = payload != null ? SerializeJson(payload) : null;
var request = new JsonRestRequest(_restClient, method, endpoint, json, options);
@@ -240,14 +240,14 @@ namespace Discord.API
}
internal Task<TResponse> SendMultipartAsync<TResponse>(string method, Expression<Func<string>> endpointExpr, IReadOnlyDictionary<string, object> multipartArgs, BucketIds ids,
string clientBucketId = null, RequestOptions options = null, [CallerMemberName] string funcName = null)
=> SendMultipartAsync<TResponse>(method, GetEndpoint(endpointExpr), multipartArgs, GetBucketId(ids, endpointExpr, AuthTokenType, funcName), clientBucketId, options);
ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null)
=> SendMultipartAsync<TResponse>(method, GetEndpoint(endpointExpr), multipartArgs, GetBucketId(ids, endpointExpr, AuthTokenType, funcName), clientBucket, options);
public async Task<TResponse> SendMultipartAsync<TResponse>(string method, string endpoint, IReadOnlyDictionary<string, object> multipartArgs,
string bucketId = null, string clientBucketId = null, RequestOptions options = null)
string bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null)
{
options = options ?? new RequestOptions();
options.BucketId = bucketId;
options.ClientBucketId = AuthTokenType == TokenType.User ? clientBucketId : null;
options.BucketId = AuthTokenType == TokenType.User ? ClientBucket.Get(clientBucket).Id : bucketId;
options.IsClientBucket = AuthTokenType == TokenType.User;
var request = new MultipartRestRequest(_restClient, method, endpoint, multipartArgs, options);
return DeserializeJson<TResponse>(await SendInternalAsync(method, endpoint, request).ConfigureAwait(false));
@@ -432,20 +432,22 @@ namespace Discord.API
if (relativeId != null)
endpoint = () => $"channels/{channelId}/messages?limit={limit}&{relativeDir}={relativeId}";
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);
}
public async Task<Message> CreateMessageAsync(ulong channelId, CreateMessageParams args, RequestOptions options = null)
{
Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotNull(args, nameof(args));
Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content));
if (!args.Embed.IsSpecified || args.Embed.Value == null)
Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content));
if (args.Content.Length > DiscordConfig.MaxMessageSize)
throw new ArgumentException($"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", nameof(args.Content));
options = RequestOptions.CreateOrClone(options);
var ids = new BucketIds(channelId: channelId);
return await SendJsonAsync<Message>("POST", () => $"channels/{channelId}/messages", args, ids, clientBucketId: ClientBucket.SendEditId, options: options).ConfigureAwait(false);
return await SendJsonAsync<Message>("POST", () => $"channels/{channelId}/messages", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
}
public async Task<Message> UploadFileAsync(ulong channelId, UploadFileParams args, RequestOptions options = null)
{
@@ -464,7 +466,7 @@ namespace Discord.API
}
var ids = new BucketIds(channelId: channelId);
return await SendMultipartAsync<Message>("POST", () => $"channels/{channelId}/messages", args.ToDictionary(), ids, clientBucketId: ClientBucket.SendEditId, options: options).ConfigureAwait(false);
return await SendMultipartAsync<Message>("POST", () => $"channels/{channelId}/messages", args.ToDictionary(), ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
}
public async Task DeleteMessageAsync(ulong channelId, ulong messageId, RequestOptions options = null)
{
@@ -496,21 +498,22 @@ namespace Discord.API
break;
}
}
public async Task<Message> ModifyMessageAsync(ulong channelId, ulong messageId, ModifyMessageParams args, RequestOptions options = null)
public async Task<Message> ModifyMessageAsync(ulong channelId, ulong messageId, Rest.ModifyMessageParams args, RequestOptions options = null)
{
Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotEqual(messageId, 0, nameof(messageId));
Preconditions.NotNull(args, nameof(args));
if (args.Content.IsSpecified)
{
Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content));
if (!args.Embed.IsSpecified)
Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content));
if (args.Content.Value.Length > DiscordConfig.MaxMessageSize)
throw new ArgumentOutOfRangeException($"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", nameof(args.Content));
}
options = RequestOptions.CreateOrClone(options);
var ids = new BucketIds(channelId: channelId);
return await SendJsonAsync<Message>("PATCH", () => $"channels/{channelId}/messages/{messageId}", args, ids, clientBucketId: ClientBucket.SendEditId, options: options).ConfigureAwait(false);
return await SendJsonAsync<Message>("PATCH", () => $"channels/{channelId}/messages/{messageId}", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
}
public async Task AddReactionAsync(ulong channelId, ulong messageId, string emoji, RequestOptions options = null)
{
@@ -1112,19 +1115,6 @@ namespace Discord.API
using (JsonReader reader = new JsonTextReader(text))
return _serializer.Deserialize<T>(reader);
}
internal string GetBucketId(ulong guildId = 0, ulong channelId = 0, [CallerMemberName] string methodName = "")
{
if (guildId != 0)
{
if (channelId != 0)
return $"{methodName}({guildId}/{channelId})";
else
return $"{methodName}({guildId})";
}
else if (channelId != 0)
return $"{methodName}({channelId})";
return $"{methodName}()";
}
internal class BucketIds
{

View File

@@ -1,4 +1,5 @@
#pragma warning disable CS1591
using System;
using Newtonsoft.Json;
namespace Discord.API.Rest
@@ -13,6 +14,8 @@ namespace Discord.API.Rest
public Optional<string> Nonce { get; set; }
[JsonProperty("tts")]
public Optional<bool> IsTTS { get; set; }
[JsonProperty("embed")]
public Optional<Embed> Embed { get; set; }
public CreateMessageParams(string content)
{

View File

@@ -8,5 +8,7 @@ namespace Discord.API.Rest
{
[JsonProperty("content")]
public Optional<string> Content { get; set; }
[JsonProperty("embed")]
public Optional<Embed> Embed { get; set; }
}
}

View File

@@ -0,0 +1,60 @@
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
<PropertyGroup>
<Description>A .Net API wrapper and bot framework for Discord.</Description>
<VersionPrefix>1.0.0-beta2</VersionPrefix>
<TargetFramework>netstandard1.3</TargetFramework>
<AssemblyName>Discord.Net.Core</AssemblyName>
<PackageTags>discord;discordapp</PackageTags>
<PackageProjectUrl>https://github.com/RogueException/Discord.Net</PackageProjectUrl>
<PackageLicenseUrl>http://opensource.org/licenses/MIT</PackageLicenseUrl>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>git://github.com/RogueException/Discord.Net</RepositoryUrl>
<PackageTargetFallback Condition=" '$(TargetFramework)' == 'netstandard1.3' ">$(PackageTargetFallback);dotnet5.4;dnxcore50;portable-net45+win8</PackageTargetFallback>
</PropertyGroup>
<ItemGroup>
<Compile Include="**\*.cs" />
<EmbeddedResource Include="**\*.resx" />
<EmbeddedResource Include="compiler\resources\**\*" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<PackageReference Include="Microsoft.NET.Sdk">
<Version>1.0.0-alpha-20161104-2</Version>
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.Win32.Primitives">
<Version>4.3.0</Version>
</PackageReference>
<PackageReference Include="Newtonsoft.Json">
<Version>9.0.1</Version>
</PackageReference>
<PackageReference Include="System.Collections.Concurrent">
<Version>4.3.0</Version>
</PackageReference>
<PackageReference Include="System.Collections.Immutable">
<Version>1.3.0</Version>
</PackageReference>
<PackageReference Include="System.Interactive.Async">
<Version>3.1.0</Version>
</PackageReference>
<PackageReference Include="System.Net.Http">
<Version>4.3.0</Version>
</PackageReference>
<PackageReference Include="System.Net.WebSockets.Client">
<Version>4.3.0</Version>
<PrivateAssets>All</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup />
<PropertyGroup Label="Configuration">
<SignAssembly>False</SignAssembly>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DefineConstants>$(DefineConstants);RELEASE</DefineConstants>
<NoWarn>$(NoWarn);CS1573;CS1591</NoWarn>
<WarningsAsErrors>true</WarningsAsErrors>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>91e9e7bd-75c9-4e98-84aa-2c271922e5c2</ProjectGuid>
<RootNamespace>Discord</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@@ -11,9 +11,10 @@ namespace Discord
"Unknown";
public static readonly string ClientAPIUrl = $"https://discordapp.com/api/v{APIVersion}/";
public const string CDNUrl = "https://discordcdn.com/";
public const string CDNUrl = "https://cdn.discordapp.com/";
public const string InviteUrl = "https://discord.gg/";
public const int DefaultRequestTimeout = 15000;
public const int MaxMessageSize = 2000;
public const int MaxMessagesPerBatch = 100;
public const int MaxUsersPerBatch = 1000;

View File

@@ -8,7 +8,7 @@ namespace Discord
public interface IMessageChannel : IChannel
{
/// <summary> Sends a message to this message channel. </summary>
Task<IUserMessage> SendMessageAsync(string text, bool isTTS = false, RequestOptions options = null);
Task<IUserMessage> SendMessageAsync(string text, bool isTTS = false, EmbedBuilder embed = null, RequestOptions options = null);
/// <summary> Sends a file to this text channel, with an optional caption. </summary>
Task<IUserMessage> SendFileAsync(string filePath, string text = null, bool isTTS = false, RequestOptions options = null);
/// <summary> Sends a file to this text channel, with an optional caption. </summary>

View File

@@ -0,0 +1,29 @@
using System.Diagnostics;
using Model = Discord.API.EmbedAuthor;
namespace Discord
{
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public struct EmbedAuthor
{
public string Name { get; set; }
public string Url { get; set; }
public string IconUrl { get; set; }
public string ProxyIconUrl { get; set; }
private EmbedAuthor(string name, string url, string iconUrl, string proxyIconUrl)
{
Name = name;
Url = url;
IconUrl = iconUrl;
ProxyIconUrl = proxyIconUrl;
}
internal static EmbedAuthor Create(Model model)
{
return new EmbedAuthor(model.Name, model.Url, model.IconUrl, model.ProxyIconUrl);
}
private string DebuggerDisplay => $"{Name} ({Url})";
public override string ToString() => Name;
}
}

View File

@@ -0,0 +1,208 @@
using System;
using System.Collections.Generic;
using Embed = Discord.API.Embed;
using Field = Discord.API.EmbedField;
using Author = Discord.API.EmbedAuthor;
using Footer = Discord.API.EmbedFooter;
using Thumbnail = Discord.API.EmbedThumbnail;
using Image = Discord.API.EmbedImage;
namespace Discord
{
public class EmbedBuilder
{
private readonly Embed _model;
private readonly List<Field> _fields;
public EmbedBuilder()
{
_model = new Embed { Type = "rich" };
_fields = new List<Field>();
}
public string Title { get { return _model.Title; } set { _model.Title = value; } }
public string Description { get { return _model.Description; } set { _model.Description = value; } }
public string Url { get { return _model.Url; } set { _model.Url = value; } }
public string ThumbnailUrl { get; set; }
public string ImageUrl { get; set; }
public DateTimeOffset? Timestamp { get; set; }
public Color? Color { get { return _model.Color.HasValue ? new Color(_model.Color.Value) : (Color?)null; } set { _model.Color = value?.RawValue; } }
public EmbedAuthorBuilder Author { get; set; }
public EmbedFooterBuilder Footer { get; set; }
public EmbedBuilder WithTitle(string title)
{
Title = title;
return this;
}
public EmbedBuilder WithDescription(string description)
{
Description = description;
return this;
}
public EmbedBuilder WithUrl(string url)
{
Url = url;
return this;
}
public EmbedBuilder WithThumbnailUrl(string thumbnailUrl)
{
ThumbnailUrl = thumbnailUrl;
return this;
}
public EmbedBuilder WithImageUrl(string imageUrl)
{
ImageUrl = ImageUrl;
return this;
}
public EmbedBuilder WithCurrentTimestamp()
{
Timestamp = DateTimeOffset.UtcNow;
return this;
}
public EmbedBuilder WithTimestamp(DateTimeOffset dateTimeOffset)
{
Timestamp = dateTimeOffset;
return this;
}
public EmbedBuilder WithColor(Color color)
{
Color = color;
return this;
}
public EmbedBuilder WithAuthor(EmbedAuthorBuilder author)
{
Author = author;
return this;
}
public EmbedBuilder WithAuthor(Action<EmbedAuthorBuilder> action)
{
var author = new EmbedAuthorBuilder();
action(author);
Author = author;
return this;
}
public EmbedBuilder WithFooter(EmbedFooterBuilder footer)
{
Footer = footer;
return this;
}
public EmbedBuilder WithFooter(Action<EmbedFooterBuilder> action)
{
var footer = new EmbedFooterBuilder();
action(footer);
Footer = footer;
return this;
}
public EmbedBuilder AddField(Action<EmbedFieldBuilder> action)
{
var field = new EmbedFieldBuilder();
action(field);
_fields.Add(field.ToModel());
return this;
}
internal Embed Build()
{
_model.Author = Author?.ToModel();
_model.Footer = Footer?.ToModel();
_model.Timestamp = Timestamp?.ToUniversalTime();
_model.Thumbnail = ThumbnailUrl != null ? new Thumbnail { Url = ThumbnailUrl } : null;
_model.Image = ImageUrl != null ? new Image { Url = ImageUrl } : null;
_model.Fields = _fields.ToArray();
return _model;
}
}
public class EmbedFieldBuilder
{
private readonly Field _model;
public string Name { get { return _model.Name; } set { _model.Name = value; } }
public string Value { get { return _model.Value; } set { _model.Value = value; } }
public bool IsInline { get { return _model.Inline; } set { _model.Inline = value; } }
public EmbedFieldBuilder()
{
_model = new Field();
}
public EmbedFieldBuilder WithName(string name)
{
Name = name;
return this;
}
public EmbedFieldBuilder WithValue(string value)
{
Value = value;
return this;
}
public EmbedFieldBuilder WithIsInline(bool isInline)
{
IsInline = isInline;
return this;
}
internal Field ToModel() => _model;
}
public class EmbedAuthorBuilder
{
private readonly Author _model;
public string Name { get { return _model.Name; } set { _model.Name = value; } }
public string Url { get { return _model.Url; } set { _model.Url = value; } }
public string IconUrl { get { return _model.IconUrl; } set { _model.IconUrl = value; } }
public EmbedAuthorBuilder()
{
_model = new Author();
}
public EmbedAuthorBuilder WithName(string name)
{
Name = name;
return this;
}
public EmbedAuthorBuilder WithUrl(string url)
{
Url = url;
return this;
}
public EmbedAuthorBuilder WithIconUrl(string iconUrl)
{
IconUrl = iconUrl;
return this;
}
internal Author ToModel() => _model;
}
public class EmbedFooterBuilder
{
private readonly Footer _model;
public string Text { get { return _model.Text; } set { _model.Text = value; } }
public string IconUrl { get { return _model.IconUrl; } set { _model.IconUrl = value; } }
public EmbedFooterBuilder()
{
_model = new Footer();
}
public EmbedFooterBuilder WithText(string text)
{
Text = text;
return this;
}
public EmbedFooterBuilder WithIconUrl(string iconUrl)
{
IconUrl = iconUrl;
return this;
}
internal Footer ToModel() => _model;
}
}

View File

@@ -0,0 +1,27 @@
using System.Diagnostics;
using Model = Discord.API.EmbedField;
namespace Discord
{
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public struct EmbedField
{
public string Name { get; set; }
public string Value { get; set; }
public bool Inline { get; set; }
private EmbedField(string name, string value, bool inline)
{
Name = name;
Value = value;
Inline = inline;
}
internal static EmbedField Create(Model model)
{
return new EmbedField(model.Name, model.Value, model.Inline);
}
private string DebuggerDisplay => $"{Name} ({Value}";
public override string ToString() => Name;
}
}

View File

@@ -0,0 +1,27 @@
using System.Diagnostics;
using Model = Discord.API.EmbedFooter;
namespace Discord
{
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public struct EmbedFooter
{
public string Text { get; set; }
public string IconUrl { get; set; }
public string ProxyUrl { get; set; }
private EmbedFooter(string text, string iconUrl, string proxyUrl)
{
Text = text;
IconUrl = iconUrl;
ProxyUrl = proxyUrl;
}
internal static EmbedFooter Create(Model model)
{
return new EmbedFooter(model.Text, model.IconUrl, model.ProxyIconUrl);
}
private string DebuggerDisplay => $"{Text} ({IconUrl})";
public override string ToString() => Text;
}
}

View File

@@ -0,0 +1,31 @@
using System.Diagnostics;
using Model = Discord.API.EmbedImage;
namespace Discord
{
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public struct EmbedImage
{
public string Url { get; }
public string ProxyUrl { get; }
public int? Height { get; }
public int? Width { get; }
private EmbedImage(string url, string proxyUrl, int? height, int? width)
{
Url = url;
ProxyUrl = proxyUrl;
Height = height;
Width = width;
}
internal static EmbedImage Create(Model model)
{
return new EmbedImage(model.Url, model.ProxyUrl,
model.Height.IsSpecified ? model.Height.Value : (int?)null,
model.Width.IsSpecified ? model.Width.Value : (int?)null);
}
private string DebuggerDisplay => $"{Url} ({(Width != null && Height != null ? $"{Width}x{Height}" : "0x0")})";
public override string ToString() => Url;
}
}

View File

@@ -25,7 +25,7 @@ namespace Discord
model.Width.IsSpecified ? model.Width.Value : (int?)null);
}
private string DebuggerDisplay => $"{ToString()} ({Url})";
public override string ToString() => Width != null && Height != null ? $"{Width}x{Height}" : "0x0";
private string DebuggerDisplay => $"{Url} ({(Width != null && Height != null ? $"{Width}x{Height}" : "0x0")})";
public override string ToString() => Url;
}
}

View File

@@ -0,0 +1,29 @@
using System.Diagnostics;
using Model = Discord.API.EmbedVideo;
namespace Discord
{
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public struct EmbedVideo
{
public string Url { get; }
public int? Height { get; }
public int? Width { get; }
private EmbedVideo(string url, int? height, int? width)
{
Url = url;
Height = height;
Width = width;
}
internal static EmbedVideo Create(Model model)
{
return new EmbedVideo(model.Url,
model.Height.IsSpecified ? model.Height.Value : (int?)null,
model.Width.IsSpecified ? model.Width.Value : (int?)null);
}
private string DebuggerDisplay => $"{Url} ({(Width != null && Height != null ? $"{Width}x{Height}" : "0x0")})";
public override string ToString() => Url;
}
}

View File

@@ -1,4 +1,7 @@
namespace Discord
using System;
using System.Collections.Immutable;
namespace Discord
{
public interface IEmbed
{
@@ -6,7 +9,14 @@
string Type { get; }
string Title { get; }
string Description { get; }
DateTimeOffset? Timestamp { get; }
Color? Color { get; }
EmbedImage? Image { get; }
EmbedVideo? Video { get; }
EmbedAuthor? Author { get; }
EmbedFooter? Footer { get; }
EmbedProvider? Provider { get; }
EmbedThumbnail? Thumbnail { get; }
ImmutableArray<EmbedField> Fields { get; }
}
}

View File

@@ -1,5 +1,4 @@
using Discord.API.Rest;
using System;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Discord
{
public class ModifyMessageParams
{
public Optional<string> Content { get; set; }
public Optional<EmbedBuilder> Embed { get; set; }
}
}

View File

@@ -2,10 +2,12 @@
{
public enum TagHandling
{
Ignore = 0,
Remove,
Name,
FullName,
Sanitize
Ignore = 0, //<@53905483156684800> -> <@53905483156684800>
Remove, //<@53905483156684800> ->
Name, //<@53905483156684800> -> @Voltana
NameNoPrefix, //<@53905483156684800> -> Voltana
FullName, //<@53905483156684800> -> @Voltana#8252
FullNameNoPrefix, //<@53905483156684800> -> Voltana#8252
Sanitize //<@53905483156684800> -> <@53905483156684800> (w/ nbsp)
}
}

View File

@@ -32,6 +32,12 @@ namespace Discord
}
public Color(float r, float g, float b)
{
if (r < 0.0f || r > 1.0f)
throw new ArgumentOutOfRangeException(nameof(r), "A float value must be within [0,1]");
if (g < 0.0f || g > 1.0f)
throw new ArgumentOutOfRangeException(nameof(g), "A float value must be within [0,1]");
if (b < 0.0f || b > 1.0f)
throw new ArgumentOutOfRangeException(nameof(b), "A float value must be within [0,1]");
RawValue =
((uint)(r * 255.0f) << 16) |
((uint)(g * 255.0f) << 8) |

View File

@@ -4,7 +4,7 @@ using System.Threading.Tasks;
namespace Discord
{
public interface IRole : ISnowflakeEntity, IDeletable, IMentionable
public interface IRole : ISnowflakeEntity, IDeletable, IMentionable, IComparable<IRole>
{
/// <summary> Gets the guild owning this role.</summary>
IGuild Guild { get; }
@@ -27,4 +27,4 @@ namespace Discord
///// <summary> Modifies this role. </summary>
Task ModifyAsync(Action<ModifyGuildRoleParams> func, RequestOptions options = null);
}
}
}

View File

@@ -6,14 +6,23 @@ namespace Discord
{
public static class GuildUserExtensions
{
//TODO: Should we remove Add/Remove? Encourages race conditions.
public static Task AddRolesAsync(this IGuildUser user, params IRole[] roles)
=> AddRolesAsync(user, (IEnumerable<IRole>)roles);
=> ChangeRolesAsync(user, add: roles);
public static Task AddRolesAsync(this IGuildUser user, IEnumerable<IRole> roles)
=> user.ModifyAsync(x => x.RoleIds = user.RoleIds.Concat(roles.Select(y => y.Id)).ToArray());
=> ChangeRolesAsync(user, add: roles);
public static Task RemoveRolesAsync(this IGuildUser user, params IRole[] roles)
=> RemoveRolesAsync(user, (IEnumerable<IRole>)roles);
=> ChangeRolesAsync(user, remove: roles);
public static Task RemoveRolesAsync(this IGuildUser user, IEnumerable<IRole> roles)
=> user.ModifyAsync(x => x.RoleIds = user.RoleIds.Except(roles.Select(y => y.Id)).ToArray());
=> ChangeRolesAsync(user, remove: roles);
public static async Task ChangeRolesAsync(this IGuildUser user, IEnumerable<IRole> add = null, IEnumerable<IRole> remove = null)
{
IEnumerable<ulong> roleIds = user.RoleIds;
if (remove != null)
roleIds = roleIds.Except(remove.Select(x => x.Id));
if (add != null)
roleIds = roleIds.Concat(add.Select(x => x.Id));
await user.ModifyAsync(x => x.RoleIds = roleIds.ToArray()).ConfigureAwait(false);
}
}
}

View File

@@ -0,0 +1,18 @@
namespace Discord
{
internal static class RoleExtensions
{
internal static int Compare(this IRole left, IRole right)
{
if (left == null)
return -1;
if (right == null)
return 1;
var result = left.Position.CompareTo(right.Position);
// As per Discord's documentation, a tie is broken by ID
if (result != 0)
return result;
return left.Id.CompareTo(right.Id);
}
}
}

View File

@@ -2,25 +2,47 @@
namespace Discord.Net.Queue
{
public struct ClientBucket
public enum ClientBucketType
{
public const string SendEditId = "<send_edit>";
Unbucketed = 0,
SendEdit = 1
}
internal struct ClientBucket
{
private static readonly ImmutableDictionary<ClientBucketType, ClientBucket> _defsByType;
private static readonly ImmutableDictionary<string, ClientBucket> _defsById;
private static readonly ImmutableDictionary<string, ClientBucket> _defs;
static ClientBucket()
{
var builder = ImmutableDictionary.CreateBuilder<string, ClientBucket>();
builder.Add(SendEditId, new ClientBucket(10, 10));
_defs = builder.ToImmutable();
var buckets = new[]
{
new ClientBucket(ClientBucketType.Unbucketed, "<unbucketed>", 10, 10),
new ClientBucket(ClientBucketType.SendEdit, "<send_edit>", 10, 10)
};
var builder = ImmutableDictionary.CreateBuilder<ClientBucketType, ClientBucket>();
foreach (var bucket in buckets)
builder.Add(bucket.Type, bucket);
_defsByType = builder.ToImmutable();
var builder2 = ImmutableDictionary.CreateBuilder<string, ClientBucket>();
foreach (var bucket in buckets)
builder2.Add(bucket.Id, bucket);
_defsById = builder2.ToImmutable();
}
public static ClientBucket Get(string id) =>_defs[id];
public static ClientBucket Get(ClientBucketType type) => _defsByType[type];
public static ClientBucket Get(string id) => _defsById[id];
public ClientBucketType Type { get; }
public string Id { get; }
public int WindowCount { get; }
public int WindowSeconds { get; }
public ClientBucket(int count, int seconds)
public ClientBucket(ClientBucketType type, string id, int count, int seconds)
{
Type = type;
Id = id;
WindowCount = count;
WindowSeconds = seconds;
}

View File

@@ -79,7 +79,9 @@ namespace Discord.Net.Queue
int millis = (int)Math.Ceiling((_waitUntil - DateTimeOffset.UtcNow).TotalMilliseconds);
if (millis > 0)
{
#if DEBUG_LIMITS
Debug.WriteLine($"[{id}] Sleeping {millis} ms (Pre-emptive) [Global]");
#endif
await Task.Delay(millis).ConfigureAwait(false);
}
}

View File

@@ -1,7 +1,10 @@
using Newtonsoft.Json;
using Discord.Net.Rest;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
#if DEBUG_LIMITS
using System.Diagnostics;
#endif
using System.IO;
using System.Net;
using System.Threading;
@@ -27,8 +30,8 @@ namespace Discord.Net.Queue
_lock = new object();
if (request.Options.ClientBucketId != null)
WindowCount = ClientBucket.Get(request.Options.ClientBucketId).WindowCount;
if (request.Options.IsClientBucket)
WindowCount = ClientBucket.Get(request.Options.BucketId).WindowCount;
else
WindowCount = 1; //Only allow one request until we get a header back
_semaphore = WindowCount;
@@ -40,62 +43,91 @@ namespace Discord.Net.Queue
public async Task<Stream> SendAsync(RestRequest request)
{
int id = Interlocked.Increment(ref nextId);
#if DEBUG_LIMITS
Debug.WriteLine($"[{id}] Start");
#endif
LastAttemptAt = DateTimeOffset.UtcNow;
while (true)
{
await _queue.EnterGlobalAsync(id, request).ConfigureAwait(false);
await EnterAsync(id, request).ConfigureAwait(false);
#if DEBUG_LIMITS
Debug.WriteLine($"[{id}] Sending...");
var response = await request.SendAsync().ConfigureAwait(false);
TimeSpan lag = DateTimeOffset.UtcNow - DateTimeOffset.Parse(response.Headers["Date"]);
var info = new RateLimitInfo(response.Headers);
if (response.StatusCode < (HttpStatusCode)200 || response.StatusCode >= (HttpStatusCode)300)
#endif
TimeSpan lag = default(TimeSpan);
RateLimitInfo info = default(RateLimitInfo);
try
{
switch (response.StatusCode)
var response = await request.SendAsync().ConfigureAwait(false);
lag = DateTimeOffset.UtcNow - DateTimeOffset.Parse(response.Headers["Date"]);
info = new RateLimitInfo(response.Headers);
if (response.StatusCode < (HttpStatusCode)200 || response.StatusCode >= (HttpStatusCode)300)
{
case (HttpStatusCode)429:
if (info.IsGlobal)
{
Debug.WriteLine($"[{id}] (!) 429 [Global]");
_queue.PauseGlobal(info, lag);
}
else
{
Debug.WriteLine($"[{id}] (!) 429");
UpdateRateLimit(id, request, info, lag, true);
}
await _queue.RaiseRateLimitTriggered(Id, info).ConfigureAwait(false);
continue; //Retry
case HttpStatusCode.BadGateway: //502
Debug.WriteLine($"[{id}] (!) 502");
continue; //Continue
default:
string reason = null;
if (response.Stream != null)
{
try
switch (response.StatusCode)
{
case (HttpStatusCode)429:
if (info.IsGlobal)
{
using (var reader = new StreamReader(response.Stream))
using (var jsonReader = new JsonTextReader(reader))
{
var json = JToken.Load(jsonReader);
reason = json.Value<string>("message");
}
#if DEBUG_LIMITS
Debug.WriteLine($"[{id}] (!) 429 [Global]");
#endif
_queue.PauseGlobal(info, lag);
}
catch { }
}
throw new HttpException(response.StatusCode, reason);
else
{
#if DEBUG_LIMITS
Debug.WriteLine($"[{id}] (!) 429");
#endif
UpdateRateLimit(id, request, info, lag, true);
}
await _queue.RaiseRateLimitTriggered(Id, info).ConfigureAwait(false);
continue; //Retry
case HttpStatusCode.BadGateway: //502
#if DEBUG_LIMITS
Debug.WriteLine($"[{id}] (!) 502");
#endif
continue; //Continue
default:
string reason = null;
if (response.Stream != null)
{
try
{
using (var reader = new StreamReader(response.Stream))
using (var jsonReader = new JsonTextReader(reader))
{
var json = JToken.Load(jsonReader);
reason = json.Value<string>("message");
}
}
catch { }
}
throw new HttpException(response.StatusCode, reason);
}
}
else
{
#if DEBUG_LIMITS
Debug.WriteLine($"[{id}] Success");
#endif
return response.Stream;
}
}
else
#if DEBUG_LIMITS
catch
{
Debug.WriteLine($"[{id}] Error");
throw;
}
#endif
finally
{
Debug.WriteLine($"[{id}] Success");
UpdateRateLimit(id, request, info, lag, false);
#if DEBUG_LIMITS
Debug.WriteLine($"[{id}] Stop");
return response.Stream;
#endif
}
}
}
@@ -135,7 +167,9 @@ namespace Discord.Net.Queue
if (resetAt > timeoutAt)
throw new RateLimitedException();
int millis = (int)Math.Ceiling((resetAt.Value - DateTimeOffset.UtcNow).TotalMilliseconds);
#if DEBUG_LIMITS
Debug.WriteLine($"[{id}] Sleeping {millis} ms (Pre-emptive)");
#endif
if (millis > 0)
await Task.Delay(millis, request.CancelToken).ConfigureAwait(false);
}
@@ -143,13 +177,17 @@ namespace Discord.Net.Queue
{
if ((timeoutAt.Value - DateTimeOffset.UtcNow).TotalMilliseconds < 500.0)
throw new RateLimitedException();
#if DEBUG_LIMITS
Debug.WriteLine($"[{id}] Sleeping 500* ms (Pre-emptive)");
#endif
await Task.Delay(500, request.CancelToken).ConfigureAwait(false);
}
continue;
}
#if DEBUG_LIMITS
else
Debug.WriteLine($"[{id}] Entered Semaphore ({_semaphore}/{WindowCount} remaining)");
#endif
break;
}
}
@@ -166,7 +204,9 @@ namespace Discord.Net.Queue
{
WindowCount = info.Limit.Value;
_semaphore = info.Remaining.Value;
#if DEBUG_LIMITS
Debug.WriteLine($"[{id}] Upgraded Semaphore to {info.Remaining.Value}/{WindowCount}");
#endif
}
var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
@@ -182,24 +222,32 @@ namespace Discord.Net.Queue
{
//RetryAfter is more accurate than Reset, where available
resetTick = DateTimeOffset.UtcNow.AddMilliseconds(info.RetryAfter.Value);
#if DEBUG_LIMITS
Debug.WriteLine($"[{id}] Retry-After: {info.RetryAfter.Value} ({info.RetryAfter.Value} ms)");
#endif
}
else if (info.Reset.HasValue)
{
resetTick = info.Reset.Value.AddSeconds(/*1.0 +*/ lag.TotalSeconds);
int diff = (int)(resetTick.Value - DateTimeOffset.UtcNow).TotalMilliseconds;
#if DEBUG_LIMITS
Debug.WriteLine($"[{id}] X-RateLimit-Reset: {info.Reset.Value.ToUnixTimeSeconds()} ({diff} ms, {lag.TotalMilliseconds} ms lag)");
#endif
}
else if (request.Options.ClientBucketId != null)
else if (request.Options.IsClientBucket && request.Options.BucketId != null)
{
resetTick = DateTimeOffset.UtcNow.AddSeconds(ClientBucket.Get(request.Options.ClientBucketId).WindowSeconds);
Debug.WriteLine($"[{id}] Client Bucket ({ClientBucket.Get(request.Options.ClientBucketId).WindowSeconds * 1000} ms)");
resetTick = DateTimeOffset.UtcNow.AddSeconds(ClientBucket.Get(request.Options.BucketId).WindowSeconds);
#if DEBUG_LIMITS
Debug.WriteLine($"[{id}] Client Bucket ({ClientBucket.Get(request.Options.BucketId).WindowSeconds * 1000} ms)");
#endif
}
if (resetTick == null)
{
WindowCount = 0; //No rate limit info, disable limits on this bucket (should only ever happen with a user token)
#if DEBUG_LIMITS
Debug.WriteLine($"[{id}] Disabled Semaphore");
#endif
return;
}
@@ -207,7 +255,9 @@ namespace Discord.Net.Queue
{
_resetTick = resetTick;
LastAttemptAt = resetTick.Value; //Make sure we dont destroy this until after its been reset
#if DEBUG_LIMITS
Debug.WriteLine($"[{id}] Reset in {(int)Math.Ceiling((resetTick - DateTimeOffset.UtcNow).Value.TotalMilliseconds)} ms");
#endif
if (!hasQueuedReset)
{
@@ -227,7 +277,9 @@ namespace Discord.Net.Queue
millis = (int)Math.Ceiling((_resetTick.Value - DateTimeOffset.UtcNow).TotalMilliseconds);
if (millis <= 0) //Make sure we havent gotten a more accurate reset time
{
#if DEBUG_LIMITS
Debug.WriteLine($"[{id}] * Reset *");
#endif
_semaphore = WindowCount;
_resetTick = null;
return;
@@ -236,4 +288,4 @@ namespace Discord.Net.Queue
}
}
}
}
}

View File

@@ -120,7 +120,7 @@ namespace Discord.Net.Rest
cancelToken = CancellationTokenSource.CreateLinkedTokenSource(_cancelToken, cancelToken).Token;
HttpResponseMessage response = await _client.SendAsync(request, cancelToken).ConfigureAwait(false);
var headers = response.Headers.ToDictionary(x => x.Key, x => x.Value.FirstOrDefault());
var headers = response.Headers.ToDictionary(x => x.Key, x => x.Value.FirstOrDefault(), StringComparer.OrdinalIgnoreCase);
var stream = !headerOnly ? await response.Content.ReadAsStreamAsync().ConfigureAwait(false) : null;
return new RestResponse(response.StatusCode, headers, stream);

View File

@@ -101,6 +101,8 @@ namespace Discord.Net.WebSockets
if (_client != null && _client.State == WebSocketState.Open)
{
var token = new CancellationToken();
await _client.CloseAsync(WebSocketCloseStatus.NormalClosure, "", token);
_client.Dispose();
_client = null;
}

View File

@@ -10,7 +10,7 @@
internal bool IgnoreState { get; set; }
internal string BucketId { get; set; }
internal string ClientBucketId { get; set; }
internal bool IsClientBucket { get; set; }
internal static RequestOptions CreateOrClone(RequestOptions options)
{
@@ -22,7 +22,7 @@
public RequestOptions()
{
Timeout = 30000;
Timeout = DiscordConfig.DefaultRequestTimeout;
}
public RequestOptions Clone() => MemberwiseClone() as RequestOptions;

View File

@@ -85,14 +85,17 @@ namespace Discord
return false;
}
internal static string Resolve(IMessage msg, TagHandling userHandling, TagHandling channelHandling, TagHandling roleHandling, TagHandling everyoneHandling, TagHandling emojiHandling)
internal static string Resolve(IMessage msg, int startIndex, TagHandling userHandling, TagHandling channelHandling, TagHandling roleHandling, TagHandling everyoneHandling, TagHandling emojiHandling)
{
var text = new StringBuilder(msg.Content);
var text = new StringBuilder(msg.Content.Substring(startIndex));
var tags = msg.Tags;
int indexOffset = 0;
int indexOffset = -startIndex;
foreach (var tag in tags)
{
if (tag.Index < startIndex)
continue;
string newText = "";
switch (tag.Type)
{
@@ -139,12 +142,22 @@ namespace Discord
if (user != null)
return $"@{guildUser?.Nickname ?? user?.Username}";
else
return $"@unknown-user";
return $"";
case TagHandling.NameNoPrefix:
if (user != null)
return $"{guildUser?.Nickname ?? user?.Username}";
else
return $"";
case TagHandling.FullName:
if (user != null)
return $"@{user.Username}#{user.Discriminator}";
else
return $"@unknown-user";
return $"";
case TagHandling.FullNameNoPrefix:
if (user != null)
return $"{user.Username}#{user.Discriminator}";
else
return $"";
case TagHandling.Sanitize:
if (guildUser != null && guildUser.Nickname == null)
return MentionUser($"{SanitizeChar}{tag.Key}", false);
@@ -166,7 +179,13 @@ namespace Discord
if (channel != null)
return $"#{channel.Name}";
else
return $"#deleted-channel";
return $"";
case TagHandling.NameNoPrefix:
case TagHandling.FullNameNoPrefix:
if (channel != null)
return $"{channel.Name}";
else
return $"";
case TagHandling.Sanitize:
return MentionChannel($"{SanitizeChar}{tag.Key}");
}
@@ -185,7 +204,13 @@ namespace Discord
if (role != null)
return $"@{role.Name}";
else
return $"@deleted-role";
return $"";
case TagHandling.NameNoPrefix:
case TagHandling.FullNameNoPrefix:
if (role != null)
return $"{role.Name}";
else
return $"";
case TagHandling.Sanitize:
return MentionRole($"{SanitizeChar}{tag.Key}");
}
@@ -200,7 +225,9 @@ namespace Discord
{
case TagHandling.Name:
case TagHandling.FullName:
return "@everyone";
case TagHandling.NameNoPrefix:
case TagHandling.FullNameNoPrefix:
return "everyone";
case TagHandling.Sanitize:
return $"@{SanitizeChar}everyone";
}
@@ -215,9 +242,11 @@ namespace Discord
{
case TagHandling.Name:
case TagHandling.FullName:
return "@everyone";
case TagHandling.NameNoPrefix:
case TagHandling.FullNameNoPrefix:
return "here";
case TagHandling.Sanitize:
return $"@{SanitizeChar}everyone";
return $"@{SanitizeChar}here";
}
}
return "";
@@ -232,8 +261,11 @@ namespace Discord
case TagHandling.Name:
case TagHandling.FullName:
return $":{emoji.Name}:";
case TagHandling.NameNoPrefix:
case TagHandling.FullNameNoPrefix:
return $"{emoji.Name}";
case TagHandling.Sanitize:
return $"<@{SanitizeChar}everyone";
return $"<{emoji.Id}{SanitizeChar}:{SanitizeChar}{emoji.Name}>";
}
}
return "";

View File

@@ -5,148 +5,182 @@ namespace Discord
internal static class Preconditions
{
//Objects
public static void NotNull<T>(T obj, string name) where T : class { if (obj == null) throw new ArgumentNullException(name); }
public static void NotNull<T>(Optional<T> obj, string name) where T : class { if (obj.IsSpecified && obj.Value == null) throw new ArgumentNullException(name); }
public static void NotNull<T>(T obj, string name, string msg = null) where T : class { if (obj == null) throw CreateNotNullException(name, msg); }
public static void NotNull<T>(Optional<T> obj, string name, string msg = null) where T : class { if (obj.IsSpecified && obj.Value == null) throw CreateNotNullException(name, msg); }
private static ArgumentNullException CreateNotNullException(string name, string msg)
{
if (msg == null) return new ArgumentNullException(name);
else return new ArgumentNullException(name, msg);
}
//Strings
public static void NotEmpty(string obj, string name) { if (obj.Length == 0) throw new ArgumentException("Argument cannot be empty.", name); }
public static void NotEmpty(Optional<string> obj, string name) { if (obj.IsSpecified && obj.Value.Length == 0) throw new ArgumentException("Argument cannot be empty.", name); }
public static void NotNullOrEmpty(string obj, string name)
public static void NotEmpty(string obj, string name, string msg = null) { if (obj.Length == 0) throw CreateNotEmptyException(name, msg); }
public static void NotEmpty(Optional<string> obj, string name, string msg = null) { if (obj.IsSpecified && obj.Value.Length == 0) throw CreateNotEmptyException(name, msg); }
public static void NotNullOrEmpty(string obj, string name, string msg = null)
{
if (obj == null)
throw new ArgumentNullException(name);
if (obj.Length == 0)
throw new ArgumentException("Argument cannot be empty.", name);
if (obj == null) throw CreateNotNullException(name, msg);
if (obj.Length == 0) throw CreateNotEmptyException(name, msg);
}
public static void NotNullOrEmpty(Optional<string> obj, string name)
public static void NotNullOrEmpty(Optional<string> obj, string name, string msg = null)
{
if (obj.IsSpecified)
{
if (obj.Value == null)
throw new ArgumentNullException(name);
if (obj.Value.Length == 0)
throw new ArgumentException("Argument cannot be empty.", name);
if (obj.Value == null) throw CreateNotNullException(name, msg);
if (obj.Value.Length == 0) throw CreateNotEmptyException(name, msg);
}
}
public static void NotNullOrWhitespace(string obj, string name)
public static void NotNullOrWhitespace(string obj, string name, string msg = null)
{
if (obj == null)
throw new ArgumentNullException(name);
if (obj.Trim().Length == 0)
throw new ArgumentException("Argument cannot be blank.", name);
if (obj == null) throw CreateNotNullException(name, msg);
if (obj.Trim().Length == 0) throw CreateNotEmptyException(name, msg);
}
public static void NotNullOrWhitespace(Optional<string> obj, string name)
public static void NotNullOrWhitespace(Optional<string> obj, string name, string msg = null)
{
if (obj.IsSpecified)
{
if (obj.Value == null)
throw new ArgumentNullException(name);
if (obj.Value.Trim().Length == 0)
throw new ArgumentException("Argument cannot be blank.", name);
if (obj.Value == null) throw CreateNotNullException(name, msg);
if (obj.Value.Trim().Length == 0) throw CreateNotEmptyException(name, msg);
}
}
private static ArgumentException CreateNotEmptyException(string name, string msg)
{
if (msg == null) return new ArgumentException(name, "Argument cannot be blank.");
else return new ArgumentException(name, msg);
}
//Numerics
public static void NotEqual(sbyte obj, sbyte value, string name) { if (obj == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(byte obj, byte value, string name) { if (obj == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(short obj, short value, string name) { if (obj == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(ushort obj, ushort value, string name) { if (obj == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(int obj, int value, string name) { if (obj == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(uint obj, uint value, string name) { if (obj == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(long obj, long value, string name) { if (obj == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(ulong obj, ulong value, string name) { if (obj == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(Optional<sbyte> obj, sbyte value, string name) { if (obj.IsSpecified && obj.Value == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(Optional<byte> obj, byte value, string name) { if (obj.IsSpecified && obj.Value == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(Optional<short> obj, short value, string name) { if (obj.IsSpecified && obj.Value == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(Optional<ushort> obj, ushort value, string name) { if (obj.IsSpecified && obj.Value == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(Optional<int> obj, int value, string name) { if (obj.IsSpecified && obj.Value == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(Optional<uint> obj, uint value, string name) { if (obj.IsSpecified && obj.Value == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(Optional<long> obj, long value, string name) { if (obj.IsSpecified && obj.Value == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(Optional<ulong> obj, ulong value, string name) { if (obj.IsSpecified && obj.Value == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(sbyte? obj, sbyte value, string name) { if (obj == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(byte? obj, byte value, string name) { if (obj == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(short? obj, short value, string name) { if (obj == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(ushort? obj, ushort value, string name) { if (obj == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(int? obj, int value, string name) { if (obj == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(uint? obj, uint value, string name) { if (obj == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(long? obj, long value, string name) { if (obj == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(ulong? obj, ulong value, string name) { if (obj == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(Optional<sbyte?> obj, sbyte value, string name) { if (obj.IsSpecified && obj.Value == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(Optional<byte?> obj, byte value, string name) { if (obj.IsSpecified && obj.Value == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(Optional<short?> obj, short value, string name) { if (obj.IsSpecified && obj.Value == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(Optional<ushort?> obj, ushort value, string name) { if (obj.IsSpecified && obj.Value == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(Optional<int?> obj, int value, string name) { if (obj.IsSpecified && obj.Value == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(Optional<uint?> obj, uint value, string name) { if (obj.IsSpecified && obj.Value == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(Optional<long?> obj, long value, string name) { if (obj.IsSpecified && obj.Value == value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(Optional<ulong?> obj, ulong value, string name) { if (obj.IsSpecified && obj.Value == value) throw new ArgumentOutOfRangeException(name); }
public static void AtLeast(sbyte obj, sbyte value, string name) { if (obj < value) throw new ArgumentOutOfRangeException(name); }
public static void AtLeast(byte obj, byte value, string name) { if (obj < value) throw new ArgumentOutOfRangeException(name); }
public static void AtLeast(short obj, short value, string name) { if (obj < value) throw new ArgumentOutOfRangeException(name); }
public static void AtLeast(ushort obj, ushort value, string name) { if (obj < value) throw new ArgumentOutOfRangeException(name); }
public static void AtLeast(int obj, int value, string name) { if (obj < value) throw new ArgumentOutOfRangeException(name); }
public static void AtLeast(uint obj, uint value, string name) { if (obj < value) throw new ArgumentOutOfRangeException(name); }
public static void AtLeast(long obj, long value, string name) { if (obj < value) throw new ArgumentOutOfRangeException(name); }
public static void AtLeast(ulong obj, ulong value, string name) { if (obj < value) throw new ArgumentOutOfRangeException(name); }
public static void AtLeast(Optional<sbyte> obj, sbyte value, string name) { if (obj.IsSpecified && obj.Value < value) throw new ArgumentOutOfRangeException(name); }
public static void AtLeast(Optional<byte> obj, byte value, string name) { if (obj.IsSpecified && obj.Value < value) throw new ArgumentOutOfRangeException(name); }
public static void AtLeast(Optional<short> obj, short value, string name) { if (obj.IsSpecified && obj.Value < value) throw new ArgumentOutOfRangeException(name); }
public static void AtLeast(Optional<ushort> obj, ushort value, string name) { if (obj.IsSpecified && obj.Value < value) throw new ArgumentOutOfRangeException(name); }
public static void AtLeast(Optional<int> obj, int value, string name) { if (obj.IsSpecified && obj.Value < value) throw new ArgumentOutOfRangeException(name); }
public static void AtLeast(Optional<uint> obj, uint value, string name) { if (obj.IsSpecified && obj.Value < value) throw new ArgumentOutOfRangeException(name); }
public static void AtLeast(Optional<long> obj, long value, string name) { if (obj.IsSpecified && obj.Value < value) throw new ArgumentOutOfRangeException(name); }
public static void AtLeast(Optional<ulong> obj, ulong value, string name) { if (obj.IsSpecified && obj.Value < value) throw new ArgumentOutOfRangeException(name); }
public static void GreaterThan(sbyte obj, sbyte value, string name) { if (obj <= value) throw new ArgumentOutOfRangeException(name); }
public static void GreaterThan(byte obj, byte value, string name) { if (obj <= value) throw new ArgumentOutOfRangeException(name); }
public static void GreaterThan(short obj, short value, string name) { if (obj <= value) throw new ArgumentOutOfRangeException(name); }
public static void GreaterThan(ushort obj, ushort value, string name) { if (obj <= value) throw new ArgumentOutOfRangeException(name); }
public static void GreaterThan(int obj, int value, string name) { if (obj <= value) throw new ArgumentOutOfRangeException(name); }
public static void GreaterThan(uint obj, uint value, string name) { if (obj <= value) throw new ArgumentOutOfRangeException(name); }
public static void GreaterThan(long obj, long value, string name) { if (obj <= value) throw new ArgumentOutOfRangeException(name); }
public static void GreaterThan(ulong obj, ulong value, string name) { if (obj <= value) throw new ArgumentOutOfRangeException(name); }
public static void GreaterThan(Optional<sbyte> obj, sbyte value, string name) { if (obj.IsSpecified && obj.Value <= value) throw new ArgumentOutOfRangeException(name); }
public static void GreaterThan(Optional<byte> obj, byte value, string name) { if (obj.IsSpecified && obj.Value <= value) throw new ArgumentOutOfRangeException(name); }
public static void GreaterThan(Optional<short> obj, short value, string name) { if (obj.IsSpecified && obj.Value <= value) throw new ArgumentOutOfRangeException(name); }
public static void GreaterThan(Optional<ushort> obj, ushort value, string name) { if (obj.IsSpecified && obj.Value <= value) throw new ArgumentOutOfRangeException(name); }
public static void GreaterThan(Optional<int> obj, int value, string name) { if (obj.IsSpecified && obj.Value <= value) throw new ArgumentOutOfRangeException(name); }
public static void GreaterThan(Optional<uint> obj, uint value, string name) { if (obj.IsSpecified && obj.Value <= value) throw new ArgumentOutOfRangeException(name); }
public static void GreaterThan(Optional<long> obj, long value, string name) { if (obj.IsSpecified && obj.Value <= value) throw new ArgumentOutOfRangeException(name); }
public static void GreaterThan(Optional<ulong> obj, ulong value, string name) { if (obj.IsSpecified && obj.Value <= value) throw new ArgumentOutOfRangeException(name); }
public static void AtMost(sbyte obj, sbyte value, string name) { if (obj > value) throw new ArgumentOutOfRangeException(name); }
public static void AtMost(byte obj, byte value, string name) { if (obj > value) throw new ArgumentOutOfRangeException(name); }
public static void AtMost(short obj, short value, string name) { if (obj > value) throw new ArgumentOutOfRangeException(name); }
public static void AtMost(ushort obj, ushort value, string name) { if (obj > value) throw new ArgumentOutOfRangeException(name); }
public static void AtMost(int obj, int value, string name) { if (obj > value) throw new ArgumentOutOfRangeException(name); }
public static void AtMost(uint obj, uint value, string name) { if (obj > value) throw new ArgumentOutOfRangeException(name); }
public static void AtMost(long obj, long value, string name) { if (obj > value) throw new ArgumentOutOfRangeException(name); }
public static void AtMost(ulong obj, ulong value, string name) { if (obj > value) throw new ArgumentOutOfRangeException(name); }
public static void AtMost(Optional<sbyte> obj, sbyte value, string name) { if (obj.IsSpecified && obj.Value > value) throw new ArgumentOutOfRangeException(name); }
public static void AtMost(Optional<byte> obj, byte value, string name) { if (obj.IsSpecified && obj.Value > value) throw new ArgumentOutOfRangeException(name); }
public static void AtMost(Optional<short> obj, short value, string name) { if (obj.IsSpecified && obj.Value > value) throw new ArgumentOutOfRangeException(name); }
public static void AtMost(Optional<ushort> obj, ushort value, string name) { if (obj.IsSpecified && obj.Value > value) throw new ArgumentOutOfRangeException(name); }
public static void AtMost(Optional<int> obj, int value, string name) { if (obj.IsSpecified && obj.Value > value) throw new ArgumentOutOfRangeException(name); }
public static void AtMost(Optional<uint> obj, uint value, string name) { if (obj.IsSpecified && obj.Value > value) throw new ArgumentOutOfRangeException(name); }
public static void AtMost(Optional<long> obj, long value, string name) { if (obj.IsSpecified && obj.Value > value) throw new ArgumentOutOfRangeException(name); }
public static void AtMost(Optional<ulong> obj, ulong value, string name) { if (obj.IsSpecified && obj.Value > value) throw new ArgumentOutOfRangeException(name); }
public static void LessThan(sbyte obj, sbyte value, string name) { if (obj >= value) throw new ArgumentOutOfRangeException(name); }
public static void LessThan(byte obj, byte value, string name) { if (obj >= value) throw new ArgumentOutOfRangeException(name); }
public static void LessThan(short obj, short value, string name) { if (obj >= value) throw new ArgumentOutOfRangeException(name); }
public static void LessThan(ushort obj, ushort value, string name) { if (obj >= value) throw new ArgumentOutOfRangeException(name); }
public static void LessThan(int obj, int value, string name) { if (obj >= value) throw new ArgumentOutOfRangeException(name); }
public static void LessThan(uint obj, uint value, string name) { if (obj >= value) throw new ArgumentOutOfRangeException(name); }
public static void LessThan(long obj, long value, string name) { if (obj >= value) throw new ArgumentOutOfRangeException(name); }
public static void LessThan(ulong obj, ulong value, string name) { if (obj >= value) throw new ArgumentOutOfRangeException(name); }
public static void LessThan(Optional<sbyte> obj, sbyte value, string name) { if (obj.IsSpecified && obj.Value >= value) throw new ArgumentOutOfRangeException(name); }
public static void LessThan(Optional<byte> obj, byte value, string name) { if (obj.IsSpecified && obj.Value >= value) throw new ArgumentOutOfRangeException(name); }
public static void LessThan(Optional<short> obj, short value, string name) { if (obj.IsSpecified && obj.Value >= value) throw new ArgumentOutOfRangeException(name); }
public static void LessThan(Optional<ushort> obj, ushort value, string name) { if (obj.IsSpecified && obj.Value >= value) throw new ArgumentOutOfRangeException(name); }
public static void LessThan(Optional<int> obj, int value, string name) { if (obj.IsSpecified && obj.Value >= value) throw new ArgumentOutOfRangeException(name); }
public static void LessThan(Optional<uint> obj, uint value, string name) { if (obj.IsSpecified && obj.Value >= value) throw new ArgumentOutOfRangeException(name); }
public static void LessThan(Optional<long> obj, long value, string name) { if (obj.IsSpecified && obj.Value >= value) throw new ArgumentOutOfRangeException(name); }
public static void LessThan(Optional<ulong> obj, ulong value, string name) { if (obj.IsSpecified && obj.Value >= value) throw new ArgumentOutOfRangeException(name); }
public static void NotEqual(sbyte obj, sbyte value, string name, string msg = null) { if (obj == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(byte obj, byte value, string name, string msg = null) { if (obj == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(short obj, short value, string name, string msg = null) { if (obj == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(ushort obj, ushort value, string name, string msg = null) { if (obj == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(int obj, int value, string name, string msg = null) { if (obj == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(uint obj, uint value, string name, string msg = null) { if (obj == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(long obj, long value, string name, string msg = null) { if (obj == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(ulong obj, ulong value, string name, string msg = null) { if (obj == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(Optional<sbyte> obj, sbyte value, string name, string msg = null) { if (obj.IsSpecified && obj.Value == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(Optional<byte> obj, byte value, string name, string msg = null) { if (obj.IsSpecified && obj.Value == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(Optional<short> obj, short value, string name, string msg = null) { if (obj.IsSpecified && obj.Value == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(Optional<ushort> obj, ushort value, string name, string msg = null) { if (obj.IsSpecified && obj.Value == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(Optional<int> obj, int value, string name, string msg = null) { if (obj.IsSpecified && obj.Value == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(Optional<uint> obj, uint value, string name, string msg = null) { if (obj.IsSpecified && obj.Value == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(Optional<long> obj, long value, string name, string msg = null) { if (obj.IsSpecified && obj.Value == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(Optional<ulong> obj, ulong value, string name, string msg = null) { if (obj.IsSpecified && obj.Value == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(sbyte? obj, sbyte value, string name, string msg = null) { if (obj == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(byte? obj, byte value, string name, string msg = null) { if (obj == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(short? obj, short value, string name, string msg = null) { if (obj == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(ushort? obj, ushort value, string name, string msg = null) { if (obj == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(int? obj, int value, string name, string msg = null) { if (obj == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(uint? obj, uint value, string name, string msg = null) { if (obj == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(long? obj, long value, string name, string msg = null) { if (obj == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(ulong? obj, ulong value, string name, string msg = null) { if (obj == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(Optional<sbyte?> obj, sbyte value, string name, string msg = null) { if (obj.IsSpecified && obj.Value == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(Optional<byte?> obj, byte value, string name, string msg = null) { if (obj.IsSpecified && obj.Value == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(Optional<short?> obj, short value, string name, string msg = null) { if (obj.IsSpecified && obj.Value == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(Optional<ushort?> obj, ushort value, string name, string msg = null) { if (obj.IsSpecified && obj.Value == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(Optional<int?> obj, int value, string name, string msg = null) { if (obj.IsSpecified && obj.Value == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(Optional<uint?> obj, uint value, string name, string msg = null) { if (obj.IsSpecified && obj.Value == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(Optional<long?> obj, long value, string name, string msg = null) { if (obj.IsSpecified && obj.Value == value) throw CreateNotEqualException(name, msg, value); }
public static void NotEqual(Optional<ulong?> obj, ulong value, string name, string msg = null) { if (obj.IsSpecified && obj.Value == value) throw CreateNotEqualException(name, msg, value); }
private static ArgumentException CreateNotEqualException<T>(string name, string msg, T value)
{
if (msg == null) return new ArgumentException($"Value may not be equal to {value}", name);
else return new ArgumentException(msg, name);
}
public static void AtLeast(sbyte obj, sbyte value, string name, string msg = null) { if (obj < value) throw CreateAtLeastException(name, msg, value); }
public static void AtLeast(byte obj, byte value, string name, string msg = null) { if (obj < value) throw CreateAtLeastException(name, msg, value); }
public static void AtLeast(short obj, short value, string name, string msg = null) { if (obj < value) throw CreateAtLeastException(name, msg, value); }
public static void AtLeast(ushort obj, ushort value, string name, string msg = null) { if (obj < value) throw CreateAtLeastException(name, msg, value); }
public static void AtLeast(int obj, int value, string name, string msg = null) { if (obj < value) throw CreateAtLeastException(name, msg, value); }
public static void AtLeast(uint obj, uint value, string name, string msg = null) { if (obj < value) throw CreateAtLeastException(name, msg, value); }
public static void AtLeast(long obj, long value, string name, string msg = null) { if (obj < value) throw CreateAtLeastException(name, msg, value); }
public static void AtLeast(ulong obj, ulong value, string name, string msg = null) { if (obj < value) throw CreateAtLeastException(name, msg, value); }
public static void AtLeast(Optional<sbyte> obj, sbyte value, string name, string msg = null) { if (obj.IsSpecified && obj.Value < value) throw CreateAtLeastException(name, msg, value); }
public static void AtLeast(Optional<byte> obj, byte value, string name, string msg = null) { if (obj.IsSpecified && obj.Value < value) throw CreateAtLeastException(name, msg, value); }
public static void AtLeast(Optional<short> obj, short value, string name, string msg = null) { if (obj.IsSpecified && obj.Value < value) throw CreateAtLeastException(name, msg, value); }
public static void AtLeast(Optional<ushort> obj, ushort value, string name, string msg = null) { if (obj.IsSpecified && obj.Value < value) throw CreateAtLeastException(name, msg, value); }
public static void AtLeast(Optional<int> obj, int value, string name, string msg = null) { if (obj.IsSpecified && obj.Value < value) throw CreateAtLeastException(name, msg, value); }
public static void AtLeast(Optional<uint> obj, uint value, string name, string msg = null) { if (obj.IsSpecified && obj.Value < value) throw CreateAtLeastException(name, msg, value); }
public static void AtLeast(Optional<long> obj, long value, string name, string msg = null) { if (obj.IsSpecified && obj.Value < value) throw CreateAtLeastException(name, msg, value); }
public static void AtLeast(Optional<ulong> obj, ulong value, string name, string msg = null) { if (obj.IsSpecified && obj.Value < value) throw CreateAtLeastException(name, msg, value); }
private static ArgumentException CreateAtLeastException<T>(string name, string msg, T value)
{
if (msg == null) return new ArgumentException($"Value must be at least {value}", name);
else return new ArgumentException(msg, name);
}
public static void GreaterThan(sbyte obj, sbyte value, string name, string msg = null) { if (obj <= value) throw CreateGreaterThanException(name, msg, value); }
public static void GreaterThan(byte obj, byte value, string name, string msg = null) { if (obj <= value) throw CreateGreaterThanException(name, msg, value); }
public static void GreaterThan(short obj, short value, string name, string msg = null) { if (obj <= value) throw CreateGreaterThanException(name, msg, value); }
public static void GreaterThan(ushort obj, ushort value, string name, string msg = null) { if (obj <= value) throw CreateGreaterThanException(name, msg, value); }
public static void GreaterThan(int obj, int value, string name, string msg = null) { if (obj <= value) throw CreateGreaterThanException(name, msg, value); }
public static void GreaterThan(uint obj, uint value, string name, string msg = null) { if (obj <= value) throw CreateGreaterThanException(name, msg, value); }
public static void GreaterThan(long obj, long value, string name, string msg = null) { if (obj <= value) throw CreateGreaterThanException(name, msg, value); }
public static void GreaterThan(ulong obj, ulong value, string name, string msg = null) { if (obj <= value) throw CreateGreaterThanException(name, msg, value); }
public static void GreaterThan(Optional<sbyte> obj, sbyte value, string name, string msg = null) { if (obj.IsSpecified && obj.Value <= value) throw CreateGreaterThanException(name, msg, value); }
public static void GreaterThan(Optional<byte> obj, byte value, string name, string msg = null) { if (obj.IsSpecified && obj.Value <= value) throw CreateGreaterThanException(name, msg, value); }
public static void GreaterThan(Optional<short> obj, short value, string name, string msg = null) { if (obj.IsSpecified && obj.Value <= value) throw CreateGreaterThanException(name, msg, value); }
public static void GreaterThan(Optional<ushort> obj, ushort value, string name, string msg = null) { if (obj.IsSpecified && obj.Value <= value) throw CreateGreaterThanException(name, msg, value); }
public static void GreaterThan(Optional<int> obj, int value, string name, string msg = null) { if (obj.IsSpecified && obj.Value <= value) throw CreateGreaterThanException(name, msg, value); }
public static void GreaterThan(Optional<uint> obj, uint value, string name, string msg = null) { if (obj.IsSpecified && obj.Value <= value) throw CreateGreaterThanException(name, msg, value); }
public static void GreaterThan(Optional<long> obj, long value, string name, string msg = null) { if (obj.IsSpecified && obj.Value <= value) throw CreateGreaterThanException(name, msg, value); }
public static void GreaterThan(Optional<ulong> obj, ulong value, string name, string msg = null) { if (obj.IsSpecified && obj.Value <= value) throw CreateGreaterThanException(name, msg, value); }
private static ArgumentException CreateGreaterThanException<T>(string name, string msg, T value)
{
if (msg == null) return new ArgumentException($"Value must be greater than {value}", name);
else return new ArgumentException(msg, name);
}
public static void AtMost(sbyte obj, sbyte value, string name, string msg = null) { if (obj > value) throw CreateAtMostException(name, msg, value); }
public static void AtMost(byte obj, byte value, string name, string msg = null) { if (obj > value) throw CreateAtMostException(name, msg, value); }
public static void AtMost(short obj, short value, string name, string msg = null) { if (obj > value) throw CreateAtMostException(name, msg, value); }
public static void AtMost(ushort obj, ushort value, string name, string msg = null) { if (obj > value) throw CreateAtMostException(name, msg, value); }
public static void AtMost(int obj, int value, string name, string msg = null) { if (obj > value) throw CreateAtMostException(name, msg, value); }
public static void AtMost(uint obj, uint value, string name, string msg = null) { if (obj > value) throw CreateAtMostException(name, msg, value); }
public static void AtMost(long obj, long value, string name, string msg = null) { if (obj > value) throw CreateAtMostException(name, msg, value); }
public static void AtMost(ulong obj, ulong value, string name, string msg = null) { if (obj > value) throw CreateAtMostException(name, msg, value); }
public static void AtMost(Optional<sbyte> obj, sbyte value, string name, string msg = null) { if (obj.IsSpecified && obj.Value > value) throw CreateAtMostException(name, msg, value); }
public static void AtMost(Optional<byte> obj, byte value, string name, string msg = null) { if (obj.IsSpecified && obj.Value > value) throw CreateAtMostException(name, msg, value); }
public static void AtMost(Optional<short> obj, short value, string name, string msg = null) { if (obj.IsSpecified && obj.Value > value) throw CreateAtMostException(name, msg, value); }
public static void AtMost(Optional<ushort> obj, ushort value, string name, string msg = null) { if (obj.IsSpecified && obj.Value > value) throw CreateAtMostException(name, msg, value); }
public static void AtMost(Optional<int> obj, int value, string name, string msg = null) { if (obj.IsSpecified && obj.Value > value) throw CreateAtMostException(name, msg, value); }
public static void AtMost(Optional<uint> obj, uint value, string name, string msg = null) { if (obj.IsSpecified && obj.Value > value) throw CreateAtMostException(name, msg, value); }
public static void AtMost(Optional<long> obj, long value, string name, string msg = null) { if (obj.IsSpecified && obj.Value > value) throw CreateAtMostException(name, msg, value); }
public static void AtMost(Optional<ulong> obj, ulong value, string name, string msg = null) { if (obj.IsSpecified && obj.Value > value) throw CreateAtMostException(name, msg, value); }
private static ArgumentException CreateAtMostException<T>(string name, string msg, T value)
{
if (msg == null) return new ArgumentException($"Value must be at most {value}", name);
else return new ArgumentException(msg, name);
}
public static void LessThan(sbyte obj, sbyte value, string name, string msg = null) { if (obj >= value) throw CreateLessThanException(name, msg, value); }
public static void LessThan(byte obj, byte value, string name, string msg = null) { if (obj >= value) throw CreateLessThanException(name, msg, value); }
public static void LessThan(short obj, short value, string name, string msg = null) { if (obj >= value) throw CreateLessThanException(name, msg, value); }
public static void LessThan(ushort obj, ushort value, string name, string msg = null) { if (obj >= value) throw CreateLessThanException(name, msg, value); }
public static void LessThan(int obj, int value, string name, string msg = null) { if (obj >= value) throw CreateLessThanException(name, msg, value); }
public static void LessThan(uint obj, uint value, string name, string msg = null) { if (obj >= value) throw CreateLessThanException(name, msg, value); }
public static void LessThan(long obj, long value, string name, string msg = null) { if (obj >= value) throw CreateLessThanException(name, msg, value); }
public static void LessThan(ulong obj, ulong value, string name, string msg = null) { if (obj >= value) throw CreateLessThanException(name, msg, value); }
public static void LessThan(Optional<sbyte> obj, sbyte value, string name, string msg = null) { if (obj.IsSpecified && obj.Value >= value) throw CreateLessThanException(name, msg, value); }
public static void LessThan(Optional<byte> obj, byte value, string name, string msg = null) { if (obj.IsSpecified && obj.Value >= value) throw CreateLessThanException(name, msg, value); }
public static void LessThan(Optional<short> obj, short value, string name, string msg = null) { if (obj.IsSpecified && obj.Value >= value) throw CreateLessThanException(name, msg, value); }
public static void LessThan(Optional<ushort> obj, ushort value, string name, string msg = null) { if (obj.IsSpecified && obj.Value >= value) throw CreateLessThanException(name, msg, value); }
public static void LessThan(Optional<int> obj, int value, string name, string msg = null) { if (obj.IsSpecified && obj.Value >= value) throw CreateLessThanException(name, msg, value); }
public static void LessThan(Optional<uint> obj, uint value, string name, string msg = null) { if (obj.IsSpecified && obj.Value >= value) throw CreateLessThanException(name, msg, value); }
public static void LessThan(Optional<long> obj, long value, string name, string msg = null) { if (obj.IsSpecified && obj.Value >= value) throw CreateLessThanException(name, msg, value); }
public static void LessThan(Optional<ulong> obj, ulong value, string name, string msg = null) { if (obj.IsSpecified && obj.Value >= value) throw CreateLessThanException(name, msg, value); }
private static ArgumentException CreateLessThanException<T>(string name, string msg, T value)
{
if (msg == null) return new ArgumentException($"Value must be less than {value}", name);
else return new ArgumentException(msg, name);
}
}
}

View File

@@ -1,5 +1,5 @@
{
"version": "1.0.0-beta2-*",
{
"version": "1.0.0-*",
"description": "A .Net API wrapper and bot framework for Discord.",
"authors": [ "RogueException" ],
@@ -26,14 +26,14 @@
},
"dependencies": {
"Microsoft.Win32.Primitives": "4.0.1",
"Microsoft.Win32.Primitives": "4.3.0",
"Newtonsoft.Json": "9.0.1",
"System.Collections.Concurrent": "4.0.12",
"System.Collections.Immutable": "1.2.0",
"System.Interactive.Async": "3.0.0",
"System.Net.Http": "4.1.0",
"System.Collections.Concurrent": "4.3.0",
"System.Collections.Immutable": "1.3.0",
"System.Interactive.Async": "3.1.0",
"System.Net.Http": "4.3.0",
"System.Net.WebSockets.Client": {
"version": "4.0.0",
"version": "4.3.0",
"type": "build"
}
},