Browse Source

Merge branch 'dev' into docs/faq-n-patches-offline

pull/1161/head
Still Hsu 7 years ago
parent
commit
596b47e1b8
No known key found for this signature in database GPG Key ID: 8601A145FDA95209
65 changed files with 484 additions and 328 deletions
  1. +1
    -7
      Discord.Net.targets
  2. +1
    -1
      samples/02_commands_framework/02_commands_framework.csproj
  3. +1
    -1
      src/Discord.Net.Analyzers/Discord.Net.Analyzers.csproj
  4. +28
    -6
      src/Discord.Net.Commands/CommandParser.cs
  5. +7
    -2
      src/Discord.Net.Commands/CommandService.cs
  6. +6
    -3
      src/Discord.Net.Commands/CommandServiceConfig.cs
  7. +7
    -3
      src/Discord.Net.Commands/Discord.Net.Commands.csproj
  8. +3
    -2
      src/Discord.Net.Commands/Info/CommandInfo.cs
  9. +2
    -2
      src/Discord.Net.Commands/PrimitiveParsers.cs
  10. +35
    -0
      src/Discord.Net.Commands/Readers/TimeSpanTypeReader.cs
  11. +95
    -0
      src/Discord.Net.Commands/Utilities/QuotationAliasUtils.cs
  12. +5
    -5
      src/Discord.Net.Core/Discord.Net.Core.csproj
  13. +1
    -0
      src/Discord.Net.Core/DiscordConfig.cs
  14. +6
    -3
      src/Discord.Net.Core/Entities/Channels/IMessageChannel.cs
  15. +2
    -4
      src/Discord.Net.Core/Entities/Guilds/IGuild.cs
  16. +2
    -3
      src/Discord.Net.Core/Entities/Image.cs
  17. +1
    -1
      src/Discord.Net.Core/Entities/Messages/IUserMessage.cs
  18. +3
    -7
      src/Discord.Net.Core/Entities/Permissions/GuildPermission.cs
  19. +13
    -9
      src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs
  20. +10
    -0
      src/Discord.Net.Core/Entities/Roles/Color.cs
  21. +2
    -3
      src/Discord.Net.Core/Extensions/UserExtensions.cs
  22. +9
    -12
      src/Discord.Net.Core/Logging/LogManager.cs
  23. +12
    -13
      src/Discord.Net.Core/Logging/Logger.cs
  24. +2
    -45
      src/Discord.Net.Core/Utils/DateTimeUtils.cs
  25. +2
    -2
      src/Discord.Net.Core/Utils/SnowflakeUtils.cs
  26. +12
    -1
      src/Discord.Net.Rest/API/Rest/CreateGuildChannelParams.cs
  27. +1
    -1
      src/Discord.Net.Rest/API/Rest/GetReactionUsersParams.cs
  28. +6
    -7
      src/Discord.Net.Rest/Discord.Net.Rest.csproj
  29. +2
    -2
      src/Discord.Net.Rest/DiscordRestApiClient.cs
  30. +5
    -2
      src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs
  31. +1
    -3
      src/Discord.Net.Rest/Entities/Channels/IRestMessageChannel.cs
  32. +8
    -7
      src/Discord.Net.Rest/Entities/Channels/RestDMChannel.cs
  33. +8
    -5
      src/Discord.Net.Rest/Entities/Channels/RestGroupChannel.cs
  34. +9
    -5
      src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs
  35. +11
    -8
      src/Discord.Net.Rest/Entities/Channels/RpcVirtualMessageChannel.cs
  36. +20
    -4
      src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs
  37. +8
    -8
      src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs
  38. +35
    -8
      src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs
  39. +3
    -3
      src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs
  40. +1
    -2
      src/Discord.Net.Rest/Net/Converters/DiscordContractResolver.cs
  41. +1
    -1
      src/Discord.Net.Rest/Net/Queue/RequestQueueBucket.cs
  42. +1
    -1
      src/Discord.Net.Rest/Net/RateLimitInfo.cs
  43. +4
    -4
      src/Discord.Net.WebSocket/Discord.Net.WebSocket.csproj
  44. +1
    -1
      src/Discord.Net.WebSocket/DiscordSocketClient.cs
  45. +2
    -2
      src/Discord.Net.WebSocket/DiscordVoiceApiClient.cs
  46. +1
    -3
      src/Discord.Net.WebSocket/Entities/Channels/ISocketMessageChannel.cs
  47. +7
    -7
      src/Discord.Net.WebSocket/Entities/Channels/SocketDMChannel.cs
  48. +8
    -5
      src/Discord.Net.WebSocket/Entities/Channels/SocketGroupChannel.cs
  49. +8
    -5
      src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs
  50. +8
    -10
      src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs
  51. +2
    -2
      src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs
  52. +0
    -6
      src/Discord.Net.WebSocket/Net/DefaultUdpSocket.cs
  53. +1
    -9
      src/Discord.Net.WebSocket/Net/DefaultUdpSocketProvider.cs
  54. +3
    -10
      src/Discord.Net.WebSocket/Net/DefaultWebSocketClient.cs
  55. +0
    -8
      src/Discord.Net.WebSocket/Net/DefaultWebSocketClientProvider.cs
  56. +2
    -2
      src/Discord.Net.Webhook/Discord.Net.Webhook.csproj
  57. +1
    -4
      src/Discord.Net.Webhook/DiscordWebhookClient.cs
  58. +0
    -2
      src/Discord.Net.Webhook/WebhookClientHelper.cs
  59. +5
    -5
      test/Discord.Net.Tests/Discord.Net.Tests.csproj
  60. +1
    -1
      test/Discord.Net.Tests/Tests.ChannelPermissions.cs
  61. +26
    -26
      test/Discord.Net.Tests/Tests.Channels.cs
  62. +2
    -1
      test/Discord.Net.Tests/Tests.Colors.cs
  63. +2
    -1
      test/Discord.Net.Tests/Tests.Emotes.cs
  64. +5
    -5
      test/Discord.Net.Tests/Tests.GuildPermissions.cs
  65. +7
    -7
      test/Discord.Net.Tests/Tests.Permissions.cs

+ 1
- 7
Discord.Net.targets View File

@@ -16,13 +16,7 @@
<PropertyGroup Condition=" '$(BuildNumber)' != '' And $(IsTagBuild) != 'true' ">
<VersionSuffix Condition=" '$(VersionSuffix)' != '' ">$(VersionSuffix)-$(BuildNumber)</VersionSuffix>
<VersionSuffix Condition=" '$(VersionSuffix)' == '' ">build-$(BuildNumber)</VersionSuffix>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' Or '$(TargetFramework)' == 'net45' ">
<DefineConstants>$(DefineConstants);FILESYSTEM;DEFAULTUDPCLIENT;DEFAULTWEBSOCKET</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
<DefineConstants>$(DefineConstants);FORMATSTR;UNIXTIME;MSTRYBUFFER;UDPDISPOSE</DefineConstants>
</PropertyGroup>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<NoWarn>$(NoWarn);CS1573;CS1591</NoWarn>
<WarningsAsErrors>true</WarningsAsErrors>


+ 1
- 1
samples/02_commands_framework/02_commands_framework.csproj View File

@@ -6,7 +6,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.1.0-preview1-final" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.0.0" />
</ItemGroup>

<ItemGroup>


+ 1
- 1
src/Discord.Net.Analyzers/Discord.Net.Analyzers.csproj View File

@@ -7,7 +7,7 @@
<TargetFramework>netstandard1.3</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis" Version="2.6.0" />
<PackageReference Include="Microsoft.CodeAnalysis" Version="2.8.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Discord.Net.Commands\Discord.Net.Commands.csproj" />


+ 28
- 6
src/Discord.Net.Commands/CommandParser.cs View File

@@ -1,4 +1,5 @@
using System;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Text;
using System.Threading.Tasks;
@@ -13,8 +14,7 @@ namespace Discord.Commands
Parameter,
QuotedParameter
}
public static async Task<ParseResult> ParseArgsAsync(CommandInfo command, ICommandContext context, IServiceProvider services, string input, int startPos)
public static async Task<ParseResult> ParseArgsAsync(CommandInfo command, ICommandContext context, bool ignoreExtraArgs, IServiceProvider services, string input, int startPos, IReadOnlyDictionary<char, char> aliasMap)
{
ParameterInfo curParam = null;
StringBuilder argBuilder = new StringBuilder(input.Length);
@@ -24,7 +24,27 @@ namespace Discord.Commands
var argList = ImmutableArray.CreateBuilder<TypeReaderResult>();
var paramList = ImmutableArray.CreateBuilder<TypeReaderResult>();
bool isEscaping = false;
char c;
char c, matchQuote = '\0';

// local helper functions
bool IsOpenQuote(IReadOnlyDictionary<char, char> dict, char ch)
{
// return if the key is contained in the dictionary if it is populated
if (dict.Count != 0)
return dict.ContainsKey(ch);
// or otherwise if it is the default double quote
return c == '\"';
}

char GetMatch(IReadOnlyDictionary<char, char> dict, char ch)
{
// get the corresponding value for the key, if it exists
// and if the dictionary is populated
if (dict.Count != 0 && dict.TryGetValue(c, out var value))
return value;
// or get the default pair of the default double quote
return '\"';
}

for (int curPos = startPos; curPos <= endPos; curPos++)
{
@@ -74,9 +94,11 @@ namespace Discord.Commands
argBuilder.Append(c);
continue;
}
if (c == '\"')
if (IsOpenQuote(aliasMap, c))
{
curPart = ParserPart.QuotedParameter;
matchQuote = GetMatch(aliasMap, c);
continue;
}
curPart = ParserPart.Parameter;
@@ -97,7 +119,7 @@ namespace Discord.Commands
}
else if (curPart == ParserPart.QuotedParameter)
{
if (c == '\"')
if (c == matchQuote)
{
argString = argBuilder.ToString(); //Remove quotes
lastArgEndPos = curPos + 1;


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

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
@@ -38,6 +38,7 @@ namespace Discord.Commands
internal readonly RunMode _defaultRunMode;
internal readonly Logger _cmdLogger;
internal readonly LogManager _logManager;
internal readonly IReadOnlyDictionary<char, char> _quotationMarkAliasMap;

/// <summary>
/// Represents all modules loaded within <see cref="CommandService" />.
@@ -73,6 +74,7 @@ namespace Discord.Commands
_ignoreExtraArgs = config.IgnoreExtraArgs;
_separatorChar = config.SeparatorChar;
_defaultRunMode = config.DefaultRunMode;
_quotationMarkAliasMap = (config.QuotationMarkAliasMap ?? new Dictionary<char, char>()).ToImmutableDictionary();
if (_defaultRunMode == RunMode.Default)
throw new InvalidOperationException("The default run mode cannot be set to Default.");

@@ -93,6 +95,10 @@ namespace Discord.Commands
_defaultTypeReaders[typeof(Nullable<>).MakeGenericType(type)] = NullableTypeReader.Create(type, _defaultTypeReaders[type]);
}

var tsreader = new TimeSpanTypeReader();
_defaultTypeReaders[typeof(TimeSpan)] = tsreader;
_defaultTypeReaders[typeof(TimeSpan?)] = NullableTypeReader.Create(typeof(TimeSpan), tsreader);

_defaultTypeReaders[typeof(string)] =
new PrimitiveTypeReader<string>((string x, out string y) => { y = x; return true; }, 0);

@@ -447,7 +453,6 @@ namespace Discord.Commands
public async Task<IResult> ExecuteAsync(ICommandContext context, string input, IServiceProvider services, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
{
services = services ?? EmptyServiceProvider.Instance;

var searchResult = Search(context, input);
if (!searchResult.IsSuccess)
return searchResult;


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

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

namespace Discord.Commands
{
@@ -33,9 +34,11 @@ namespace Discord.Commands
/// </summary>
public bool ThrowOnError { get; set; } = true;

/// <summary>
/// Gets or sets whether extra parameters should be ignored.
/// </summary>
/// <summary> Collection of aliases that can wrap strings for command parsing.
/// represents the opening quotation mark and the value is the corresponding closing mark.</summary>
public Dictionary<char, char> QuotationMarkAliasMap { get; set; } = QuotationAliasUtils.GetDefaultAliasMap;

/// <summary> Determines whether extra parameters should be ignored. </summary>
public bool IgnoreExtraArgs { get; set; } = false;
}
}

+ 7
- 3
src/Discord.Net.Commands/Discord.Net.Commands.csproj View File

@@ -1,15 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="../../Discord.Net.targets" />
<PropertyGroup>
<AssemblyName>Discord.Net.Commands</AssemblyName>
<RootNamespace>Discord.Commands</RootNamespace>
<Description>A Discord.Net extension adding support for bot commands.</Description>
<TargetFrameworks>netstandard1.1;netstandard1.3</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net46;netstandard1.3;netstandard2.0</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netstandard1.3;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Discord.Net.Core\Discord.Net.Core.csproj" />
</ItemGroup>
<ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.0.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' != 'netstandard2.0' ">
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="1.1.1" />
</ItemGroup>
</Project>

+ 3
- 2
src/Discord.Net.Commands/Info/CommandInfo.cs View File

@@ -1,4 +1,4 @@
using Discord.Commands.Builders;
using Discord.Commands.Builders;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
@@ -172,7 +172,8 @@ namespace Discord.Commands
return ParseResult.FromError(preconditionResult);

string input = searchResult.Text.Substring(startIndex);
return await CommandParser.ParseArgsAsync(this, context, services, input, 0).ConfigureAwait(false);

return await CommandParser.ParseArgsAsync(this, context, _commandService._ignoreExtraArgs, services, input, 0, _commandService._quotationMarkAliasMap).ConfigureAwait(false);
}
public Task<IResult> ExecuteAsync(ICommandContext context, ParseResult parseResult, IServiceProvider services)


+ 2
- 2
src/Discord.Net.Commands/PrimitiveParsers.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;

@@ -29,7 +29,7 @@ namespace Discord.Commands
parserBuilder[typeof(decimal)] = (TryParseDelegate<decimal>)decimal.TryParse;
parserBuilder[typeof(DateTime)] = (TryParseDelegate<DateTime>)DateTime.TryParse;
parserBuilder[typeof(DateTimeOffset)] = (TryParseDelegate<DateTimeOffset>)DateTimeOffset.TryParse;
parserBuilder[typeof(TimeSpan)] = (TryParseDelegate<TimeSpan>)TimeSpan.TryParse;
//parserBuilder[typeof(TimeSpan)] = (TryParseDelegate<TimeSpan>)TimeSpan.TryParse;
parserBuilder[typeof(char)] = (TryParseDelegate<char>)char.TryParse;
return parserBuilder.ToImmutable();
}


+ 35
- 0
src/Discord.Net.Commands/Readers/TimeSpanTypeReader.cs View File

@@ -0,0 +1,35 @@
using System;
using System.Globalization;
using System.Threading.Tasks;

namespace Discord.Commands
{
internal class TimeSpanTypeReader : TypeReader
{
private static readonly string[] _formats = new[]
{
"%d'd'%h'h'%m'm'%s's'", //4d3h2m1s
"%d'd'%h'h'%m'm'", //4d3h2m
"%d'd'%h'h'%s's'", //4d3h 1s
"%d'd'%h'h'", //4d3h
"%d'd'%m'm'%s's'", //4d 2m1s
"%d'd'%m'm'", //4d 2m
"%d'd'%s's'", //4d 1s
"%d'd'", //4d
"%h'h'%m'm'%s's'", // 3h2m1s
"%h'h'%m'm'", // 3h2m
"%h'h'%s's'", // 3h 1s
"%h'h'", // 3h
"%m'm'%s's'", // 2m1s
"%m'm'", // 2m
"%s's'", // 1s
};

public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services)
{
return (TimeSpan.TryParseExact(input.ToLowerInvariant(), _formats, CultureInfo.InvariantCulture, out var timeSpan))
? Task.FromResult(TypeReaderResult.FromSuccess(timeSpan))
: Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse TimeSpan"));
}
}
}

+ 95
- 0
src/Discord.Net.Commands/Utilities/QuotationAliasUtils.cs View File

@@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Globalization;

namespace Discord.Commands
{
/// <summary>
/// Utility methods for generating matching pairs of unicode quotation marks for CommandServiceConfig
/// </summary>
internal static class QuotationAliasUtils
{
/// <summary>
/// Generates an IEnumerable of characters representing open-close pairs of
/// quotation punctuation.
/// </summary>
internal static Dictionary<char, char> GetDefaultAliasMap
{
get
{
// Output of a gist provided by https://gist.github.com/ufcpp
// https://gist.github.com/ufcpp/5b2cf9a9bf7d0b8743714a0b88f7edc5
// This was not used for the implementation because of incompatibility with netstandard1.1
return new Dictionary<char, char> {
{'\"', '\"' },
{'«', '»' },
{'‘', '’' },
{'“', '”' },
{'„', '‟' },
{'‹', '›' },
{'‚', '‛' },
{'《', '》' },
{'〈', '〉' },
{'「', '」' },
{'『', '』' },
{'〝', '〞' },
{'﹁', '﹂' },
{'﹃', '﹄' },
{'"', '"' },
{''', ''' },
{'「', '」' },
{'(', ')' },
{'༺', '༻' },
{'༼', '༽' },
{'᚛', '᚜' },
{'⁅', '⁆' },
{'⌈', '⌉' },
{'⌊', '⌋' },
{'❨', '❩' },
{'❪', '❫' },
{'❬', '❭' },
{'❮', '❯' },
{'❰', '❱' },
{'❲', '❳' },
{'❴', '❵' },
{'⟅', '⟆' },
{'⟦', '⟧' },
{'⟨', '⟩' },
{'⟪', '⟫' },
{'⟬', '⟭' },
{'⟮', '⟯' },
{'⦃', '⦄' },
{'⦅', '⦆' },
{'⦇', '⦈' },
{'⦉', '⦊' },
{'⦋', '⦌' },
{'⦍', '⦎' },
{'⦏', '⦐' },
{'⦑', '⦒' },
{'⦓', '⦔' },
{'⦕', '⦖' },
{'⦗', '⦘' },
{'⧘', '⧙' },
{'⧚', '⧛' },
{'⧼', '⧽' },
{'⸂', '⸃' },
{'⸄', '⸅' },
{'⸉', '⸊' },
{'⸌', '⸍' },
{'⸜', '⸝' },
{'⸠', '⸡' },
{'⸢', '⸣' },
{'⸤', '⸥' },
{'⸦', '⸧' },
{'⸨', '⸩' },
{'【', '】'},
{'〔', '〕' },
{'〖', '〗' },
{'〘', '〙' },
{'〚', '〛' }
};
}
}
}
}

+ 5
- 5
src/Discord.Net.Core/Discord.Net.Core.csproj View File

@@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="../../Discord.Net.targets" />
<PropertyGroup>
<AssemblyName>Discord.Net.Core</AssemblyName>
<RootNamespace>Discord</RootNamespace>
<Description>The core components for the Discord.Net library.</Description>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net45;netstandard1.1;netstandard1.3</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netstandard1.1;netstandard1.3</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net46;netstandard1.3;netstandard2.0</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netstandard1.3;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
<PackageReference Include="System.Collections.Immutable" Version="1.3.1" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="System.Collections.Immutable" Version="1.4.0" />
<PackageReference Include="System.Interactive.Async" Version="3.1.1" />
</ItemGroup>
</Project>

+ 1
- 0
src/Discord.Net.Core/DiscordConfig.cs View File

@@ -93,6 +93,7 @@ namespace Discord
/// The maximum number of guilds that can be gotten per-batch.
/// </returns>
public const int MaxGuildsPerBatch = 100;
public const int MaxUserReactionsPerBatch = 100;
public const int MaxAuditLogEntriesPerBatch = 100;

/// <summary>


+ 6
- 3
src/Discord.Net.Core/Entities/Channels/IMessageChannel.cs View File

@@ -20,8 +20,7 @@ namespace Discord
/// <returns>
/// An awaitable Task containing the message sent to the channel.
/// </returns>
Task<IUserMessage> SendMessageAsync(string text, bool isTTS = false, Embed embed = null, RequestOptions options = null);
#if FILESYSTEM
Task<IUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null);
/// <summary>
/// Sends a file to this message channel with an optional caption.
/// </summary>
@@ -39,7 +38,6 @@ namespace Discord
/// An awaitable Task containing the message sent to the channel.
/// </returns>
Task<IUserMessage> SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null);
#endif
/// <summary>
/// Sends a file to this message channel with an optional caption.
/// </summary>
@@ -121,6 +119,11 @@ namespace Discord
/// </returns>
Task<IReadOnlyCollection<IMessage>> GetPinnedMessagesAsync(RequestOptions options = null);

/// <summary> Deletes a message based on the message ID in this channel. </summary>
Task DeleteMessageAsync(ulong messageId, RequestOptions options = null);
/// <summary> Deletes a message based on the provided message in this channel. </summary>
Task DeleteMessageAsync(IMessage message, RequestOptions options = null);

/// <summary>
/// Broadcasts the "user is typing" message to all users in this channel, lasting 10 seconds.
/// </summary>


+ 2
- 4
src/Discord.Net.Core/Entities/Guilds/IGuild.cs View File

@@ -414,7 +414,7 @@ namespace Discord
/// <returns>
/// An awaitable <see cref="Task"/> containing the newly created text channel.
/// </returns>
Task<ITextChannel> CreateTextChannelAsync(string name, RequestOptions options = null);
Task<ITextChannel> CreateTextChannelAsync(string name, Action<TextChannelProperties> func = null, RequestOptions options = null);
/// <summary>
/// Creates a new voice channel.
/// </summary>
@@ -423,13 +423,11 @@ namespace Discord
/// <returns>
/// An awaitable <see cref="Task"/> containing the newly created voice channel.
/// </returns>
Task<IVoiceChannel> CreateVoiceChannelAsync(string name, RequestOptions options = null);
Task<IVoiceChannel> CreateVoiceChannelAsync(string name, Action<VoiceChannelProperties> func = null, RequestOptions options = null);
/// <summary>
/// Creates a new channel category.
/// </summary>
/// <param name="name">The new name for the category.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// An awaitable <see cref="Task"/> containing the newly created category channel.
/// </returns>
Task<ICategoryChannel> CreateCategoryAsync(string name, RequestOptions options = null);


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

@@ -1,4 +1,3 @@
using System;
using System.IO;
namespace Discord
{
@@ -22,7 +21,7 @@ namespace Discord
{
Stream = stream;
}
#if FILESYSTEM
/// <summary>
/// Create the image from a file path.
/// </summary>
@@ -55,6 +54,6 @@ namespace Discord
{
Stream = File.OpenRead(path);
}
#endif
}
}

+ 1
- 1
src/Discord.Net.Core/Entities/Messages/IUserMessage.cs View File

@@ -42,7 +42,7 @@ namespace Discord
/// <summary>
/// Gets all users that reacted to a message with a given emote.
/// </summary>
Task<IReadOnlyCollection<IUser>> GetReactionUsersAsync(IEmote emoji, int limit = 100, ulong? afterUserId = null, RequestOptions options = null);
IAsyncEnumerable<IReadOnlyCollection<IUser>> GetReactionUsersAsync(IEmote emoji, int limit, RequestOptions options = null);

/// <summary>
/// Transforms this message's text into a human-readable form by resolving its tags.


+ 3
- 7
src/Discord.Net.Core/Entities/Permissions/GuildPermission.cs View File

@@ -41,13 +41,9 @@ namespace Discord
/// Allows for viewing of audit logs.
/// </summary>
ViewAuditLog = 0x00_00_00_80,
/// <summary>
/// Allows for reading of message.
/// </summary>
ReadMessages = 0x00_00_04_00,
/// <summary>
/// Allows for sending messages in a channel.
/// </summary>
[Obsolete("Use ViewChannel instead.")]
ReadMessages = ViewChannel,
ViewChannel = 0x00_00_04_00,
SendMessages = 0x00_00_08_00,
/// <summary>
/// Allows for sending of text-to-speech messages.


+ 13
- 9
src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;

@@ -34,9 +35,12 @@ namespace Discord
/// <summary> If <c>true</c>, a user may view the audit log. </summary>
public bool ViewAuditLog => Permissions.GetValue(RawValue, GuildPermission.ViewAuditLog);

/// <summary> If <c>true</c>, a user may join channels. </summary>
public bool ReadMessages => Permissions.GetValue(RawValue, GuildPermission.ReadMessages);
/// <summary> If <c>true</c>, a user may send messages. </summary>
/// <summary> If True, a user may join channels. </summary>
[Obsolete("Use ViewChannel instead.")]
public bool ReadMessages => ViewChannel;
/// <summary> If True, a user may view channels. </summary>
public bool ViewChannel => Permissions.GetValue(RawValue, GuildPermission.ViewChannel);
/// <summary> If True, a user may send messages. </summary>
public bool SendMessages => Permissions.GetValue(RawValue, GuildPermission.SendMessages);
/// <summary> If <c>true</c>, a user may send text-to-speech messages. </summary>
public bool SendTTSMessages => Permissions.GetValue(RawValue, GuildPermission.SendTTSMessages);
@@ -83,7 +87,7 @@ namespace Discord
private GuildPermissions(ulong initialValue, bool? createInstantInvite = null, bool? kickMembers = null,
bool? banMembers = null, bool? administrator = null, bool? manageChannels = null, bool? manageGuild = null,
bool? addReactions = null, bool? viewAuditLog = null,
bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, bool? manageMessages = null,
bool? viewChannel = null, bool? sendMessages = null, bool? sendTTSMessages = null, bool? manageMessages = null,
bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, bool? mentionEveryone = null,
bool? useExternalEmojis = null, bool? connect = null, bool? speak = null, bool? muteMembers = null, bool? deafenMembers = null,
bool? moveMembers = null, bool? useVoiceActivation = null, bool? changeNickname = null, bool? manageNicknames = null,
@@ -99,7 +103,7 @@ namespace Discord
Permissions.SetValue(ref value, manageGuild, GuildPermission.ManageGuild);
Permissions.SetValue(ref value, addReactions, GuildPermission.AddReactions);
Permissions.SetValue(ref value, viewAuditLog, GuildPermission.ViewAuditLog);
Permissions.SetValue(ref value, readMessages, GuildPermission.ReadMessages);
Permissions.SetValue(ref value, viewChannel, GuildPermission.ViewChannel);
Permissions.SetValue(ref value, sendMessages, GuildPermission.SendMessages);
Permissions.SetValue(ref value, sendTTSMessages, GuildPermission.SendTTSMessages);
Permissions.SetValue(ref value, manageMessages, GuildPermission.ManageMessages);
@@ -127,14 +131,14 @@ namespace Discord
public GuildPermissions(bool createInstantInvite = false, bool kickMembers = false,
bool banMembers = false, bool administrator = false, bool manageChannels = false, bool manageGuild = false,
bool addReactions = false, bool viewAuditLog = false,
bool readMessages = false, bool sendMessages = false, bool sendTTSMessages = false, bool manageMessages = false,
bool viewChannel = false, bool sendMessages = false, bool sendTTSMessages = false, bool manageMessages = false,
bool embedLinks = false, bool attachFiles = false, bool readMessageHistory = false, bool mentionEveryone = false,
bool useExternalEmojis = false, bool connect = false, bool speak = false, bool muteMembers = false, bool deafenMembers = false,
bool moveMembers = false, bool useVoiceActivation = false, bool? changeNickname = false, bool? manageNicknames = false,
bool manageRoles = false, bool manageWebhooks = false, bool manageEmojis = false)
: this(0, createInstantInvite: createInstantInvite, manageRoles: manageRoles, kickMembers: kickMembers, banMembers: banMembers,
administrator: administrator, manageChannels: manageChannels, manageGuild: manageGuild, addReactions: addReactions,
viewAuditLog: viewAuditLog, readMessages: readMessages, sendMessages: sendMessages, sendTTSMessages: sendTTSMessages,
viewAuditLog: viewAuditLog, viewChannel: viewChannel, sendMessages: sendMessages, sendTTSMessages: sendTTSMessages,
manageMessages: manageMessages, embedLinks: embedLinks, attachFiles: attachFiles, readMessageHistory: readMessageHistory,
mentionEveryone: mentionEveryone, useExternalEmojis: useExternalEmojis, connect: connect, speak: speak, muteMembers: muteMembers,
deafenMembers: deafenMembers, moveMembers: moveMembers, useVoiceActivation: useVoiceActivation, changeNickname: changeNickname,
@@ -145,13 +149,13 @@ namespace Discord
public GuildPermissions Modify(bool? createInstantInvite = null, bool? kickMembers = null,
bool? banMembers = null, bool? administrator = null, bool? manageChannels = null, bool? manageGuild = null,
bool? addReactions = null, bool? viewAuditLog = null,
bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, bool? manageMessages = null,
bool? viewChannel = null, bool? sendMessages = null, bool? sendTTSMessages = null, bool? manageMessages = null,
bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, bool? mentionEveryone = null,
bool? useExternalEmojis = null, bool? connect = null, bool? speak = null, bool? muteMembers = null, bool? deafenMembers = null,
bool? moveMembers = null, bool? useVoiceActivation = null, bool? changeNickname = null, bool? manageNicknames = null,
bool? manageRoles = null, bool? manageWebhooks = null, bool? manageEmojis = null)
=> new GuildPermissions(RawValue, createInstantInvite, kickMembers, banMembers, administrator, manageChannels, manageGuild, addReactions,
viewAuditLog, readMessages, sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles,
viewAuditLog, viewChannel, sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles,
readMessageHistory, mentionEveryone, useExternalEmojis, connect, speak, muteMembers, deafenMembers, moveMembers,
useVoiceActivation, changeNickname, manageNicknames, manageRoles, manageWebhooks, manageEmojis);



+ 10
- 0
src/Discord.Net.Core/Entities/Roles/Color.cs View File

@@ -1,5 +1,8 @@
using System;
using System.Diagnostics;
#if NETSTANDARD2_0 || NET45
using StandardColor = System.Drawing.Color;
#endif

namespace Discord
{
@@ -125,6 +128,13 @@ namespace Discord
(uint)(b * 255.0f);
}

#if NETSTANDARD2_0 || NET45
public static implicit operator StandardColor(Color color) =>
StandardColor.FromArgb((int)color.RawValue);
public static explicit operator Color(StandardColor color) =>
new Color((uint)color.ToArgb() << 8 >> 8);
#endif

/// <summary>
/// Gets the hexadecimal representation of the color (e.g. <c>#000ccc</c>).
/// </summary>


+ 2
- 3
src/Discord.Net.Core/Extensions/UserExtensions.cs View File

@@ -18,7 +18,7 @@ namespace Discord
/// An awaitable Task containing the message sent to the channel.
/// </returns>
public static async Task<IUserMessage> SendMessageAsync(this IUser user,
string text,
string text = null,
bool isTTS = false,
Embed embed = null,
RequestOptions options = null)
@@ -55,7 +55,6 @@ namespace Discord
return await (await user.GetOrCreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(stream, filename, text, isTTS, embed, options).ConfigureAwait(false);
}

#if FILESYSTEM
/// <summary>
/// Sends a file via DM with an optional caption.
/// </summary>
@@ -81,7 +80,7 @@ namespace Discord
{
return await (await user.GetOrCreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(filePath, text, isTTS, embed, options).ConfigureAwait(false);
}
#endif
/// <summary>
/// Bans the provided user from the guild and optionally prunes their recent messages.
/// </summary>


+ 9
- 12
src/Discord.Net.Core/Logging/LogManager.cs View File

@@ -41,7 +41,7 @@ namespace Discord.Logging
// ignored
}
}
#if FORMATSTR
public async Task LogAsync(LogSeverity severity, string source, FormattableString message, Exception ex = null)
{
try
@@ -51,52 +51,49 @@ namespace Discord.Logging
}
catch { }
}
#endif

public Task ErrorAsync(string source, Exception ex)
=> LogAsync(LogSeverity.Error, source, ex);
public Task ErrorAsync(string source, string message, Exception ex = null)
=> LogAsync(LogSeverity.Error, source, message, ex);
#if FORMATSTR
public Task ErrorAsync(string source, FormattableString message, Exception ex = null)
=> LogAsync(LogSeverity.Error, source, message, ex);
#endif

public Task WarningAsync(string source, Exception ex)
=> LogAsync(LogSeverity.Warning, source, ex);
public Task WarningAsync(string source, string message, Exception ex = null)
=> LogAsync(LogSeverity.Warning, source, message, ex);
#if FORMATSTR
public Task WarningAsync(string source, FormattableString message, Exception ex = null)
=> LogAsync(LogSeverity.Warning, source, message, ex);
#endif

public Task InfoAsync(string source, Exception ex)
=> LogAsync(LogSeverity.Info, source, ex);
public Task InfoAsync(string source, string message, Exception ex = null)
=> LogAsync(LogSeverity.Info, source, message, ex);
#if FORMATSTR
public Task InfoAsync(string source, FormattableString message, Exception ex = null)
=> LogAsync(LogSeverity.Info, source, message, ex);
#endif

public Task VerboseAsync(string source, Exception ex)
=> LogAsync(LogSeverity.Verbose, source, ex);
public Task VerboseAsync(string source, string message, Exception ex = null)
=> LogAsync(LogSeverity.Verbose, source, message, ex);
#if FORMATSTR
public Task VerboseAsync(string source, FormattableString message, Exception ex = null)
=> LogAsync(LogSeverity.Verbose, source, message, ex);
#endif

public Task DebugAsync(string source, Exception ex)
=> LogAsync(LogSeverity.Debug, source, ex);
public Task DebugAsync(string source, string message, Exception ex = null)
=> LogAsync(LogSeverity.Debug, source, message, ex);
#if FORMATSTR
public Task DebugAsync(string source, FormattableString message, Exception ex = null)
=> LogAsync(LogSeverity.Debug, source, message, ex);
#endif

public Logger CreateLogger(string name) => new Logger(this, name);



+ 12
- 13
src/Discord.Net.Core/Logging/Logger.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Threading.Tasks;

namespace Discord.Logging
@@ -20,54 +20,53 @@ namespace Discord.Logging
=> _manager.LogAsync(severity, Name, exception);
public Task LogAsync(LogSeverity severity, string message, Exception exception = null)
=> _manager.LogAsync(severity, Name, message, exception);
#if FORMATSTR
public Task LogAsync(LogSeverity severity, FormattableString message, Exception exception = null)
=> _manager.LogAsync(severity, Name, message, exception);
#endif

public Task ErrorAsync(Exception exception)
=> _manager.ErrorAsync(Name, exception);
public Task ErrorAsync(string message, Exception exception = null)
=> _manager.ErrorAsync(Name, message, exception);
#if FORMATSTR
public Task ErrorAsync(FormattableString message, Exception exception = null)
=> _manager.ErrorAsync(Name, message, exception);
#endif

public Task WarningAsync(Exception exception)
=> _manager.WarningAsync(Name, exception);
public Task WarningAsync(string message, Exception exception = null)
=> _manager.WarningAsync(Name, message, exception);
#if FORMATSTR
public Task WarningAsync(FormattableString message, Exception exception = null)
=> _manager.WarningAsync(Name, message, exception);
#endif

public Task InfoAsync(Exception exception)
=> _manager.InfoAsync(Name, exception);
public Task InfoAsync(string message, Exception exception = null)
=> _manager.InfoAsync(Name, message, exception);
#if FORMATSTR
public Task InfoAsync(FormattableString message, Exception exception = null)
=> _manager.InfoAsync(Name, message, exception);
#endif

public Task VerboseAsync(Exception exception)
=> _manager.VerboseAsync(Name, exception);
public Task VerboseAsync(string message, Exception exception = null)
=> _manager.VerboseAsync(Name, message, exception);
#if FORMATSTR
public Task VerboseAsync(FormattableString message, Exception exception = null)
=> _manager.VerboseAsync(Name, message, exception);
#endif

public Task DebugAsync(Exception exception)
=> _manager.DebugAsync(Name, exception);
public Task DebugAsync(string message, Exception exception = null)
=> _manager.DebugAsync(Name, message, exception);
#if FORMATSTR
public Task DebugAsync(FormattableString message, Exception exception = null)
=> _manager.DebugAsync(Name, message, exception);
#endif
}
}

+ 2
- 45
src/Discord.Net.Core/Utils/DateTimeUtils.cs View File

@@ -1,57 +1,14 @@
using System;
using System;

namespace Discord
{
//Source: https://github.com/dotnet/coreclr/blob/master/src/mscorlib/src/System/DateTimeOffset.cs
internal static class DateTimeUtils
{
#if !UNIXTIME
private const long UnixEpochTicks = 621_355_968_000_000_000;
private const long UnixEpochSeconds = 62_135_596_800;
private const long UnixEpochMilliseconds = 62_135_596_800_000;
#endif

public static DateTimeOffset FromTicks(long ticks)
=> new DateTimeOffset(ticks, TimeSpan.Zero);
public static DateTimeOffset? FromTicks(long? ticks)
=> ticks != null ? new DateTimeOffset(ticks.Value, TimeSpan.Zero) : (DateTimeOffset?)null;

public static DateTimeOffset FromUnixSeconds(long seconds)
{
#if UNIXTIME
return DateTimeOffset.FromUnixTimeSeconds(seconds);
#else
long ticks = seconds * TimeSpan.TicksPerSecond + UnixEpochTicks;
return new DateTimeOffset(ticks, TimeSpan.Zero);
#endif
}
public static DateTimeOffset FromUnixMilliseconds(long milliseconds)
{
#if UNIXTIME
return DateTimeOffset.FromUnixTimeMilliseconds(milliseconds);
#else
long ticks = milliseconds * TimeSpan.TicksPerMillisecond + UnixEpochTicks;
return new DateTimeOffset(ticks, TimeSpan.Zero);
#endif
}

public static long ToUnixSeconds(DateTimeOffset dto)
{
#if UNIXTIME
return dto.ToUnixTimeSeconds();
#else
long seconds = dto.UtcDateTime.Ticks / TimeSpan.TicksPerSecond;
return seconds - UnixEpochSeconds;
#endif
}
public static long ToUnixMilliseconds(DateTimeOffset dto)
{
#if UNIXTIME
return dto.ToUnixTimeMilliseconds();
#else
long milliseconds = dto.UtcDateTime.Ticks / TimeSpan.TicksPerMillisecond;
return milliseconds - UnixEpochMilliseconds;
#endif
}
}
}

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

@@ -5,8 +5,8 @@ namespace Discord
public static class SnowflakeUtils
{
public static DateTimeOffset FromSnowflake(ulong value)
=> DateTimeUtils.FromUnixMilliseconds((long)((value >> 22) + 1420070400000UL));
=> DateTimeOffset.FromUnixTimeMilliseconds((long)((value >> 22) + 1420070400000UL));
public static ulong ToSnowflake(DateTimeOffset value)
=> ((ulong)DateTimeUtils.ToUnixMilliseconds(value) - 1420070400000UL) << 22;
=> ((ulong)value.ToUnixTimeMilliseconds() - 1420070400000UL) << 22;
}
}

+ 12
- 1
src/Discord.Net.Rest/API/Rest/CreateGuildChannelParams.cs View File

@@ -1,4 +1,4 @@
#pragma warning disable CS1591
#pragma warning disable CS1591
using Newtonsoft.Json;

namespace Discord.API.Rest
@@ -10,9 +10,20 @@ namespace Discord.API.Rest
public string Name { get; }
[JsonProperty("type")]
public ChannelType Type { get; }
[JsonProperty("parent_id")]
public Optional<ulong?> CategoryId { get; set; }

//Text channels
[JsonProperty("topic")]
public Optional<string> Topic { get; set; }
[JsonProperty("nsfw")]
public Optional<bool> IsNsfw { get; set; }

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

public CreateGuildChannelParams(string name, ChannelType type)
{


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

@@ -1,4 +1,4 @@
namespace Discord.API.Rest
namespace Discord.API.Rest
{
internal class GetReactionUsersParams
{


+ 6
- 7
src/Discord.Net.Rest/Discord.Net.Rest.csproj View File

@@ -1,20 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="../../Discord.Net.targets" />
<PropertyGroup>
<AssemblyName>Discord.Net.Rest</AssemblyName>
<RootNamespace>Discord.Rest</RootNamespace>
<Description>A core Discord.Net library containing the REST client and models.</Description>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net45;netstandard1.1;netstandard1.3</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netstandard1.1;netstandard1.3</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net46;netstandard1.3;netstandard2.0</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netstandard1.3;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Discord.Net.Core\Discord.Net.Core.csproj" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' != 'net45' ">
<PackageReference Include="System.Net.Http" Version="4.3.2" />
<!-- https://github.com/dotnet/corefx/issues/19535 -->
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
<PackageReference Include="System.Net.Http" Version="4.3.3" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
<ItemGroup Condition=" '$(TargetFramework)' == 'net46' ">
<Reference Include="System.Net.Http" />
</ItemGroup>
</Project>

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

@@ -630,11 +630,11 @@ namespace Discord.API
Preconditions.NotNullOrWhitespace(emoji, nameof(emoji));
Preconditions.NotNull(args, nameof(args));
Preconditions.GreaterThan(args.Limit, 0, nameof(args.Limit));
Preconditions.AtMost(args.Limit, DiscordConfig.MaxUsersPerBatch, nameof(args.Limit));
Preconditions.AtMost(args.Limit, DiscordConfig.MaxUserReactionsPerBatch, nameof(args.Limit));
Preconditions.GreaterThan(args.AfterUserId, 0, nameof(args.AfterUserId));
options = RequestOptions.CreateOrClone(options);

int limit = args.Limit.GetValueOrDefault(int.MaxValue);
int limit = args.Limit.GetValueOrDefault(DiscordConfig.MaxUserReactionsPerBatch);
ulong afterUserId = args.AfterUserId.GetValueOrDefault(0);

var ids = new BucketIds(channelId: channelId);


+ 5
- 2
src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs View File

@@ -162,7 +162,6 @@ namespace Discord.Rest
return RestUserMessage.Create(client, channel, client.CurrentUser, model);
}

#if FILESYSTEM
/// <exception cref="ArgumentException">
/// <paramref name="filePath" /> is a zero-length string, contains only white space, or contains one or more
/// invalid characters as defined by <see cref="System.IO.Path.InvalidPathChars" />.
@@ -194,7 +193,7 @@ namespace Discord.Rest
using (var file = File.OpenRead(filePath))
return await SendFileAsync(channel, client, file, filename, text, isTTS, embed, options).ConfigureAwait(false);
}
#endif
/// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception>
public static async Task<RestUserMessage> SendFileAsync(IMessageChannel channel, BaseDiscordClient client,
Stream stream, string filename, string text, bool isTTS, Embed embed, RequestOptions options)
@@ -204,6 +203,10 @@ namespace Discord.Rest
return RestUserMessage.Create(client, channel, client.CurrentUser, model);
}

public static Task DeleteMessageAsync(IMessageChannel channel, ulong messageId, BaseDiscordClient client,
RequestOptions options)
=> MessageHelper.DeleteAsync(channel.Id, messageId, client, options);

public static async Task DeleteMessagesAsync(ITextChannel channel, BaseDiscordClient client,
IEnumerable<ulong> messageIds, RequestOptions options)
{


+ 1
- 3
src/Discord.Net.Rest/Entities/Channels/IRestMessageChannel.cs View File

@@ -19,8 +19,7 @@ namespace Discord.Rest
/// <returns>
/// An awaitable Task containing the message sent to the channel.
/// </returns>
new Task<RestUserMessage> SendMessageAsync(string text, bool isTTS = false, Embed embed = null, RequestOptions options = null);
#if FILESYSTEM
new Task<RestUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null);
/// <summary>
/// Sends a file to this message channel, with an optional caption.
/// </summary>
@@ -38,7 +37,6 @@ namespace Discord.Rest
/// An awaitable Task containing the message sent to the channel.
/// </returns>
new Task<RestUserMessage> SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null);
#endif
/// <summary>
/// Sends a file to this message channel, with an optional caption.
/// </summary>


+ 8
- 7
src/Discord.Net.Rest/Entities/Channels/RestDMChannel.cs View File

@@ -74,17 +74,21 @@ namespace Discord.Rest
=> ChannelHelper.GetPinnedMessagesAsync(this, Discord, options);

/// <inheritdoc />
public Task<RestUserMessage> SendMessageAsync(string text, bool isTTS = false, Embed embed = null, RequestOptions options = null)
public Task<RestUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null)
=> ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, options);
#if FILESYSTEM
/// <inheritdoc />
public Task<RestUserMessage> SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null)
=> ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, embed, options);
#endif
/// <inheritdoc />
public Task<RestUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null)
=> ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, embed, options);

public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null)
=> ChannelHelper.DeleteMessageAsync(this, messageId, Discord, options);
public Task DeleteMessageAsync(IMessage message, RequestOptions options = null)
=> ChannelHelper.DeleteMessageAsync(this, message.Id, Discord, options);

/// <inheritdoc />
public Task TriggerTypingAsync(RequestOptions options = null)
=> ChannelHelper.TriggerTypingAsync(this, Discord, options);
@@ -143,12 +147,9 @@ namespace Discord.Rest
async Task<IReadOnlyCollection<IMessage>> IMessageChannel.GetPinnedMessagesAsync(RequestOptions options)
=> await GetPinnedMessagesAsync(options).ConfigureAwait(false);

#if FILESYSTEM
/// <inheritdoc />
async Task<IUserMessage> IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS, Embed embed, RequestOptions options)
=> await SendFileAsync(filePath, text, isTTS, embed, options).ConfigureAwait(false);
#endif
/// <inheritdoc />

async Task<IUserMessage> IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS, Embed embed, RequestOptions options)
=> await SendFileAsync(stream, filename, text, isTTS, embed, options).ConfigureAwait(false);
/// <inheritdoc />


+ 8
- 5
src/Discord.Net.Rest/Entities/Channels/RestGroupChannel.cs View File

@@ -83,11 +83,16 @@ namespace Discord.Rest
public Task<IReadOnlyCollection<RestMessage>> GetPinnedMessagesAsync(RequestOptions options = null)
=> ChannelHelper.GetPinnedMessagesAsync(this, Discord, options);

public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null)
=> ChannelHelper.DeleteMessageAsync(this, messageId, Discord, options);
public Task DeleteMessageAsync(IMessage message, RequestOptions options = null)
=> ChannelHelper.DeleteMessageAsync(this, message.Id, Discord, options);

/// <inheritdoc />
/// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception>
public Task<RestUserMessage> SendMessageAsync(string text, bool isTTS = false, Embed embed = null, RequestOptions options = null)
public Task<RestUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null)
=> ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, options);
#if FILESYSTEM
/// <inheritdoc />
/// <exception cref="ArgumentException">
/// <paramref name="filePath" /> is a zero-length string, contains only white space, or contains one or more
@@ -115,7 +120,6 @@ namespace Discord.Rest
/// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception>
public Task<RestUserMessage> SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null)
=> ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, embed, options);
#endif
/// <inheritdoc />
/// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception>
public Task<RestUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null)
@@ -168,10 +172,9 @@ namespace Discord.Rest
async Task<IReadOnlyCollection<IMessage>> IMessageChannel.GetPinnedMessagesAsync(RequestOptions options)
=> await GetPinnedMessagesAsync(options).ConfigureAwait(false);

#if FILESYSTEM
async Task<IUserMessage> IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS, Embed embed, RequestOptions options)
=> await SendFileAsync(filePath, text, isTTS, embed, options).ConfigureAwait(false);
#endif
async Task<IUserMessage> IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS, Embed embed, RequestOptions options)
=> await SendFileAsync(stream, filename, text, isTTS, embed, options).ConfigureAwait(false);
async Task<IUserMessage> IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options)


+ 9
- 5
src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs View File

@@ -58,15 +58,20 @@ namespace Discord.Rest
public Task<IReadOnlyCollection<RestMessage>> GetPinnedMessagesAsync(RequestOptions options = null)
=> ChannelHelper.GetPinnedMessagesAsync(this, Discord, options);

public Task<RestUserMessage> SendMessageAsync(string text, bool isTTS = false, Embed embed = null, RequestOptions options = null)
public Task<RestUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null)
=> ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, options);
#if FILESYSTEM
public Task<RestUserMessage> SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null)
=> ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, embed, options);
#endif
public Task<RestUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null)
=> ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, embed, options);

public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null)
=> ChannelHelper.DeleteMessageAsync(this, messageId, Discord, options);
public Task DeleteMessageAsync(IMessage message, RequestOptions options = null)
=> ChannelHelper.DeleteMessageAsync(this, message.Id, Discord, options);

public Task DeleteMessagesAsync(IEnumerable<IMessage> messages, RequestOptions options = null)
=> ChannelHelper.DeleteMessagesAsync(this, Discord, messages.Select(x => x.Id), options);
public Task DeleteMessagesAsync(IEnumerable<ulong> messageIds, RequestOptions options = null)
@@ -126,10 +131,9 @@ namespace Discord.Rest
async Task<IReadOnlyCollection<IMessage>> IMessageChannel.GetPinnedMessagesAsync(RequestOptions options)
=> await GetPinnedMessagesAsync(options).ConfigureAwait(false);

#if FILESYSTEM
async Task<IUserMessage> IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS, Embed embed, RequestOptions options)
=> await SendFileAsync(filePath, text, isTTS, embed, options).ConfigureAwait(false);
#endif
async Task<IUserMessage> IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS, Embed embed, RequestOptions options)
=> await SendFileAsync(stream, filename, text, isTTS, embed, options).ConfigureAwait(false);
async Task<IUserMessage> IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options)


+ 11
- 8
src/Discord.Net.Rest/Entities/Channels/RpcVirtualMessageChannel.cs View File

@@ -33,15 +33,19 @@ namespace Discord.Rest
public Task<IReadOnlyCollection<RestMessage>> GetPinnedMessagesAsync(RequestOptions options = null)
=> ChannelHelper.GetPinnedMessagesAsync(this, Discord, options);

public Task<RestUserMessage> SendMessageAsync(string text, bool isTTS, Embed embed = null, RequestOptions options = null)
public Task<RestUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null)
=> ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, options);
#if FILESYSTEM
public Task<RestUserMessage> SendFileAsync(string filePath, string text, bool isTTS, Embed embed = null, RequestOptions options = null)
public Task<RestUserMessage> SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null)
=> ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, embed, options);
#endif
public Task<RestUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS, Embed embed = null, RequestOptions options = null)
public Task<RestUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null)
=> ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, embed, options);

public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null)
=> ChannelHelper.DeleteMessageAsync(this, messageId, Discord, options);
public Task DeleteMessageAsync(IMessage message, RequestOptions options = null)
=> ChannelHelper.DeleteMessageAsync(this, message.Id, Discord, options);

public Task TriggerTypingAsync(RequestOptions options = null)
=> ChannelHelper.TriggerTypingAsync(this, Discord, options);
public IDisposable EnterTypingState(RequestOptions options = null)
@@ -81,10 +85,9 @@ namespace Discord.Rest
async Task<IReadOnlyCollection<IMessage>> IMessageChannel.GetPinnedMessagesAsync(RequestOptions options)
=> await GetPinnedMessagesAsync(options).ConfigureAwait(false);

#if FILESYSTEM
async Task<IUserMessage> IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS, Embed embed, RequestOptions options)
=> await SendFileAsync(filePath, text, isTTS, embed, options).ConfigureAwait(false);
#endif
=> await SendFileAsync(filePath, text, isTTS, embed, options);
async Task<IUserMessage> IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS, Embed embed, RequestOptions options)
=> await SendFileAsync(stream, filename, text, isTTS, embed, options).ConfigureAwait(false);
async Task<IUserMessage> IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options)


+ 20
- 4
src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs View File

@@ -147,21 +147,37 @@ namespace Discord.Rest
}
/// <exception cref="ArgumentNullException"><paramref name="name"/> is <c>null</c>.</exception>
public static async Task<RestTextChannel> CreateTextChannelAsync(IGuild guild, BaseDiscordClient client,
string name, RequestOptions options)
string name, RequestOptions options, Action<TextChannelProperties> func = null)
{
if (name == null) throw new ArgumentNullException(nameof(name));

var args = new CreateGuildChannelParams(name, ChannelType.Text);
var props = new TextChannelProperties();
func?.Invoke(props);

var args = new CreateGuildChannelParams(name, ChannelType.Text)
{
CategoryId = props.CategoryId,
Topic = props.Topic,
IsNsfw = props.IsNsfw
};
var model = await client.ApiClient.CreateGuildChannelAsync(guild.Id, args, options).ConfigureAwait(false);
return RestTextChannel.Create(client, guild, model);
}
/// <exception cref="ArgumentNullException"><paramref name="name"/> is <c>null</c>.</exception>
public static async Task<RestVoiceChannel> CreateVoiceChannelAsync(IGuild guild, BaseDiscordClient client,
string name, RequestOptions options)
string name, RequestOptions options, Action<VoiceChannelProperties> func = null)
{
if (name == null) throw new ArgumentNullException(nameof(name));

var args = new CreateGuildChannelParams(name, ChannelType.Voice);
var props = new VoiceChannelProperties();
func?.Invoke(props);

var args = new CreateGuildChannelParams(name, ChannelType.Voice)
{
CategoryId = props.CategoryId,
Bitrate = props.Bitrate,
UserLimit = props.UserLimit
};
var model = await client.ApiClient.CreateGuildChannelAsync(guild.Id, args, options).ConfigureAwait(false);
return RestVoiceChannel.Create(client, guild, model);
}


+ 8
- 8
src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs View File

@@ -258,10 +258,10 @@ namespace Discord.Rest
}
return null;
}
public Task<RestTextChannel> CreateTextChannelAsync(string name, RequestOptions options = null)
=> GuildHelper.CreateTextChannelAsync(this, Discord, name, options);
public Task<RestVoiceChannel> CreateVoiceChannelAsync(string name, RequestOptions options = null)
=> GuildHelper.CreateVoiceChannelAsync(this, Discord, name, options);
public Task<RestTextChannel> CreateTextChannelAsync(string name, Action<TextChannelProperties> func = null, RequestOptions options = null)
=> GuildHelper.CreateTextChannelAsync(this, Discord, name, options, func);
public Task<RestVoiceChannel> CreateVoiceChannelAsync(string name, Action<VoiceChannelProperties> func = null, RequestOptions options = null)
=> GuildHelper.CreateVoiceChannelAsync(this, Discord, name, options, func);
public Task<RestCategoryChannel> CreateCategoryChannelAsync(string name, RequestOptions options = null)
=> GuildHelper.CreateCategoryChannelAsync(this, Discord, name, options);

@@ -448,11 +448,11 @@ namespace Discord.Rest
return null;
}
/// <inheritdoc />
async Task<ITextChannel> IGuild.CreateTextChannelAsync(string name, RequestOptions options)
=> await CreateTextChannelAsync(name, options).ConfigureAwait(false);
async Task<ITextChannel> IGuild.CreateTextChannelAsync(string name, Action<TextChannelProperties> func, RequestOptions options)
=> await CreateTextChannelAsync(name, func, options).ConfigureAwait(false);
/// <inheritdoc />
async Task<IVoiceChannel> IGuild.CreateVoiceChannelAsync(string name, RequestOptions options)
=> await CreateVoiceChannelAsync(name, options).ConfigureAwait(false);
async Task<IVoiceChannel> IGuild.CreateVoiceChannelAsync(string name, Action<VoiceChannelProperties> func, RequestOptions options)
=> await CreateVoiceChannelAsync(name, func, options).ConfigureAwait(false);
/// <inheritdoc />
async Task<ICategoryChannel> IGuild.CreateCategoryAsync(string name, RequestOptions options)
=> await CreateCategoryChannelAsync(name, options).ConfigureAwait(false);


+ 35
- 8
src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs View File

@@ -27,10 +27,12 @@ namespace Discord.Rest
};
return await client.ApiClient.ModifyMessageAsync(msg.Channel.Id, msg.Id, apiArgs, options).ConfigureAwait(false);
}
public static async Task DeleteAsync(IMessage msg, BaseDiscordClient client,
public static Task DeleteAsync(IMessage msg, BaseDiscordClient client, RequestOptions options)
=> DeleteAsync(msg.Channel.Id, msg.Id, client, options);
public static async Task DeleteAsync(ulong channelId, ulong msgId, BaseDiscordClient client,
RequestOptions options)
{
await client.ApiClient.DeleteMessageAsync(msg.Channel.Id, msg.Id, options).ConfigureAwait(false);
await client.ApiClient.DeleteMessageAsync(channelId, msgId, options).ConfigureAwait(false);
}

public static async Task AddReactionAsync(IMessage msg, IEmote emote, BaseDiscordClient client, RequestOptions options)
@@ -48,13 +50,38 @@ namespace Discord.Rest
await client.ApiClient.RemoveAllReactionsAsync(msg.Channel.Id, msg.Id, options).ConfigureAwait(false);
}

public static async Task<IReadOnlyCollection<IUser>> GetReactionUsersAsync(IMessage msg, IEmote emote,
Action<GetReactionUsersParams> func, BaseDiscordClient client, RequestOptions options)
public static IAsyncEnumerable<IReadOnlyCollection<IUser>> GetReactionUsersAsync(IMessage msg, IEmote emote,
int? limit, BaseDiscordClient client, RequestOptions options)
{
var args = new GetReactionUsersParams();
func(args);
string emoji = (emote is Emote e ? $"{e.Name}:{e.Id}" : emote.Name);
return (await client.ApiClient.GetReactionUsersAsync(msg.Channel.Id, msg.Id, emoji, args, options).ConfigureAwait(false)).Select(u => RestUser.Create(client, u)).ToImmutableArray();
Preconditions.NotNull(emote, nameof(emote));
var emoji = (emote is Emote e ? $"{e.Name}:{e.Id}" : emote.Name);

return new PagedAsyncEnumerable<IUser>(
DiscordConfig.MaxUserReactionsPerBatch,
async (info, ct) =>
{
var args = new GetReactionUsersParams
{
Limit = info.PageSize
};

if (info.Position != null)
args.AfterUserId = info.Position.Value;

var models = await client.ApiClient.GetReactionUsersAsync(msg.Channel.Id, msg.Id, emoji, args, options).ConfigureAwait(false);
return models.Select(x => RestUser.Create(client, x)).ToImmutableArray();
},
nextPage: (info, lastPage) =>
{
if (lastPage.Count != DiscordConfig.MaxUsersPerBatch)
return false;

info.Position = lastPage.Max(x => x.Id);
return true;
},
count: limit
);

}

public static async Task PinAsync(IMessage msg, BaseDiscordClient client,


+ 3
- 3
src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs View File

@@ -151,9 +151,9 @@ namespace Discord.Rest
public Task RemoveAllReactionsAsync(RequestOptions options = null)
=> MessageHelper.RemoveAllReactionsAsync(this, Discord, options);
/// <inheritdoc />
public Task<IReadOnlyCollection<IUser>> GetReactionUsersAsync(IEmote emote, int limit = 100, ulong? afterUserId = null, RequestOptions options = null)
=> MessageHelper.GetReactionUsersAsync(this, emote, x => { x.Limit = limit; x.AfterUserId = afterUserId ?? Optional.Create<ulong>(); }, Discord, options);
public IAsyncEnumerable<IReadOnlyCollection<IUser>> GetReactionUsersAsync(IEmote emote, int limit, RequestOptions options = null)
=> MessageHelper.GetReactionUsersAsync(this, emote, limit, Discord, options);
/// <inheritdoc />
public Task PinAsync(RequestOptions options = null)
=> MessageHelper.PinAsync(this, Discord, options);


+ 1
- 2
src/Discord.Net.Rest/Net/Converters/DiscordContractResolver.cs View File

@@ -1,4 +1,4 @@
using Discord.API;
using Discord.API;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
@@ -25,7 +25,6 @@ namespace Discord.Net.Converters
if (converter != null)
{
property.Converter = converter;
property.MemberConverter = converter;
}
}
else


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

@@ -230,7 +230,7 @@ namespace Discord.Net.Queue
#endif
}

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

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


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

@@ -21,7 +21,7 @@ namespace Discord.Net
Remaining = headers.TryGetValue("X-RateLimit-Remaining", out temp) &&
int.TryParse(temp, out var remaining) ? remaining : (int?)null;
Reset = headers.TryGetValue("X-RateLimit-Reset", out temp) &&
int.TryParse(temp, out var reset) ? DateTimeUtils.FromUnixSeconds(reset) : (DateTimeOffset?)null;
int.TryParse(temp, out var reset) ? DateTimeOffset.FromUnixTimeSeconds(reset) : (DateTimeOffset?)null;
RetryAfter = headers.TryGetValue("Retry-After", out temp) &&
int.TryParse(temp, out var retryAfter) ? retryAfter : (int?)null;
Lag = headers.TryGetValue("Date", out temp) &&


+ 4
- 4
src/Discord.Net.WebSocket/Discord.Net.WebSocket.csproj View File

@@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="../../Discord.Net.targets" />
<PropertyGroup>
<AssemblyName>Discord.Net.WebSocket</AssemblyName>
<RootNamespace>Discord.WebSocket</RootNamespace>
<Description>A core Discord.Net library containing the WebSocket client and models.</Description>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net45;netstandard1.1;netstandard1.3</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netstandard1.1;netstandard1.3</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net46;netstandard1.3;netstandard2.0</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netstandard1.3;netstandard2.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
@@ -13,6 +13,6 @@
<ProjectReference Include="..\Discord.Net.Rest\Discord.Net.Rest.csproj" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
<PackageReference Include="System.Net.WebSockets.Client" Version="4.3.1" />
<PackageReference Include="System.Net.WebSockets.Client" Version="4.3.2" />
</ItemGroup>
</Project>

+ 1
- 1
src/Discord.Net.WebSocket/DiscordSocketClient.cs View File

@@ -378,7 +378,7 @@ namespace Discord.WebSocket
await ApiClient.SendStatusUpdateAsync(
status,
status == UserStatus.AFK,
statusSince != null ? DateTimeUtils.ToUnixMilliseconds(_statusSince.Value) : (long?)null,
statusSince != null ? _statusSince.Value.ToUnixTimeMilliseconds() : (long?)null,
gameModel).ConfigureAwait(false);
}



+ 2
- 2
src/Discord.Net.WebSocket/DiscordVoiceApiClient.cs View File

@@ -1,4 +1,4 @@
#pragma warning disable CS1591
#pragma warning disable CS1591
using Discord.API;
using Discord.API.Voice;
using Discord.Net.Converters;
@@ -129,7 +129,7 @@ namespace Discord.Audio
//WebSocket
public async Task SendHeartbeatAsync(RequestOptions options = null)
{
await SendAsync(VoiceOpCode.Heartbeat, DateTimeUtils.ToUnixMilliseconds(DateTimeOffset.UtcNow), options: options).ConfigureAwait(false);
await SendAsync(VoiceOpCode.Heartbeat, DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), options: options).ConfigureAwait(false);
}
public async Task SendIdentityAsync(ulong userId, string sessionId, string token)
{


+ 1
- 3
src/Discord.Net.WebSocket/Entities/Channels/ISocketMessageChannel.cs View File

@@ -28,8 +28,7 @@ namespace Discord.WebSocket
/// <returns>
/// An awaitable Task containing the message sent to the channel.
/// </returns>
new Task<RestUserMessage> SendMessageAsync(string text, bool isTTS = false, Embed embed = null, RequestOptions options = null);
#if FILESYSTEM
new Task<RestUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null);
/// <summary>
/// Sends a file to this message channel, with an optional caption.
/// </summary>
@@ -47,7 +46,6 @@ namespace Discord.WebSocket
/// An awaitable Task containing the message sent to the channel.
/// </returns>
new Task<RestUserMessage> SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null);
#endif
/// <summary>
/// Sends a file to this message channel, with an optional caption.
/// </summary>


+ 7
- 7
src/Discord.Net.WebSocket/Entities/Channels/SocketDMChannel.cs View File

@@ -79,18 +79,22 @@ namespace Discord.WebSocket

/// <inheritdoc />
/// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception>
public Task<RestUserMessage> SendMessageAsync(string text, bool isTTS = false, Embed embed = null, RequestOptions options = null)
public Task<RestUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null)
=> ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, options);
#if FILESYSTEM
/// <inheritdoc />
public Task<RestUserMessage> SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null)
=> ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, embed, options);
#endif
/// <inheritdoc />
/// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception>
public Task<RestUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null)
=> ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, embed, options);

public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null)
=> ChannelHelper.DeleteMessageAsync(this, messageId, Discord, options);
public Task DeleteMessageAsync(IMessage message, RequestOptions options = null)
=> ChannelHelper.DeleteMessageAsync(this, message.Id, Discord, options);

/// <inheritdoc />
public Task TriggerTypingAsync(RequestOptions options = null)
=> ChannelHelper.TriggerTypingAsync(this, Discord, options);
@@ -160,12 +164,8 @@ namespace Discord.WebSocket
/// <inheritdoc />
async Task<IReadOnlyCollection<IMessage>> IMessageChannel.GetPinnedMessagesAsync(RequestOptions options)
=> await GetPinnedMessagesAsync(options).ConfigureAwait(false);
#if FILESYSTEM
/// <inheritdoc />
async Task<IUserMessage> IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS, Embed embed, RequestOptions options)
=> await SendFileAsync(filePath, text, isTTS, embed, options).ConfigureAwait(false);
#endif
/// <inheritdoc />
async Task<IUserMessage> IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS, Embed embed, RequestOptions options)
=> await SendFileAsync(stream, filename, text, isTTS, embed, options).ConfigureAwait(false);
/// <inheritdoc />


+ 8
- 5
src/Discord.Net.WebSocket/Entities/Channels/SocketGroupChannel.cs View File

@@ -109,17 +109,21 @@ namespace Discord.WebSocket

/// <inheritdoc />
/// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception>
public Task<RestUserMessage> SendMessageAsync(string text, bool isTTS = false, Embed embed = null, RequestOptions options = null)
public Task<RestUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null)
=> ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, options);
#if FILESYSTEM
/// <inheritdoc />
public Task<RestUserMessage> SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null)
=> ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, embed, options);
#endif
/// <inheritdoc />
public Task<RestUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null)
=> ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, embed, options);

public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null)
=> ChannelHelper.DeleteMessageAsync(this, messageId, Discord, options);
public Task DeleteMessageAsync(IMessage message, RequestOptions options = null)
=> ChannelHelper.DeleteMessageAsync(this, message.Id, Discord, options);

/// <inheritdoc />
public Task TriggerTypingAsync(RequestOptions options = null)
=> ChannelHelper.TriggerTypingAsync(this, Discord, options);
@@ -235,11 +239,10 @@ namespace Discord.WebSocket
/// <inheritdoc />
async Task<IReadOnlyCollection<IMessage>> IMessageChannel.GetPinnedMessagesAsync(RequestOptions options)
=> await GetPinnedMessagesAsync(options).ConfigureAwait(false);
#if FILESYSTEM
/// <inheritdoc />
async Task<IUserMessage> IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS, Embed embed, RequestOptions options)
=> await SendFileAsync(filePath, text, isTTS, embed, options).ConfigureAwait(false);
#endif
/// <inheritdoc />
async Task<IUserMessage> IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS, Embed embed, RequestOptions options)
=> await SendFileAsync(stream, filename, text, isTTS, embed, options).ConfigureAwait(false);


+ 8
- 5
src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs View File

@@ -90,13 +90,12 @@ namespace Discord.WebSocket
=> ChannelHelper.GetPinnedMessagesAsync(this, Discord, options);

/// <inheritdoc />
public Task<RestUserMessage> SendMessageAsync(string text, bool isTTS = false, Embed embed = null, RequestOptions options = null)
public Task<RestUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null)
=> ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, options);
#if FILESYSTEM
/// <inheritdoc />
public Task<RestUserMessage> SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null)
=> ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, embed, options);
#endif
/// <inheritdoc />
public Task<RestUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null)
=> ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, embed, options);
@@ -108,6 +107,11 @@ namespace Discord.WebSocket
public Task DeleteMessagesAsync(IEnumerable<ulong> messageIds, RequestOptions options = null)
=> ChannelHelper.DeleteMessagesAsync(this, Discord, messageIds, options);

public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null)
=> ChannelHelper.DeleteMessageAsync(this, messageId, Discord, options);
public Task DeleteMessageAsync(IMessage message, RequestOptions options = null)
=> ChannelHelper.DeleteMessageAsync(this, message.Id, Discord, options);

/// <inheritdoc />
public Task TriggerTypingAsync(RequestOptions options = null)
=> ChannelHelper.TriggerTypingAsync(this, Discord, options);
@@ -209,11 +213,10 @@ namespace Discord.WebSocket
/// <inheritdoc />
async Task<IReadOnlyCollection<IMessage>> IMessageChannel.GetPinnedMessagesAsync(RequestOptions options)
=> await GetPinnedMessagesAsync(options).ConfigureAwait(false);
#if FILESYSTEM
/// <inheritdoc />
async Task<IUserMessage> IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS, Embed embed, RequestOptions options)
=> await SendFileAsync(filePath, text, isTTS, embed, options).ConfigureAwait(false);
#endif
/// <inheritdoc />
async Task<IUserMessage> IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS, Embed embed, RequestOptions options)
=> await SendFileAsync(stream, filename, text, isTTS, embed, options).ConfigureAwait(false);


+ 8
- 10
src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs View File

@@ -463,9 +463,8 @@ namespace Discord.WebSocket
/// <returns>
/// The created text channel.
/// </returns>
public Task<RestTextChannel> CreateTextChannelAsync(string name, RequestOptions options = null)
=> GuildHelper.CreateTextChannelAsync(this, Discord, name, options);

public Task<RestTextChannel> CreateTextChannelAsync(string name, Action<TextChannelProperties> func = null, RequestOptions options = null)
=> GuildHelper.CreateTextChannelAsync(this, Discord, name, options, func);
/// <summary>
/// Creates a voice channel with the provided name.
/// </summary>
@@ -475,9 +474,8 @@ namespace Discord.WebSocket
/// <returns>
/// The created voice channel.
/// </returns>
public Task<RestVoiceChannel> CreateVoiceChannelAsync(string name, RequestOptions options = null)
=> GuildHelper.CreateVoiceChannelAsync(this, Discord, name, options);

public Task<RestVoiceChannel> CreateVoiceChannelAsync(string name, Action<VoiceChannelProperties> func = null, RequestOptions options = null)
=> GuildHelper.CreateVoiceChannelAsync(this, Discord, name, options, func);
/// <summary>
/// Creates a category channel with the provided name.
/// </summary>
@@ -930,11 +928,11 @@ namespace Discord.WebSocket
Task<ITextChannel> IGuild.GetSystemChannelAsync(CacheMode mode, RequestOptions options)
=> Task.FromResult<ITextChannel>(SystemChannel);
/// <inheritdoc />
async Task<ITextChannel> IGuild.CreateTextChannelAsync(string name, RequestOptions options)
=> await CreateTextChannelAsync(name, options).ConfigureAwait(false);
async Task<ITextChannel> IGuild.CreateTextChannelAsync(string name, Action<TextChannelProperties> func, RequestOptions options)
=> await CreateTextChannelAsync(name, func, options).ConfigureAwait(false);
/// <inheritdoc />
async Task<IVoiceChannel> IGuild.CreateVoiceChannelAsync(string name, RequestOptions options)
=> await CreateVoiceChannelAsync(name, options).ConfigureAwait(false);
async Task<IVoiceChannel> IGuild.CreateVoiceChannelAsync(string name, Action<VoiceChannelProperties> func, RequestOptions options)
=> await CreateVoiceChannelAsync(name, func, options).ConfigureAwait(false);
/// <inheritdoc />
async Task<ICategoryChannel> IGuild.CreateCategoryAsync(string name, RequestOptions options)
=> await CreateCategoryChannelAsync(name, options).ConfigureAwait(false);


+ 2
- 2
src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs View File

@@ -150,8 +150,8 @@ namespace Discord.WebSocket
public Task RemoveAllReactionsAsync(RequestOptions options = null)
=> MessageHelper.RemoveAllReactionsAsync(this, Discord, options);
/// <inheritdoc />
public Task<IReadOnlyCollection<IUser>> GetReactionUsersAsync(IEmote emote, int limit = 100, ulong? afterUserId = null, RequestOptions options = null)
=> MessageHelper.GetReactionUsersAsync(this, emote, x => { x.Limit = limit; x.AfterUserId = afterUserId ?? Optional.Create<ulong>(); }, Discord, options);
public IAsyncEnumerable<IReadOnlyCollection<IUser>> GetReactionUsersAsync(IEmote emote, int limit, RequestOptions options = null)
=> MessageHelper.GetReactionUsersAsync(this, emote, limit, Discord, options);

/// <inheritdoc />
public Task PinAsync(RequestOptions options = null)


+ 0
- 6
src/Discord.Net.WebSocket/Net/DefaultUdpSocket.cs View File

@@ -1,4 +1,3 @@
#if DEFAULTUDPCLIENT
using System;
using System.Net;
using System.Net.Sockets;
@@ -85,11 +84,7 @@ namespace Discord.Net.Udp

if (_udp != null)
{
#if UDPDISPOSE
try { _udp.Dispose(); }
#else
try { _udp.Close(); }
#endif
catch { }
_udp = null;
}
@@ -132,4 +127,3 @@ namespace Discord.Net.Udp
}
}
}
#endif

+ 1
- 9
src/Discord.Net.WebSocket/Net/DefaultUdpSocketProvider.cs View File

@@ -4,7 +4,6 @@ namespace Discord.Net.Udp
{
public static class DefaultUdpSocketProvider
{
#if DEFAULTUDPCLIENT
public static readonly UdpSocketProvider Instance = () =>
{
try
@@ -16,12 +15,5 @@ namespace Discord.Net.Udp
throw new PlatformNotSupportedException("The default UdpSocketProvider is not supported on this platform.", ex);
}
};
#else
public static readonly UdpSocketProvider Instance = () =>
{
throw new PlatformNotSupportedException("The default UdpSocketProvider is not supported on this platform.\n" +
"You must specify a UdpSocketProvider or target a runtime supporting .NET Standard 1.3, such as .NET Framework 4.6+.");
};
#endif
}
}
}

+ 3
- 10
src/Discord.Net.WebSocket/Net/DefaultWebSocketClient.cs View File

@@ -1,4 +1,3 @@
#if DEFAULTWEBSOCKET
using System;
using System.Collections.Generic;
using System.ComponentModel;
@@ -209,14 +208,9 @@ namespace Discord.Net.WebSockets

//Use the internal buffer if we can get it
resultCount = (int)stream.Length;
#if MSTRYBUFFER
if (stream.TryGetBuffer(out var streamBuffer))
result = streamBuffer.Array;
else
result = stream.ToArray();
#else
result = stream.GetBuffer();
#endif

result = stream.TryGetBuffer(out var streamBuffer) ? streamBuffer.Array : stream.ToArray();

}
}
else
@@ -248,4 +242,3 @@ namespace Discord.Net.WebSockets
}
}
}
#endif

+ 0
- 8
src/Discord.Net.WebSocket/Net/DefaultWebSocketClientProvider.cs View File

@@ -5,7 +5,6 @@ namespace Discord.Net.WebSockets
{
public static class DefaultWebSocketProvider
{
#if DEFAULTWEBSOCKET
public static readonly WebSocketProvider Instance = Create();

/// <exception cref="PlatformNotSupportedException">The default WebSocketProvider is not supported on this platform.</exception>
@@ -23,12 +22,5 @@ namespace Discord.Net.WebSockets
}
};
}
#else
public static readonly WebSocketProvider Instance = () =>
{
throw new PlatformNotSupportedException("The default WebSocketProvider is not supported on this platform.\n" +
"You must specify a WebSocketProvider or target a runtime supporting .NET Standard 1.3, such as .NET Framework 4.6+.");
};
#endif
}
}

+ 2
- 2
src/Discord.Net.Webhook/Discord.Net.Webhook.csproj View File

@@ -1,10 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="../../Discord.Net.targets" />
<PropertyGroup>
<AssemblyName>Discord.Net.Webhook</AssemblyName>
<RootNamespace>Discord.Webhook</RootNamespace>
<Description>A core Discord.Net library containing the Webhook client and models.</Description>
<TargetFrameworks>netstandard1.1;netstandard1.3</TargetFrameworks>
<TargetFrameworks>netstandard1.3</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Discord.Net.Core\Discord.Net.Core.csproj" />


+ 1
- 4
src/Discord.Net.Webhook/DiscordWebhookClient.cs View File

@@ -62,20 +62,17 @@ namespace Discord.Webhook
}
private static API.DiscordRestApiClient CreateApiClient(DiscordRestConfig config)
=> new API.DiscordRestApiClient(config.RestClientProvider, DiscordRestConfig.UserAgent);

/// <summary> Sends a message using to the channel for this webhook. </summary>
/// <returns> Returns the ID of the created message. </returns>
public Task<ulong> SendMessageAsync(string text, bool isTTS = false, IEnumerable<Embed> embeds = null,
public Task<ulong> SendMessageAsync(string text = null, bool isTTS = false, IEnumerable<Embed> embeds = null,
string username = null, string avatarUrl = null, RequestOptions options = null)
=> WebhookClientHelper.SendMessageAsync(this, text, isTTS, embeds, username, avatarUrl, options);

#if FILESYSTEM
/// <summary> Sends a message to the channel for this webhook with an attachment. </summary>
/// <returns> Returns the ID of the created message. </returns>
public Task<ulong> SendFileAsync(string filePath, string text, bool isTTS = false,
IEnumerable<Embed> embeds = null, string username = null, string avatarUrl = null, RequestOptions options = null)
=> WebhookClientHelper.SendFileAsync(this, filePath, text, isTTS, embeds, username, avatarUrl, options);
#endif
/// <summary> Sends a message to the channel for this webhook with an attachment. </summary>
/// <returns> Returns the ID of the created message. </returns>
public Task<ulong> SendFileAsync(Stream stream, string filename, string text, bool isTTS = false,


+ 0
- 2
src/Discord.Net.Webhook/WebhookClientHelper.cs View File

@@ -34,7 +34,6 @@ namespace Discord.Webhook
var model = await client.ApiClient.CreateWebhookMessageAsync(client.Webhook.Id, args, options: options).ConfigureAwait(false);
return model.Id;
}
#if FILESYSTEM
public static async Task<ulong> SendFileAsync(DiscordWebhookClient client, string filePath, string text, bool isTTS,
IEnumerable<Embed> embeds, string username, string avatarUrl, RequestOptions options)
{
@@ -42,7 +41,6 @@ namespace Discord.Webhook
using (var file = File.OpenRead(filePath))
return await SendFileAsync(client, file, filename, text, isTTS, embeds, username, avatarUrl, options).ConfigureAwait(false);
}
#endif
public static async Task<ulong> SendFileAsync(DiscordWebhookClient client, Stream stream, string filename, string text, bool isTTS,
IEnumerable<Embed> embeds, string username, string avatarUrl, RequestOptions options)
{


+ 5
- 5
test/Discord.Net.Tests/Discord.Net.Tests.csproj View File

@@ -21,10 +21,10 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Akavache" Version="5.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
<PackageReference Include="xunit" Version="2.2.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
<PackageReference Include="xunit.runner.reporters" Version="2.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.2" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<PackageReference Include="xunit.runner.reporters" Version="2.3.1" />
</ItemGroup>
</Project>

+ 1
- 1
test/Discord.Net.Tests/Tests.ChannelPermissions.cs View File

@@ -84,7 +84,7 @@ namespace Discord
Assert.Equal(groupChannel, ChannelPermissions.Group.RawValue);
return Task.CompletedTask;
}
[Fact]
public Task TestChannelPermissionModify()
{
// test channel permission modify


+ 26
- 26
test/Discord.Net.Tests/Tests.Channels.cs View File

@@ -49,35 +49,35 @@ namespace Discord
}
private static void CheckTextChannels(RestGuild guild, params RestTextChannel[] textChannels)
{
Assert.Equal(textChannels.Length, 5);
Assert.Equal(5, textChannels.Length);
Assert.All(textChannels, x =>
{
Assert.NotNull(x);
Assert.NotEqual(x.Id, 0UL);
Assert.NotEqual(0UL, x.Id);
Assert.True(x.Position >= 0);
});

var text1 = textChannels.Where(x => x.Name == "text1").FirstOrDefault();
var text2 = textChannels.Where(x => x.Name == "text2").FirstOrDefault();
var text3 = textChannels.Where(x => x.Name == "text3").FirstOrDefault();
var text4 = textChannels.Where(x => x.Name == "text4").FirstOrDefault();
var text5 = textChannels.Where(x => x.Name == "text5").FirstOrDefault();
var text1 = textChannels.FirstOrDefault(x => x.Name == "text1");
var text2 = textChannels.FirstOrDefault(x => x.Name == "text2");
var text3 = textChannels.FirstOrDefault(x => x.Name == "text3");
var text4 = textChannels.FirstOrDefault(x => x.Name == "text4");
var text5 = textChannels.FirstOrDefault(x => x.Name == "text5");

Assert.NotNull(text1);
//Assert.True(text1.Id == guild.DefaultChannelId);
Assert.Equal(text1.Position, 1);
Assert.Equal(text1.Topic, "Topic1");
Assert.Equal(1, text1.Position);
Assert.Equal("Topic1", text1.Topic);

Assert.NotNull(text2);
Assert.Equal(text2.Position, 2);
Assert.Equal(2, text2.Position);
Assert.Null(text2.Topic);

Assert.NotNull(text3);
Assert.Equal(text3.Topic, "Topic2");
Assert.Equal("Topic2", text3.Topic);

Assert.NotNull(text4);
Assert.Equal(text4.Position, 3);
Assert.Equal(text4.Topic, "Topic2");
Assert.Equal(3, text4.Position);
Assert.Equal("Topic2", text4.Topic);

Assert.NotNull(text5);
Assert.Null(text5.Topic);
@@ -114,31 +114,31 @@ namespace Discord
}
private static void CheckVoiceChannels(params RestVoiceChannel[] voiceChannels)
{
Assert.Equal(voiceChannels.Length, 3);
Assert.Equal(3, voiceChannels.Length);
Assert.All(voiceChannels, x =>
{
Assert.NotNull(x);
Assert.NotEqual(x.Id, 0UL);
Assert.NotEqual(x.UserLimit, 0);
Assert.NotEqual(0UL, x.Id);
Assert.NotEqual(0, x.UserLimit);
Assert.True(x.Bitrate > 0);
Assert.True(x.Position >= 0);
});

var voice1 = voiceChannels.Where(x => x.Name == "voice1").FirstOrDefault();
var voice2 = voiceChannels.Where(x => x.Name == "voice2").FirstOrDefault();
var voice3 = voiceChannels.Where(x => x.Name == "voice3").FirstOrDefault();
var voice1 = voiceChannels.FirstOrDefault(x => x.Name == "voice1");
var voice2 = voiceChannels.FirstOrDefault(x => x.Name == "voice2");
var voice3 = voiceChannels.FirstOrDefault(x => x.Name == "voice3");

Assert.NotNull(voice1);
Assert.Equal(voice1.Bitrate, 96000);
Assert.Equal(voice1.Position, 1);
Assert.Equal(96000, voice1.Bitrate);
Assert.Equal(1, voice1.Position);

Assert.NotNull(voice2);
Assert.Equal(voice2.UserLimit, null);
Assert.Null(voice2.UserLimit);

Assert.NotNull(voice3);
Assert.Equal(voice3.Bitrate, 8000);
Assert.Equal(voice3.Position, 1);
Assert.Equal(voice3.UserLimit, 16);
Assert.Equal(8000, voice3.Bitrate);
Assert.Equal(1, voice3.Position);
Assert.Equal(16, voice3.UserLimit);
}
}
}
}

+ 2
- 1
test/Discord.Net.Tests/Tests.Colors.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using Xunit;

namespace Discord
@@ -12,6 +12,7 @@ namespace Discord
Assert.Equal(uint.MinValue, new Color(uint.MinValue).RawValue);
Assert.Equal(uint.MaxValue, new Color(uint.MaxValue).RawValue);
}
[Fact]
public void Color_Default()
{
Assert.Equal(0u, Color.Default.RawValue);


+ 2
- 1
test/Discord.Net.Tests/Tests.Emotes.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using Xunit;

namespace Discord
@@ -34,6 +34,7 @@ namespace Discord
Assert.Equal(DateTimeOffset.FromUnixTimeMilliseconds(1514056829775), emote.CreatedAt);
Assert.EndsWith("gif", emote.Url);
}
[Fact]
public void Test_Invalid_Amimated_Emote_Parse()
{
Assert.False(Emote.TryParse("<x:typingstatus:394207658351263745>", out _));


+ 5
- 5
test/Discord.Net.Tests/Tests.GuildPermissions.cs View File

@@ -138,12 +138,12 @@ namespace Discord


// individual permission test
perm = perm.Modify(readMessages: true);
Assert.True(perm.ReadMessages);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.ReadMessages);
perm = perm.Modify(viewChannel: true);
Assert.True(perm.ViewChannel);
Assert.Equal(perm.RawValue, (ulong)GuildPermission.ViewChannel);

perm = perm.Modify(readMessages: false);
Assert.False(perm.ReadMessages);
perm = perm.Modify(viewChannel: false);
Assert.False(perm.ViewChannel);
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue);




+ 7
- 7
test/Discord.Net.Tests/Tests.Permissions.cs View File

@@ -25,15 +25,15 @@ namespace Discord

// check that toggling the bit works
Permissions.UnsetFlag(ref rawValue, flagValue);
Assert.Equal(false, Permissions.GetValue(rawValue, flagValue));
Assert.False(Permissions.GetValue(rawValue, flagValue));
Permissions.SetFlag(ref rawValue, flagValue);
Assert.Equal(true, Permissions.GetValue(rawValue, flagValue));
Assert.True(Permissions.GetValue(rawValue, flagValue));

// do the same, but with the SetValue method
Permissions.SetValue(ref rawValue, true, flagValue);
Assert.Equal(true, Permissions.GetValue(rawValue, flagValue));
Assert.True(Permissions.GetValue(rawValue, flagValue));
Permissions.SetValue(ref rawValue, false, flagValue);
Assert.Equal(false, Permissions.GetValue(rawValue, flagValue));
Assert.False(Permissions.GetValue(rawValue, flagValue));
}

/// <summary>
@@ -280,7 +280,7 @@ namespace Discord
TestHelper(value, GuildPermission.ManageGuild, false);
TestHelper(value, GuildPermission.AddReactions, false);
TestHelper(value, GuildPermission.ViewAuditLog, false);
TestHelper(value, GuildPermission.ReadMessages, false);
TestHelper(value, GuildPermission.ViewChannel, false);
TestHelper(value, GuildPermission.SendMessages, false);
TestHelper(value, GuildPermission.SendTTSMessages, false);
TestHelper(value, GuildPermission.ManageMessages, false);
@@ -323,7 +323,7 @@ namespace Discord
TestHelper(value, GuildPermission.ManageGuild, true);
TestHelper(value, GuildPermission.AddReactions, true);
TestHelper(value, GuildPermission.ViewAuditLog, true);
TestHelper(value, GuildPermission.ReadMessages, true);
TestHelper(value, GuildPermission.ViewChannel, true);
TestHelper(value, GuildPermission.SendMessages, true);
TestHelper(value, GuildPermission.SendTTSMessages, true);
TestHelper(value, GuildPermission.ManageMessages, true);
@@ -367,7 +367,7 @@ namespace Discord
TestHelper(value, GuildPermission.ManageGuild, false);
TestHelper(value, GuildPermission.AddReactions, false);
TestHelper(value, GuildPermission.ViewAuditLog, false);
TestHelper(value, GuildPermission.ReadMessages, false);
TestHelper(value, GuildPermission.ViewChannel, false);
TestHelper(value, GuildPermission.SendMessages, true);
TestHelper(value, GuildPermission.SendTTSMessages, true);
TestHelper(value, GuildPermission.ManageMessages, false);


Loading…
Cancel
Save