diff --git a/README.md b/README.md index bd0ef20c7..7dc8cd788 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,9 @@ Our stable builds available from NuGet through the Discord.Net metapackage: The individual components may also be installed from NuGet: - [Discord.Net.Commands](https://www.nuget.org/packages/Discord.Net.Commands/) - [Discord.Net.Rest](https://www.nuget.org/packages/Discord.Net.Rest/) -- [Discord.Net.Rpc](https://www.nuget.org/packages/Discord.Net.Rpc/) - [Discord.Net.WebSocket](https://www.nuget.org/packages/Discord.Net.WebSocket/) - [Discord.Net.Webhook](https://www.nuget.org/packages/Discord.Net.Webhook/) -The following provider is available for platforms not supporting .NET Standard 1.3: -- [Discord.Net.Providers.WS4Net](https://www.nuget.org/packages/Discord.Net.Providers.WS4Net/) - ### Unstable (MyGet) Nightly builds are available through our MyGet feed (`https://www.myget.org/F/discord-net/api/v3/index.json`). @@ -41,5 +37,4 @@ The .NET Core workload must be selected during Visual Studio installation. ## Known Issues ### WebSockets (Win7 and earlier) -.NET Core 1.1 does not support WebSockets on Win7 and earlier. It's recommended to use the Discord.Net.Providers.WS4Net package until this is resolved. -Track the issue [here](https://github.com/dotnet/corefx/issues/9503). +.NET Core 1.1 does not support WebSockets on Win7 and earlier. This issue has been fixed since the release of .NET Core 2.1. It is recommended to target .NET Core 2.1 or above for your project if you wish to run your bot on legacy platforms; alternatively, you may choose to install the [Discord.Net.Providers.WS4Net](https://www.nuget.org/packages/Discord.Net.Providers.WS4Net/) package. diff --git a/src/Discord.Net.Commands/Attributes/CommandAttribute.cs b/src/Discord.Net.Commands/Attributes/CommandAttribute.cs index a0fcf3e4a..bfc04641a 100644 --- a/src/Discord.Net.Commands/Attributes/CommandAttribute.cs +++ b/src/Discord.Net.Commands/Attributes/CommandAttribute.cs @@ -7,7 +7,7 @@ namespace Discord.Commands { public string Text { get; } public RunMode RunMode { get; set; } = RunMode.Default; - public bool? IgnoreExtraArgs { get; set; } + public bool? IgnoreExtraArgs { get; } public CommandAttribute() { @@ -17,5 +17,10 @@ namespace Discord.Commands { Text = text; } + public CommandAttribute(string text, bool ignoreExtraArgs) + { + Text = text; + IgnoreExtraArgs = ignoreExtraArgs; + } } } diff --git a/src/Discord.Net.Commands/Attributes/OverrideTypeReaderAttribute.cs b/src/Discord.Net.Commands/Attributes/OverrideTypeReaderAttribute.cs index 44ab6d214..17e2310d4 100644 --- a/src/Discord.Net.Commands/Attributes/OverrideTypeReaderAttribute.cs +++ b/src/Discord.Net.Commands/Attributes/OverrideTypeReaderAttribute.cs @@ -7,13 +7,13 @@ namespace Discord.Commands [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] public class OverrideTypeReaderAttribute : Attribute { - private static readonly TypeInfo _typeReaderTypeInfo = typeof(TypeReader).GetTypeInfo(); + private static readonly TypeInfo TypeReaderTypeInfo = typeof(TypeReader).GetTypeInfo(); public Type TypeReader { get; } public OverrideTypeReaderAttribute(Type overridenTypeReader) { - if (!_typeReaderTypeInfo.IsAssignableFrom(overridenTypeReader.GetTypeInfo())) + if (!TypeReaderTypeInfo.IsAssignableFrom(overridenTypeReader.GetTypeInfo())) throw new ArgumentException($"{nameof(overridenTypeReader)} must inherit from {nameof(TypeReader)}"); TypeReader = overridenTypeReader; diff --git a/src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs b/src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs index cbe02aafb..307874ca6 100644 --- a/src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs +++ b/src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs @@ -10,7 +10,7 @@ namespace Discord.Commands { internal static class ModuleClassBuilder { - private static readonly TypeInfo _moduleTypeInfo = typeof(IModuleBase).GetTypeInfo(); + private static readonly TypeInfo ModuleTypeInfo = typeof(IModuleBase).GetTypeInfo(); public static async Task> SearchAsync(Assembly assembly, CommandService service) { @@ -135,7 +135,7 @@ namespace Discord.Commands if (builder.Name == null) builder.Name = typeInfo.Name; - var validCommands = typeInfo.DeclaredMethods.Where(x => IsValidCommandDefinition(x)); + var validCommands = typeInfo.DeclaredMethods.Where(IsValidCommandDefinition); foreach (var method in validCommands) { @@ -299,7 +299,7 @@ namespace Discord.Commands private static bool IsValidModuleDefinition(TypeInfo typeInfo) { - return _moduleTypeInfo.IsAssignableFrom(typeInfo) && + return ModuleTypeInfo.IsAssignableFrom(typeInfo) && !typeInfo.IsAbstract && !typeInfo.ContainsGenericParameters; } diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index 6fd5d38ad..7b7cffda2 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -118,7 +118,7 @@ namespace Discord.Commands var typeInfo = type.GetTypeInfo(); if (_typedModuleDefs.ContainsKey(type)) - throw new ArgumentException($"This module has already been added."); + throw new ArgumentException("This module has already been added."); var module = (await ModuleClassBuilder.BuildAsync(this, services, typeInfo).ConfigureAwait(false)).FirstOrDefault(); @@ -241,7 +241,7 @@ namespace Discord.Commands { if (_defaultTypeReaders.ContainsKey(type)) _ = _cmdLogger.WarningAsync($"The default TypeReader for {type.FullName} was replaced by {reader.GetType().FullName}." + - $"To suppress this message, use AddTypeReader(reader, true)."); + "To suppress this message, use AddTypeReader(reader, true)."); AddTypeReader(type, reader, true); } /// diff --git a/src/Discord.Net.Commands/Info/CommandInfo.cs b/src/Discord.Net.Commands/Info/CommandInfo.cs index df0bb297b..604bfbc93 100644 --- a/src/Discord.Net.Commands/Info/CommandInfo.cs +++ b/src/Discord.Net.Commands/Info/CommandInfo.cs @@ -1,4 +1,4 @@ -using Discord.Commands.Builders; +using Discord.Commands.Builders; using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -63,7 +63,7 @@ namespace Discord.Commands Attributes = builder.Attributes.ToImmutableArray(); Parameters = builder.Parameters.Select(x => x.Build(this)).ToImmutableArray(); - HasVarArgs = builder.Parameters.Count > 0 ? builder.Parameters[builder.Parameters.Count - 1].IsMultiple : false; + HasVarArgs = builder.Parameters.Count > 0 && builder.Parameters[builder.Parameters.Count - 1].IsMultiple; IgnoreExtraArgs = builder.IgnoreExtraArgs; _action = builder.Callback; diff --git a/src/Discord.Net.Commands/Map/CommandMap.cs b/src/Discord.Net.Commands/Map/CommandMap.cs index bcff800d3..141ec6fdf 100644 --- a/src/Discord.Net.Commands/Map/CommandMap.cs +++ b/src/Discord.Net.Commands/Map/CommandMap.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; namespace Discord.Commands { @@ -6,7 +6,7 @@ namespace Discord.Commands { private readonly CommandService _service; private readonly CommandMapNode _root; - private static readonly string[] _blankAliases = new[] { "" }; + private static readonly string[] BlankAliases = { "" }; public CommandMap(CommandService service) { diff --git a/src/Discord.Net.Commands/Map/CommandMapNode.cs b/src/Discord.Net.Commands/Map/CommandMapNode.cs index 863409207..bd3067718 100644 --- a/src/Discord.Net.Commands/Map/CommandMapNode.cs +++ b/src/Discord.Net.Commands/Map/CommandMapNode.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; @@ -7,7 +7,7 @@ namespace Discord.Commands { internal class CommandMapNode { - private static readonly char[] _whitespaceChars = new[] { ' ', '\r', '\n' }; + private static readonly char[] WhitespaceChars = { ' ', '\r', '\n' }; private readonly ConcurrentDictionary _nodes; private readonly string _name; @@ -52,7 +52,6 @@ namespace Discord.Commands public void RemoveCommand(CommandService service, string text, int index, CommandInfo command) { int nextSegment = NextSegment(text, index, service._separatorChar); - string name; lock (_lockObj) { @@ -60,13 +59,13 @@ namespace Discord.Commands _commands = _commands.Remove(command); else { + string name; if (nextSegment == -1) name = text.Substring(index); else name = text.Substring(index, nextSegment - index); - CommandMapNode nextNode; - if (_nodes.TryGetValue(name, out nextNode)) + if (_nodes.TryGetValue(name, out var nextNode)) { nextNode.RemoveCommand(service, nextSegment == -1 ? "" : text, nextSegment + 1, command); if (nextNode.IsEmpty) @@ -100,7 +99,7 @@ namespace Discord.Commands } //Check if this is the last command segment before args - nextSegment = NextSegment(text, index, _whitespaceChars, service._separatorChar); + nextSegment = NextSegment(text, index, WhitespaceChars, service._separatorChar); if (nextSegment != -1) { name = text.Substring(index, nextSegment - index); diff --git a/src/Discord.Net.Commands/PrimitiveParsers.cs b/src/Discord.Net.Commands/PrimitiveParsers.cs index bf0622c28..e9b6aac3f 100644 --- a/src/Discord.Net.Commands/PrimitiveParsers.cs +++ b/src/Discord.Net.Commands/PrimitiveParsers.cs @@ -8,9 +8,9 @@ namespace Discord.Commands internal static class PrimitiveParsers { - private static readonly Lazy> _parsers = new Lazy>(CreateParsers); + private static readonly Lazy> Parsers = new Lazy>(CreateParsers); - public static IEnumerable SupportedTypes = _parsers.Value.Keys; + public static IEnumerable SupportedTypes = Parsers.Value.Keys; static IReadOnlyDictionary CreateParsers() { @@ -34,7 +34,7 @@ namespace Discord.Commands return parserBuilder.ToImmutable(); } - public static TryParseDelegate Get() => (TryParseDelegate)_parsers.Value[typeof(T)]; - public static Delegate Get(Type type) => _parsers.Value[type]; + public static TryParseDelegate Get() => (TryParseDelegate)Parsers.Value[typeof(T)]; + public static Delegate Get(Type type) => Parsers.Value[type]; } } diff --git a/src/Discord.Net.Commands/Readers/TimeSpanTypeReader.cs b/src/Discord.Net.Commands/Readers/TimeSpanTypeReader.cs index 31ab9d821..314fbb322 100644 --- a/src/Discord.Net.Commands/Readers/TimeSpanTypeReader.cs +++ b/src/Discord.Net.Commands/Readers/TimeSpanTypeReader.cs @@ -6,8 +6,7 @@ namespace Discord.Commands { internal class TimeSpanTypeReader : TypeReader { - private static readonly string[] _formats = new[] - { + private static readonly string[] Formats = { "%d'd'%h'h'%m'm'%s's'", //4d3h2m1s "%d'd'%h'h'%m'm'", //4d3h2m "%d'd'%h'h'%s's'", //4d3h 1s @@ -27,7 +26,7 @@ namespace Discord.Commands public override Task ReadAsync(ICommandContext context, string input, IServiceProvider services) { - return (TimeSpan.TryParseExact(input.ToLowerInvariant(), _formats, CultureInfo.InvariantCulture, out var timeSpan)) + 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")); } diff --git a/src/Discord.Net.Commands/Readers/UserTypeReader.cs b/src/Discord.Net.Commands/Readers/UserTypeReader.cs index 425c2ccb7..498a214e4 100644 --- a/src/Discord.Net.Commands/Readers/UserTypeReader.cs +++ b/src/Discord.Net.Commands/Readers/UserTypeReader.cs @@ -71,8 +71,8 @@ namespace Discord.Commands .Where(x => string.Equals(input, (x as IGuildUser)?.Nickname, StringComparison.OrdinalIgnoreCase)) .ForEachAsync(channelUser => AddResult(results, channelUser as T, (channelUser as IGuildUser).Nickname == input ? 0.65f : 0.55f)); - foreach (var guildUser in guildUsers.Where(x => string.Equals(input, (x as IGuildUser).Nickname, StringComparison.OrdinalIgnoreCase))) - AddResult(results, guildUser as T, (guildUser as IGuildUser).Nickname == input ? 0.60f : 0.50f); + foreach (var guildUser in guildUsers.Where(x => string.Equals(input, x.Nickname, StringComparison.OrdinalIgnoreCase))) + AddResult(results, guildUser as T, guildUser.Nickname == input ? 0.60f : 0.50f); } if (results.Count > 0) diff --git a/src/Discord.Net.Commands/Results/ParseResult.cs b/src/Discord.Net.Commands/Results/ParseResult.cs index d4a9af521..3a0692b2d 100644 --- a/src/Discord.Net.Commands/Results/ParseResult.cs +++ b/src/Discord.Net.Commands/Results/ParseResult.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Diagnostics; namespace Discord.Commands @@ -53,6 +54,8 @@ namespace Discord.Commands public static ParseResult FromError(CommandError error, string reason) => new ParseResult(null, null, error, reason); + public static ParseResult FromError(Exception ex) + => FromError(CommandError.Exception, ex.Message); public static ParseResult FromError(IResult result) => new ParseResult(null, null, result.Error, result.ErrorReason); diff --git a/src/Discord.Net.Commands/Results/PreconditionGroupResult.cs b/src/Discord.Net.Commands/Results/PreconditionGroupResult.cs index 1d7f29122..ee650600a 100644 --- a/src/Discord.Net.Commands/Results/PreconditionGroupResult.cs +++ b/src/Discord.Net.Commands/Results/PreconditionGroupResult.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Diagnostics; namespace Discord.Commands @@ -18,6 +19,8 @@ namespace Discord.Commands => new PreconditionGroupResult(null, null, null); public static PreconditionGroupResult FromError(string reason, ICollection preconditions) => new PreconditionGroupResult(CommandError.UnmetPrecondition, reason, preconditions); + public static new PreconditionGroupResult FromError(Exception ex) + => new PreconditionGroupResult(CommandError.Exception, ex.Message, null); public static new PreconditionGroupResult FromError(IResult result) //needed? => new PreconditionGroupResult(result.Error, result.ErrorReason, null); diff --git a/src/Discord.Net.Commands/Results/PreconditionResult.cs b/src/Discord.Net.Commands/Results/PreconditionResult.cs index ca65a373e..01fc1a3fd 100644 --- a/src/Discord.Net.Commands/Results/PreconditionResult.cs +++ b/src/Discord.Net.Commands/Results/PreconditionResult.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +using System; +using System.Diagnostics; namespace Discord.Commands { @@ -20,6 +21,8 @@ namespace Discord.Commands => new PreconditionResult(null, null); public static PreconditionResult FromError(string reason) => new PreconditionResult(CommandError.UnmetPrecondition, reason); + public static PreconditionResult FromError(Exception ex) + => new PreconditionResult(CommandError.Exception, ex.Message); public static PreconditionResult FromError(IResult result) => new PreconditionResult(result.Error, result.ErrorReason); diff --git a/src/Discord.Net.Commands/Results/SearchResult.cs b/src/Discord.Net.Commands/Results/SearchResult.cs index 87d900d4d..6a5878ea2 100644 --- a/src/Discord.Net.Commands/Results/SearchResult.cs +++ b/src/Discord.Net.Commands/Results/SearchResult.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Diagnostics; namespace Discord.Commands @@ -26,6 +27,8 @@ namespace Discord.Commands => new SearchResult(text, commands, null, null); public static SearchResult FromError(CommandError error, string reason) => new SearchResult(null, null, error, reason); + public static SearchResult FromError(Exception ex) + => FromError(CommandError.Exception, ex.Message); public static SearchResult FromError(IResult result) => new SearchResult(null, null, result.Error, result.ErrorReason); diff --git a/src/Discord.Net.Commands/Results/TypeReaderResult.cs b/src/Discord.Net.Commands/Results/TypeReaderResult.cs index 639ca3ac1..e696dbc17 100644 --- a/src/Discord.Net.Commands/Results/TypeReaderResult.cs +++ b/src/Discord.Net.Commands/Results/TypeReaderResult.cs @@ -50,6 +50,8 @@ namespace Discord.Commands => new TypeReaderResult(values, null, null); public static TypeReaderResult FromError(CommandError error, string reason) => new TypeReaderResult(null, error, reason); + public static TypeReaderResult FromError(Exception ex) + => FromError(CommandError.Exception, ex.Message); public static TypeReaderResult FromError(IResult result) => new TypeReaderResult(null, result.Error, result.ErrorReason); diff --git a/src/Discord.Net.Commands/Utilities/ReflectionUtils.cs b/src/Discord.Net.Commands/Utilities/ReflectionUtils.cs index 30dd7c36b..ec981cf52 100644 --- a/src/Discord.Net.Commands/Utilities/ReflectionUtils.cs +++ b/src/Discord.Net.Commands/Utilities/ReflectionUtils.cs @@ -8,7 +8,7 @@ namespace Discord.Commands { internal static class ReflectionUtils { - private static readonly TypeInfo _objectTypeInfo = typeof(object).GetTypeInfo(); + private static readonly TypeInfo ObjectTypeInfo = typeof(object).GetTypeInfo(); internal static T CreateObject(TypeInfo typeInfo, CommandService commands, IServiceProvider services = null) => CreateBuilder(typeInfo, commands)(services); @@ -54,7 +54,7 @@ namespace Discord.Commands private static System.Reflection.PropertyInfo[] GetProperties(TypeInfo ownerType) { var result = new List(); - while (ownerType != _objectTypeInfo) + while (ownerType != ObjectTypeInfo) { foreach (var prop in ownerType.DeclaredProperties) { diff --git a/src/Discord.Net.Core/Entities/AuditLogs/IAuditLogEntry.cs b/src/Discord.Net.Core/Entities/AuditLogs/IAuditLogEntry.cs index b85730a1d..150c59a42 100644 --- a/src/Discord.Net.Core/Entities/AuditLogs/IAuditLogEntry.cs +++ b/src/Discord.Net.Core/Entities/AuditLogs/IAuditLogEntry.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -9,7 +9,7 @@ namespace Discord /// /// Represents an entry in an audit log /// - public interface IAuditLogEntry : IEntity + public interface IAuditLogEntry : ISnowflakeEntity { /// /// The action which occured to create this entry diff --git a/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs b/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs index 04f4f6884..7e288ef6b 100644 --- a/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs +++ b/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs @@ -239,7 +239,7 @@ namespace Discord get => _name; set { - if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException($"Field name must not be null, empty or entirely whitespace.", nameof(Name)); + if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException("Field name must not be null, empty or entirely whitespace.", nameof(Name)); if (value.Length > MaxFieldNameLength) throw new ArgumentException($"Field name length must be less than or equal to {MaxFieldNameLength}.", nameof(Name)); _name = value; } @@ -251,7 +251,7 @@ namespace Discord set { var stringValue = value?.ToString(); - if (string.IsNullOrEmpty(stringValue)) throw new ArgumentException($"Field value must not be null or empty.", nameof(Value)); + if (string.IsNullOrEmpty(stringValue)) throw new ArgumentException("Field value must not be null or empty.", nameof(Value)); if (stringValue.Length > MaxFieldValueLength) throw new ArgumentException($"Field value length must be less than or equal to {MaxFieldValueLength}.", nameof(Value)); _value = stringValue; } diff --git a/src/Discord.Net.Core/Entities/Messages/EmbedImage.cs b/src/Discord.Net.Core/Entities/Messages/EmbedImage.cs index f21d42c0c..e12ffc53f 100644 --- a/src/Discord.Net.Core/Entities/Messages/EmbedImage.cs +++ b/src/Discord.Net.Core/Entities/Messages/EmbedImage.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; namespace Discord @@ -20,6 +20,6 @@ namespace Discord } private string DebuggerDisplay => $"{Url} ({(Width != null && Height != null ? $"{Width}x{Height}" : "0x0")})"; - public override string ToString() => Url.ToString(); + public override string ToString() => Url; } } diff --git a/src/Discord.Net.Core/Entities/Messages/EmbedThumbnail.cs b/src/Discord.Net.Core/Entities/Messages/EmbedThumbnail.cs index 209a93e37..9b3d6153a 100644 --- a/src/Discord.Net.Core/Entities/Messages/EmbedThumbnail.cs +++ b/src/Discord.Net.Core/Entities/Messages/EmbedThumbnail.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; namespace Discord @@ -20,6 +20,6 @@ namespace Discord } private string DebuggerDisplay => $"{Url} ({(Width != null && Height != null ? $"{Width}x{Height}" : "0x0")})"; - public override string ToString() => Url.ToString(); + public override string ToString() => Url; } } diff --git a/src/Discord.Net.Core/Entities/Messages/EmbedVideo.cs b/src/Discord.Net.Core/Entities/Messages/EmbedVideo.cs index f00681d89..5725e0e14 100644 --- a/src/Discord.Net.Core/Entities/Messages/EmbedVideo.cs +++ b/src/Discord.Net.Core/Entities/Messages/EmbedVideo.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; namespace Discord @@ -18,6 +18,6 @@ namespace Discord } private string DebuggerDisplay => $"{Url} ({(Width != null && Height != null ? $"{Width}x{Height}" : "0x0")})"; - public override string ToString() => Url.ToString(); + public override string ToString() => Url; } } diff --git a/src/Discord.Net.Core/Entities/Roles/Color.cs b/src/Discord.Net.Core/Entities/Roles/Color.cs index 0bb04d339..727049dcc 100644 --- a/src/Discord.Net.Core/Entities/Roles/Color.cs +++ b/src/Discord.Net.Core/Entities/Roles/Color.cs @@ -100,6 +100,17 @@ namespace Discord (uint)(b * 255.0f); } + public static bool operator ==(Color lhs, Color rhs) + => lhs.RawValue == rhs.RawValue; + + public static bool operator !=(Color lhs, Color rhs) + => lhs.RawValue != rhs.RawValue; + + public override bool Equals(object obj) + => (obj is Color c && RawValue == c.RawValue); + + public override int GetHashCode() => RawValue.GetHashCode(); + #if NETSTANDARD2_0 || NET45 public static implicit operator StandardColor(Color color) => StandardColor.FromArgb((int)color.RawValue); diff --git a/src/Discord.Net.Core/Extensions/DiscordClientExtensions.cs b/src/Discord.Net.Core/Extensions/DiscordClientExtensions.cs index ff3c7caf7..81cd10b49 100644 --- a/src/Discord.Net.Core/Extensions/DiscordClientExtensions.cs +++ b/src/Discord.Net.Core/Extensions/DiscordClientExtensions.cs @@ -12,12 +12,12 @@ namespace Discord public static async Task GetDMChannelAsync(this IDiscordClient client, ulong id) => await client.GetPrivateChannelAsync(id).ConfigureAwait(false) as IDMChannel; public static async Task> GetDMChannelsAsync(this IDiscordClient client) - => (await client.GetPrivateChannelsAsync().ConfigureAwait(false)).Select(x => x as IDMChannel).Where(x => x != null); + => (await client.GetPrivateChannelsAsync().ConfigureAwait(false)).OfType(); public static async Task GetGroupChannelAsync(this IDiscordClient client, ulong id) => await client.GetPrivateChannelAsync(id).ConfigureAwait(false) as IGroupChannel; public static async Task> GetGroupChannelsAsync(this IDiscordClient client) - => (await client.GetPrivateChannelsAsync().ConfigureAwait(false)).Select(x => x as IGroupChannel).Where(x => x != null); + => (await client.GetPrivateChannelsAsync().ConfigureAwait(false)).OfType(); public static async Task GetOptimalVoiceRegionAsync(this IDiscordClient discord) { diff --git a/src/Discord.Net.Core/Format.cs b/src/Discord.Net.Core/Format.cs index aa822f99e..414e00a29 100644 --- a/src/Discord.Net.Core/Format.cs +++ b/src/Discord.Net.Core/Format.cs @@ -1,9 +1,9 @@ -namespace Discord +namespace Discord { public static class Format { // Characters which need escaping - private static string[] SensitiveCharacters = { "\\", "*", "_", "~", "`" }; + private static readonly string[] SensitiveCharacters = { "\\", "*", "_", "~", "`" }; /// Returns a markdown-formatted string with bold formatting. public static string Bold(string text) => $"**{text}**"; diff --git a/src/Discord.Net.Core/Utils/MentionUtils.cs b/src/Discord.Net.Core/Utils/MentionUtils.cs index 6c69827b4..f2afe497a 100644 --- a/src/Discord.Net.Core/Utils/MentionUtils.cs +++ b/src/Discord.Net.Core/Utils/MentionUtils.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Globalization; using System.Text; @@ -139,22 +139,22 @@ namespace Discord if (user != null) return $"@{guildUser?.Nickname ?? user?.Username}"; else - return $""; + return ""; case TagHandling.NameNoPrefix: if (user != null) return $"{guildUser?.Nickname ?? user?.Username}"; else - return $""; + return ""; case TagHandling.FullName: if (user != null) return $"@{user.Username}#{user.Discriminator}"; else - return $""; + return ""; case TagHandling.FullNameNoPrefix: if (user != null) return $"{user.Username}#{user.Discriminator}"; else - return $""; + return ""; case TagHandling.Sanitize: if (guildUser != null && guildUser.Nickname == null) return MentionUser($"{SanitizeChar}{tag.Key}", false); @@ -176,13 +176,13 @@ namespace Discord if (channel != null) return $"#{channel.Name}"; else - return $""; + return ""; case TagHandling.NameNoPrefix: case TagHandling.FullNameNoPrefix: if (channel != null) return $"{channel.Name}"; else - return $""; + return ""; case TagHandling.Sanitize: return MentionChannel($"{SanitizeChar}{tag.Key}"); } @@ -201,13 +201,13 @@ namespace Discord if (role != null) return $"@{role.Name}"; else - return $""; + return ""; case TagHandling.NameNoPrefix: case TagHandling.FullNameNoPrefix: if (role != null) return $"{role.Name}"; else - return $""; + return ""; case TagHandling.Sanitize: return MentionRole($"{SanitizeChar}{tag.Key}"); } diff --git a/src/Discord.Net.Core/Utils/Paging/PagedEnumerator.cs b/src/Discord.Net.Core/Utils/Paging/PagedEnumerator.cs index 96059bb4f..a31721875 100644 --- a/src/Discord.Net.Core/Utils/Paging/PagedEnumerator.cs +++ b/src/Discord.Net.Core/Utils/Paging/PagedEnumerator.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -60,7 +60,7 @@ namespace Discord if (Current.Count == 0) _info.Remaining = 0; } - _info.PageSize = _info.Remaining != null ? (int)Math.Min(_info.Remaining.Value, _source.PageSize) : _source.PageSize; + _info.PageSize = _info.Remaining != null ? Math.Min(_info.Remaining.Value, _source.PageSize) : _source.PageSize; if (_info.Remaining != 0) { @@ -74,4 +74,4 @@ namespace Discord public void Dispose() { Current = null; } } } -} \ No newline at end of file +} diff --git a/src/Discord.Net.Core/Utils/Permissions.cs b/src/Discord.Net.Core/Utils/Permissions.cs index 04e6784c3..6e7125ab7 100644 --- a/src/Discord.Net.Core/Utils/Permissions.cs +++ b/src/Discord.Net.Core/Utils/Permissions.cs @@ -1,4 +1,4 @@ -using System.Runtime.CompilerServices; +using System.Runtime.CompilerServices; namespace Discord { @@ -119,13 +119,11 @@ namespace Discord resolvedPermissions = mask; //Owners and administrators always have all permissions else { - OverwritePermissions? perms; - //Start with this user's guild permissions resolvedPermissions = guildPermissions; //Give/Take Everyone permissions - perms = channel.GetPermissionOverwrite(guild.EveryoneRole); + var perms = channel.GetPermissionOverwrite(guild.EveryoneRole); if (perms != null) resolvedPermissions = (resolvedPermissions & ~perms.Value.DenyValue) | perms.Value.AllowValue; @@ -133,7 +131,7 @@ namespace Discord ulong deniedPermissions = 0UL, allowedPermissions = 0UL; foreach (var roleId in user.RoleIds) { - IRole role = null; + IRole role; if (roleId != guild.EveryoneRole.Id && (role = guild.GetRole(roleId)) != null) { perms = channel.GetPermissionOverwrite(role); @@ -151,7 +149,7 @@ namespace Discord if (perms != null) resolvedPermissions = (resolvedPermissions & ~perms.Value.DenyValue) | perms.Value.AllowValue; - if (channel is ITextChannel textChannel) + if (channel is ITextChannel) { if (!GetValue(resolvedPermissions, ChannelPermission.ViewChannel)) { diff --git a/src/Discord.Net.Core/Utils/Preconditions.cs b/src/Discord.Net.Core/Utils/Preconditions.cs index 300f584e4..1a297a6a1 100644 --- a/src/Discord.Net.Core/Utils/Preconditions.cs +++ b/src/Discord.Net.Core/Utils/Preconditions.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace Discord { @@ -198,7 +198,7 @@ namespace Discord for (var i = 0; i < roles.Length; i++) { if (roles[i] == guildId) - throw new ArgumentException($"The everyone role cannot be assigned to a user", name); + throw new ArgumentException("The everyone role cannot be assigned to a user", name); } } } diff --git a/src/Discord.Net.Core/Utils/TokenUtils.cs b/src/Discord.Net.Core/Utils/TokenUtils.cs new file mode 100644 index 000000000..2cc0f1041 --- /dev/null +++ b/src/Discord.Net.Core/Utils/TokenUtils.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + public static class TokenUtils + { + /// + /// Checks the validity of the supplied token of a specific type. + /// + /// The type of token to validate. + /// The token value to validate. + /// Thrown when the supplied token string is null, empty, or contains only whitespace. + /// Thrown when the supplied TokenType or token value is invalid. + public static void ValidateToken(TokenType tokenType, string token) + { + // A Null or WhiteSpace token of any type is invalid. + if (string.IsNullOrWhiteSpace(token)) + throw new ArgumentNullException("A token cannot be null, empty, or contain only whitespace.", nameof(token)); + + switch (tokenType) + { + case TokenType.Webhook: + // no validation is performed on Webhook tokens + break; + case TokenType.Bearer: + // no validation is performed on Bearer tokens + break; + case TokenType.Bot: + // bot tokens are assumed to be at least 59 characters in length + // this value was determined by referencing examples in the discord documentation, and by comparing with + // pre-existing tokens + if (token.Length < 59) + throw new ArgumentException("A Bot token must be at least 59 characters in length.", nameof(token)); + break; + default: + // All unrecognized TokenTypes (including User tokens) are considered to be invalid. + throw new ArgumentException("Unrecognized TokenType.", nameof(token)); + } + } + + } +} diff --git a/src/Discord.Net.Rest/API/Common/AuditLogOptions.cs b/src/Discord.Net.Rest/API/Common/AuditLogOptions.cs index 65b401cce..24141d90c 100644 --- a/src/Discord.Net.Rest/API/Common/AuditLogOptions.cs +++ b/src/Discord.Net.Rest/API/Common/AuditLogOptions.cs @@ -20,7 +20,7 @@ namespace Discord.API [JsonProperty("role_name")] public string OverwriteRoleName { get; set; } [JsonProperty("type")] - public string OverwriteType { get; set; } + public PermissionTarget OverwriteType { get; set; } [JsonProperty("id")] public ulong? OverwriteTargetId { get; set; } } diff --git a/src/Discord.Net.Rest/BaseDiscordClient.cs b/src/Discord.Net.Rest/BaseDiscordClient.cs index f8642b96c..8a3db3e6a 100644 --- a/src/Discord.Net.Rest/BaseDiscordClient.cs +++ b/src/Discord.Net.Rest/BaseDiscordClient.cs @@ -55,11 +55,11 @@ namespace Discord.Rest await _stateLock.WaitAsync().ConfigureAwait(false); try { - await LoginInternalAsync(tokenType, token).ConfigureAwait(false); + await LoginInternalAsync(tokenType, token, validateToken).ConfigureAwait(false); } finally { _stateLock.Release(); } } - private async Task LoginInternalAsync(TokenType tokenType, string token) + private async Task LoginInternalAsync(TokenType tokenType, string token, bool validateToken) { if (_isFirstLogin) { @@ -73,11 +73,26 @@ namespace Discord.Rest try { + // If token validation is enabled, validate the token and let it throw any ArgumentExceptions + // that result from invalid parameters + if (validateToken) + { + try + { + TokenUtils.ValidateToken(tokenType, token); + } + catch (ArgumentException ex) + { + // log these ArgumentExceptions and allow for the client to attempt to log in anyways + await LogManager.WarningAsync("Discord", "A supplied token was invalid", ex).ConfigureAwait(false); + } + } + await ApiClient.LoginAsync(tokenType, token).ConfigureAwait(false); await OnLoginAsync(tokenType, token).ConfigureAwait(false); LoginState = LoginState.LoggedIn; } - catch (Exception) + catch { await LogoutInternalAsync().ConfigureAwait(false); throw; diff --git a/src/Discord.Net.Rest/ClientHelper.cs b/src/Discord.Net.Rest/ClientHelper.cs index d8f481d15..aa99fe005 100644 --- a/src/Discord.Net.Rest/ClientHelper.cs +++ b/src/Discord.Net.Rest/ClientHelper.cs @@ -47,7 +47,7 @@ namespace Discord.Rest public static async Task> GetConnectionsAsync(BaseDiscordClient client, RequestOptions options) { var models = await client.ApiClient.GetMyConnectionsAsync(options).ConfigureAwait(false); - return models.Select(x => RestConnection.Create(x)).ToImmutableArray(); + return models.Select(RestConnection.Create).ToImmutableArray(); } public static async Task GetInviteAsync(BaseDiscordClient client, diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs index 2236dbbf8..f8e3e6f50 100644 --- a/src/Discord.Net.Rest/DiscordRestApiClient.cs +++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs @@ -43,9 +43,11 @@ namespace Discord.API public TokenType AuthTokenType { get; private set; } internal string AuthToken { get; private set; } internal IRestClient RestClient { get; private set; } - internal ulong? CurrentUserId { get; set;} + internal ulong? CurrentUserId { get; set; } - public DiscordRestApiClient(RestClientProvider restClientProvider, string userAgent, RetryMode defaultRetryMode = RetryMode.AlwaysRetry, + internal JsonSerializer Serializer => _serializer; + + public DiscordRestApiClient(RestClientProvider restClientProvider, string userAgent, RetryMode defaultRetryMode = RetryMode.AlwaysRetry, JsonSerializer serializer = null) { _restClientProvider = restClientProvider; @@ -123,7 +125,7 @@ namespace Discord.API LoginState = LoginState.LoggedIn; } - catch (Exception) + catch { await LogoutInternalAsync().ConfigureAwait(false); throw; @@ -235,7 +237,7 @@ namespace Discord.API internal Task SendMultipartAsync(string method, Expression> endpointExpr, IReadOnlyDictionary multipartArgs, BucketIds ids, 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 multipartArgs, + public async Task SendMultipartAsync(string method, string endpoint, IReadOnlyDictionary multipartArgs, string bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null) { options = options ?? new RequestOptions(); @@ -414,7 +416,7 @@ namespace Discord.API var ids = new BucketIds(guildId: guildId); await SendAsync("DELETE", () => $"guilds/{guildId}/members/{userId}/roles/{roleId}", ids, options: options); } - + //Channel Messages public async Task GetChannelMessageAsync(ulong channelId, ulong messageId, RequestOptions options = null) { @@ -490,7 +492,7 @@ namespace Discord.API 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); - + return await SendJsonAsync("POST", () => $"webhooks/{webhookId}/{AuthToken}?wait=true", args, new BucketIds(), clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false); } public async Task UploadFileAsync(ulong channelId, UploadFileParams args, RequestOptions options = null) @@ -737,7 +739,7 @@ namespace Discord.API Preconditions.NotNullOrWhitespace(args.Name, nameof(args.Name)); Preconditions.NotNullOrWhitespace(args.RegionId, nameof(args.RegionId)); options = RequestOptions.CreateOrClone(options); - + return await SendJsonAsync("POST", () => "guilds", args, new BucketIds(), options: options).ConfigureAwait(false); } public async Task DeleteGuildAsync(ulong guildId, RequestOptions options = null) @@ -964,7 +966,7 @@ namespace Discord.API { Preconditions.NotNullOrEmpty(inviteId, nameof(inviteId)); options = RequestOptions.CreateOrClone(options); - + return await SendAsync("DELETE", () => $"invites/{inviteId}", new BucketIds(), options: options).ConfigureAwait(false); } @@ -1163,7 +1165,7 @@ namespace Discord.API int limit = args.Limit.GetValueOrDefault(int.MaxValue); ulong afterGuildId = args.AfterGuildId.GetValueOrDefault(0); - + return await SendAsync>("GET", () => $"users/@me/guilds?limit={limit}&after={afterGuildId}", new BucketIds(), options: options).ConfigureAwait(false); } public async Task GetMyApplicationAsync(RequestOptions options = null) @@ -1263,7 +1265,7 @@ namespace Discord.API Preconditions.NotNull(args, nameof(args)); Preconditions.NotNullOrEmpty(args.Name, nameof(args.Name)); options = RequestOptions.CreateOrClone(options); - + if (AuthTokenType == TokenType.Webhook) return await SendJsonAsync("PATCH", () => $"webhooks/{webhookId}/{AuthToken}", args, new BucketIds(), options: options).ConfigureAwait(false); else @@ -1392,9 +1394,9 @@ namespace Discord.API int argId = int.Parse(format.Substring(leftIndex + 1, rightIndex - leftIndex - 1)); string fieldName = GetFieldName(methodArgs[argId + 1]); - int? mappedId; - - mappedId = BucketIds.GetIndex(fieldName); + + var mappedId = BucketIds.GetIndex(fieldName); + if(!mappedId.HasValue && rightIndex != endIndex && format.Length > rightIndex + 1 && format[rightIndex + 1] == '/') //Ignore the next slash rightIndex++; diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelCreateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelCreateAuditLogData.cs index ef4787295..51e72c414 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelCreateAuditLogData.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelCreateAuditLogData.cs @@ -26,18 +26,16 @@ namespace Discord.Rest var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type"); var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); - var type = typeModel.NewValue.ToObject(); - var name = nameModel.NewValue.ToObject(); + var type = typeModel.NewValue.ToObject(discord.ApiClient.Serializer); + var name = nameModel.NewValue.ToObject(discord.ApiClient.Serializer); foreach (var overwrite in overwritesModel.NewValue) { var deny = overwrite.Value("deny"); - var _type = overwrite.Value("type"); + var permType = overwrite.Value("type"); var id = overwrite.Value("id"); var allow = overwrite.Value("allow"); - PermissionTarget permType = _type == "member" ? PermissionTarget.User : PermissionTarget.Role; - overwrites.Add(new Overwrite(id, permType, new OverwritePermissions(allow, deny))); } diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelDeleteAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelDeleteAuditLogData.cs index 4816ce770..7af5ca10c 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelDeleteAuditLogData.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelDeleteAuditLogData.cs @@ -27,11 +27,11 @@ namespace Discord.Rest var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type"); var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); - var overwrites = overwritesModel.OldValue.ToObject() + var overwrites = overwritesModel.OldValue.ToObject(discord.ApiClient.Serializer) .Select(x => new Overwrite(x.TargetId, x.TargetType, new OverwritePermissions(x.Allow, x.Deny))) .ToList(); - var type = typeModel.OldValue.ToObject(); - var name = nameModel.OldValue.ToObject(); + var type = typeModel.OldValue.ToObject(discord.ApiClient.Serializer); + var name = nameModel.OldValue.ToObject(discord.ApiClient.Serializer); var id = entry.TargetId.Value; return new ChannelDeleteAuditLogData(id, name, type, overwrites.ToReadOnlyCollection()); diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelUpdateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelUpdateAuditLogData.cs index 491cb5717..36fe82084 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelUpdateAuditLogData.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelUpdateAuditLogData.cs @@ -23,14 +23,14 @@ namespace Discord.Rest var bitrateModel = changes.FirstOrDefault(x => x.ChangedProperty == "bitrate"); var userLimitModel = changes.FirstOrDefault(x => x.ChangedProperty == "user_limit"); - string oldName = nameModel?.OldValue?.ToObject(), - newName = nameModel?.NewValue?.ToObject(); - string oldTopic = topicModel?.OldValue?.ToObject(), - newTopic = topicModel?.NewValue?.ToObject(); - int? oldBitrate = bitrateModel?.OldValue?.ToObject(), - newBitrate = bitrateModel?.NewValue?.ToObject(); - int? oldLimit = userLimitModel?.OldValue?.ToObject(), - newLimit = userLimitModel?.NewValue?.ToObject(); + string oldName = nameModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newName = nameModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + string oldTopic = topicModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newTopic = topicModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + int? oldBitrate = bitrateModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newBitrate = bitrateModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + int? oldLimit = userLimitModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newLimit = userLimitModel?.NewValue?.ToObject(discord.ApiClient.Serializer); var before = new ChannelInfo(oldName, oldTopic, oldBitrate, oldLimit); var after = new ChannelInfo(newName, newTopic, newBitrate, newLimit); diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteCreateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteCreateAuditLogData.cs index 5d1ef8463..dac2d90ef 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteCreateAuditLogData.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteCreateAuditLogData.cs @@ -21,7 +21,7 @@ namespace Discord.Rest { var change = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name"); - var emoteName = change.NewValue?.ToObject(); + var emoteName = change.NewValue?.ToObject(discord.ApiClient.Serializer); return new EmoteCreateAuditLogData(entry.TargetId.Value, emoteName); } diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteDeleteAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteDeleteAuditLogData.cs index d0a11191f..73cb31af9 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteDeleteAuditLogData.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteDeleteAuditLogData.cs @@ -17,7 +17,7 @@ namespace Discord.Rest { var change = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name"); - var emoteName = change.OldValue?.ToObject(); + var emoteName = change.OldValue?.ToObject(discord.ApiClient.Serializer); return new EmoteDeleteAuditLogData(entry.TargetId.Value, emoteName); } diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteUpdateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteUpdateAuditLogData.cs index 60020bcaa..84898013d 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteUpdateAuditLogData.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteUpdateAuditLogData.cs @@ -18,8 +18,8 @@ namespace Discord.Rest { var change = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name"); - var newName = change.NewValue?.ToObject(); - var oldName = change.OldValue?.ToObject(); + var newName = change.NewValue?.ToObject(discord.ApiClient.Serializer); + var oldName = change.OldValue?.ToObject(discord.ApiClient.Serializer); return new EmoteUpdateAuditLogData(entry.TargetId.Value, oldName, newName); } diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/GuildUpdateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/GuildUpdateAuditLogData.cs index 08550ed7a..09c1eda18 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/GuildUpdateAuditLogData.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/GuildUpdateAuditLogData.cs @@ -28,26 +28,26 @@ namespace Discord.Rest var mfaLevelModel = changes.FirstOrDefault(x => x.ChangedProperty == "afk_timeout"); var contentFilterModel = changes.FirstOrDefault(x => x.ChangedProperty == "afk_timeout"); - int? oldAfkTimeout = afkTimeoutModel?.OldValue?.ToObject(), - newAfkTimeout = afkTimeoutModel?.NewValue?.ToObject(); - DefaultMessageNotifications? oldDefaultMessageNotifications = defaultMessageNotificationsModel?.OldValue?.ToObject(), - newDefaultMessageNotifications = defaultMessageNotificationsModel?.NewValue?.ToObject(); - ulong? oldAfkChannelId = afkChannelModel?.OldValue?.ToObject(), - newAfkChannelId = afkChannelModel?.NewValue?.ToObject(); - string oldName = nameModel?.OldValue?.ToObject(), - newName = nameModel?.NewValue?.ToObject(); - string oldRegionId = regionIdModel?.OldValue?.ToObject(), - newRegionId = regionIdModel?.NewValue?.ToObject(); - string oldIconHash = iconHashModel?.OldValue?.ToObject(), - newIconHash = iconHashModel?.NewValue?.ToObject(); - VerificationLevel? oldVerificationLevel = verificationLevelModel?.OldValue?.ToObject(), - newVerificationLevel = verificationLevelModel?.NewValue?.ToObject(); - ulong? oldOwnerId = ownerIdModel?.OldValue?.ToObject(), - newOwnerId = ownerIdModel?.NewValue?.ToObject(); - MfaLevel? oldMfaLevel = mfaLevelModel?.OldValue?.ToObject(), - newMfaLevel = mfaLevelModel?.NewValue?.ToObject(); - int? oldContentFilter = contentFilterModel?.OldValue?.ToObject(), - newContentFilter = contentFilterModel?.NewValue?.ToObject(); + int? oldAfkTimeout = afkTimeoutModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newAfkTimeout = afkTimeoutModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + DefaultMessageNotifications? oldDefaultMessageNotifications = defaultMessageNotificationsModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newDefaultMessageNotifications = defaultMessageNotificationsModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + ulong? oldAfkChannelId = afkChannelModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newAfkChannelId = afkChannelModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + string oldName = nameModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newName = nameModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + string oldRegionId = regionIdModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newRegionId = regionIdModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + string oldIconHash = iconHashModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newIconHash = iconHashModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + VerificationLevel? oldVerificationLevel = verificationLevelModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newVerificationLevel = verificationLevelModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + ulong? oldOwnerId = ownerIdModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newOwnerId = ownerIdModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + MfaLevel? oldMfaLevel = mfaLevelModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newMfaLevel = mfaLevelModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + int? oldContentFilter = contentFilterModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newContentFilter = contentFilterModel?.NewValue?.ToObject(discord.ApiClient.Serializer); IUser oldOwner = null; if (oldOwnerId != null) diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteCreateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteCreateAuditLogData.cs index 292715420..1d7f48e93 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteCreateAuditLogData.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteCreateAuditLogData.cs @@ -30,13 +30,13 @@ namespace Discord.Rest var usesModel = changes.FirstOrDefault(x => x.ChangedProperty == "uses"); var maxUsesModel = changes.FirstOrDefault(x => x.ChangedProperty == "max_uses"); - var maxAge = maxAgeModel.NewValue.ToObject(); - var code = codeModel.NewValue.ToObject(); - var temporary = temporaryModel.NewValue.ToObject(); - var inviterId = inviterIdModel.NewValue.ToObject(); - var channelId = channelIdModel.NewValue.ToObject(); - var uses = usesModel.NewValue.ToObject(); - var maxUses = maxUsesModel.NewValue.ToObject(); + var maxAge = maxAgeModel.NewValue.ToObject(discord.ApiClient.Serializer); + var code = codeModel.NewValue.ToObject(discord.ApiClient.Serializer); + var temporary = temporaryModel.NewValue.ToObject(discord.ApiClient.Serializer); + var inviterId = inviterIdModel.NewValue.ToObject(discord.ApiClient.Serializer); + var channelId = channelIdModel.NewValue.ToObject(discord.ApiClient.Serializer); + var uses = usesModel.NewValue.ToObject(discord.ApiClient.Serializer); + var maxUses = maxUsesModel.NewValue.ToObject(discord.ApiClient.Serializer); var inviterInfo = log.Users.FirstOrDefault(x => x.Id == inviterId); var inviter = RestUser.Create(discord, inviterInfo); diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteDeleteAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteDeleteAuditLogData.cs index 1dc6d518b..091285532 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteDeleteAuditLogData.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteDeleteAuditLogData.cs @@ -30,13 +30,13 @@ namespace Discord.Rest var usesModel = changes.FirstOrDefault(x => x.ChangedProperty == "uses"); var maxUsesModel = changes.FirstOrDefault(x => x.ChangedProperty == "max_uses"); - var maxAge = maxAgeModel.OldValue.ToObject(); - var code = codeModel.OldValue.ToObject(); - var temporary = temporaryModel.OldValue.ToObject(); - var inviterId = inviterIdModel.OldValue.ToObject(); - var channelId = channelIdModel.OldValue.ToObject(); - var uses = usesModel.OldValue.ToObject(); - var maxUses = maxUsesModel.OldValue.ToObject(); + var maxAge = maxAgeModel.OldValue.ToObject(discord.ApiClient.Serializer); + var code = codeModel.OldValue.ToObject(discord.ApiClient.Serializer); + var temporary = temporaryModel.OldValue.ToObject(discord.ApiClient.Serializer); + var inviterId = inviterIdModel.OldValue.ToObject(discord.ApiClient.Serializer); + var channelId = channelIdModel.OldValue.ToObject(discord.ApiClient.Serializer); + var uses = usesModel.OldValue.ToObject(discord.ApiClient.Serializer); + var maxUses = maxUsesModel.OldValue.ToObject(discord.ApiClient.Serializer); var inviterInfo = log.Users.FirstOrDefault(x => x.Id == inviterId); var inviter = RestUser.Create(discord, inviterInfo); diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteUpdateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteUpdateAuditLogData.cs index b932cfbfc..35088be98 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteUpdateAuditLogData.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteUpdateAuditLogData.cs @@ -23,16 +23,16 @@ namespace Discord.Rest var channelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "channel_id"); var maxUsesModel = changes.FirstOrDefault(x => x.ChangedProperty == "max_uses"); - int? oldMaxAge = maxAgeModel?.OldValue?.ToObject(), - newMaxAge = maxAgeModel?.NewValue?.ToObject(); - string oldCode = codeModel?.OldValue?.ToObject(), - newCode = codeModel?.NewValue?.ToObject(); - bool? oldTemporary = temporaryModel?.OldValue?.ToObject(), - newTemporary = temporaryModel?.NewValue?.ToObject(); - ulong? oldChannelId = channelIdModel?.OldValue?.ToObject(), - newChannelId = channelIdModel?.NewValue?.ToObject(); - int? oldMaxUses = maxUsesModel?.OldValue?.ToObject(), - newMaxUses = maxUsesModel?.NewValue?.ToObject(); + int? oldMaxAge = maxAgeModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newMaxAge = maxAgeModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + string oldCode = codeModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newCode = codeModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + bool? oldTemporary = temporaryModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newTemporary = temporaryModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + ulong? oldChannelId = channelIdModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newChannelId = channelIdModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + int? oldMaxUses = maxUsesModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newMaxUses = maxUsesModel?.NewValue?.ToObject(discord.ApiClient.Serializer); var before = new InviteInfo(oldMaxAge, oldCode, oldTemporary, oldChannelId, oldMaxUses); var after = new InviteInfo(newMaxAge, newCode, newTemporary, newChannelId, newMaxUses); diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberRoleAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberRoleAuditLogData.cs index 3bcbce440..48adb1833 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberRoleAuditLogData.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberRoleAuditLogData.cs @@ -19,7 +19,7 @@ namespace Discord.Rest { var changes = entry.Changes; - var roleInfos = changes.SelectMany(x => x.NewValue.ToObject(), + var roleInfos = changes.SelectMany(x => x.NewValue.ToObject(discord.ApiClient.Serializer), (model, role) => new { model.ChangedProperty, Role = role }) .Select(x => new MemberRoleEditInfo(x.Role.Name, x.Role.Id, x.ChangedProperty == "$add")) .ToList(); diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberUpdateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberUpdateAuditLogData.cs index 40a3ba681..96d34610e 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberUpdateAuditLogData.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberUpdateAuditLogData.cs @@ -24,14 +24,14 @@ namespace Discord.Rest var muteModel = changes.FirstOrDefault(x => x.ChangedProperty == "mute"); var avatarModel = changes.FirstOrDefault(x => x.ChangedProperty == "avatar_hash"); - string oldNick = nickModel?.OldValue?.ToObject(), - newNick = nickModel?.NewValue?.ToObject(); - bool? oldDeaf = deafModel?.OldValue?.ToObject(), - newDeaf = deafModel?.NewValue?.ToObject(); - bool? oldMute = muteModel?.OldValue?.ToObject(), - newMute = muteModel?.NewValue?.ToObject(); - string oldAvatar = avatarModel?.OldValue?.ToObject(), - newAvatar = avatarModel?.NewValue?.ToObject(); + string oldNick = nickModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newNick = nickModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + bool? oldDeaf = deafModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newDeaf = deafModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + bool? oldMute = muteModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newMute = muteModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + string oldAvatar = avatarModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newAvatar = avatarModel?.NewValue?.ToObject(discord.ApiClient.Serializer); var targetInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId); var user = RestUser.Create(discord, targetInfo); diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteCreateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteCreateAuditLogData.cs index d58488136..b13f4b8fd 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteCreateAuditLogData.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteCreateAuditLogData.cs @@ -19,17 +19,15 @@ namespace Discord.Rest var denyModel = changes.FirstOrDefault(x => x.ChangedProperty == "deny"); var allowModel = changes.FirstOrDefault(x => x.ChangedProperty == "allow"); - var deny = denyModel.NewValue.ToObject(); - var allow = allowModel.NewValue.ToObject(); + var deny = denyModel.NewValue.ToObject(discord.ApiClient.Serializer); + var allow = allowModel.NewValue.ToObject(discord.ApiClient.Serializer); var permissions = new OverwritePermissions(allow, deny); var id = entry.Options.OverwriteTargetId.Value; var type = entry.Options.OverwriteType; - PermissionTarget target = type == "member" ? PermissionTarget.User : PermissionTarget.Role; - - return new OverwriteCreateAuditLogData(new Overwrite(id, target, permissions)); + return new OverwriteCreateAuditLogData(new Overwrite(id, type, permissions)); } public Overwrite Overwrite { get; } diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteDeleteAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteDeleteAuditLogData.cs index 445c2e302..5d5177d9a 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteDeleteAuditLogData.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteDeleteAuditLogData.cs @@ -27,14 +27,12 @@ namespace Discord.Rest var idModel = changes.FirstOrDefault(x => x.ChangedProperty == "id"); var allowModel = changes.FirstOrDefault(x => x.ChangedProperty == "allow"); - var deny = denyModel.OldValue.ToObject(); - var type = typeModel.OldValue.ToObject(); - var id = idModel.OldValue.ToObject(); - var allow = allowModel.OldValue.ToObject(); + var deny = denyModel.OldValue.ToObject(discord.ApiClient.Serializer); + var type = typeModel.OldValue.ToObject(discord.ApiClient.Serializer); + var id = idModel.OldValue.ToObject(discord.ApiClient.Serializer); + var allow = allowModel.OldValue.ToObject(discord.ApiClient.Serializer); - PermissionTarget target = type == "member" ? PermissionTarget.User : PermissionTarget.Role; - - return new OverwriteDeleteAuditLogData(new Overwrite(id, target, new OverwritePermissions(allow, deny))); + return new OverwriteDeleteAuditLogData(new Overwrite(id, type, new OverwritePermissions(allow, deny))); } public Overwrite Overwrite { get; } diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteUpdateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteUpdateAuditLogData.cs index d000146c3..d05e1feff 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteUpdateAuditLogData.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteUpdateAuditLogData.cs @@ -22,17 +22,17 @@ namespace Discord.Rest var denyModel = changes.FirstOrDefault(x => x.ChangedProperty == "deny"); var allowModel = changes.FirstOrDefault(x => x.ChangedProperty == "allow"); - var beforeAllow = allowModel?.OldValue?.ToObject(); - var afterAllow = allowModel?.NewValue?.ToObject(); - var beforeDeny = denyModel?.OldValue?.ToObject(); - var afterDeny = denyModel?.OldValue?.ToObject(); + var beforeAllow = allowModel?.OldValue?.ToObject(discord.ApiClient.Serializer); + var afterAllow = allowModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + var beforeDeny = denyModel?.OldValue?.ToObject(discord.ApiClient.Serializer); + var afterDeny = denyModel?.OldValue?.ToObject(discord.ApiClient.Serializer); var beforePermissions = new OverwritePermissions(beforeAllow ?? 0, beforeDeny ?? 0); var afterPermissions = new OverwritePermissions(afterAllow ?? 0, afterDeny ?? 0); - PermissionTarget target = entry.Options.OverwriteType == "member" ? PermissionTarget.User : PermissionTarget.Role; + var type = entry.Options.OverwriteType; - return new OverwriteUpdateAuditLogData(beforePermissions, afterPermissions, entry.Options.OverwriteTargetId.Value, target); + return new OverwriteUpdateAuditLogData(beforePermissions, afterPermissions, entry.Options.OverwriteTargetId.Value, type); } public OverwritePermissions OldPermissions { get; } diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleCreateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleCreateAuditLogData.cs index dcc1c6ab6..69e72fdb0 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleCreateAuditLogData.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleCreateAuditLogData.cs @@ -23,11 +23,11 @@ namespace Discord.Rest var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); var permissionsModel = changes.FirstOrDefault(x => x.ChangedProperty == "permissions"); - uint? colorRaw = colorModel?.NewValue?.ToObject(); - bool? mentionable = mentionableModel?.NewValue?.ToObject(); - bool? hoist = hoistModel?.NewValue?.ToObject(); - string name = nameModel?.NewValue?.ToObject(); - ulong? permissionsRaw = permissionsModel?.NewValue?.ToObject(); + uint? colorRaw = colorModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + bool? mentionable = mentionableModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + bool? hoist = hoistModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + string name = nameModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + ulong? permissionsRaw = permissionsModel?.NewValue?.ToObject(discord.ApiClient.Serializer); Color? color = null; GuildPermissions? permissions = null; diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleDeleteAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleDeleteAuditLogData.cs index 263909daf..f812567cb 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleDeleteAuditLogData.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleDeleteAuditLogData.cs @@ -23,11 +23,11 @@ namespace Discord.Rest var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); var permissionsModel = changes.FirstOrDefault(x => x.ChangedProperty == "permissions"); - uint? colorRaw = colorModel?.OldValue?.ToObject(); - bool? mentionable = mentionableModel?.OldValue?.ToObject(); - bool? hoist = hoistModel?.OldValue?.ToObject(); - string name = nameModel?.OldValue?.ToObject(); - ulong? permissionsRaw = permissionsModel?.OldValue?.ToObject(); + uint? colorRaw = colorModel?.OldValue?.ToObject(discord.ApiClient.Serializer); + bool? mentionable = mentionableModel?.OldValue?.ToObject(discord.ApiClient.Serializer); + bool? hoist = hoistModel?.OldValue?.ToObject(discord.ApiClient.Serializer); + string name = nameModel?.OldValue?.ToObject(discord.ApiClient.Serializer); + ulong? permissionsRaw = permissionsModel?.OldValue?.ToObject(discord.ApiClient.Serializer); Color? color = null; GuildPermissions? permissions = null; diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleUpdateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleUpdateAuditLogData.cs index b645ef7ae..5cea865f1 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleUpdateAuditLogData.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleUpdateAuditLogData.cs @@ -24,16 +24,16 @@ namespace Discord.Rest var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); var permissionsModel = changes.FirstOrDefault(x => x.ChangedProperty == "permissions"); - uint? oldColorRaw = colorModel?.OldValue?.ToObject(), - newColorRaw = colorModel?.NewValue?.ToObject(); - bool? oldMentionable = mentionableModel?.OldValue?.ToObject(), - newMentionable = mentionableModel?.NewValue?.ToObject(); - bool? oldHoist = hoistModel?.OldValue?.ToObject(), - newHoist = hoistModel?.NewValue?.ToObject(); - string oldName = nameModel?.OldValue?.ToObject(), - newName = nameModel?.NewValue?.ToObject(); - ulong? oldPermissionsRaw = permissionsModel?.OldValue?.ToObject(), - newPermissionsRaw = permissionsModel?.OldValue?.ToObject(); + uint? oldColorRaw = colorModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newColorRaw = colorModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + bool? oldMentionable = mentionableModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newMentionable = mentionableModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + bool? oldHoist = hoistModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newHoist = hoistModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + string oldName = nameModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newName = nameModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + ulong? oldPermissionsRaw = permissionsModel?.OldValue?.ToObject(discord.ApiClient.Serializer), + newPermissionsRaw = permissionsModel?.OldValue?.ToObject(discord.ApiClient.Serializer); Color? oldColor = null, newColor = null; diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookCreateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookCreateAuditLogData.cs index 1ae45fb8c..06932bfc4 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookCreateAuditLogData.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookCreateAuditLogData.cs @@ -23,9 +23,9 @@ namespace Discord.Rest var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type"); var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); - var channelId = channelIdModel.NewValue.ToObject(); - var type = typeModel.NewValue.ToObject(); - var name = nameModel.NewValue.ToObject(); + var channelId = channelIdModel.NewValue.ToObject(discord.ApiClient.Serializer); + var type = typeModel.NewValue.ToObject(discord.ApiClient.Serializer); + var name = nameModel.NewValue.ToObject(discord.ApiClient.Serializer); var webhookInfo = log.Webhooks?.FirstOrDefault(x => x.Id == entry.TargetId); var webhook = RestWebhook.Create(discord, (IGuild)null, webhookInfo); diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookDeleteAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookDeleteAuditLogData.cs index 4133d5dff..8fc4da578 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookDeleteAuditLogData.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookDeleteAuditLogData.cs @@ -29,10 +29,10 @@ namespace Discord.Rest var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); var avatarHashModel = changes.FirstOrDefault(x => x.ChangedProperty == "avatar_hash"); - var channelId = channelIdModel.OldValue.ToObject(); - var type = typeModel.OldValue.ToObject(); - var name = nameModel.OldValue.ToObject(); - var avatarHash = avatarHashModel?.OldValue?.ToObject(); + var channelId = channelIdModel.OldValue.ToObject(discord.ApiClient.Serializer); + var type = typeModel.OldValue.ToObject(discord.ApiClient.Serializer); + var name = nameModel.OldValue.ToObject(discord.ApiClient.Serializer); + var avatarHash = avatarHashModel?.OldValue?.ToObject(discord.ApiClient.Serializer); return new WebhookDeleteAuditLogData(entry.TargetId.Value, channelId, type, name, avatarHash); } diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookUpdateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookUpdateAuditLogData.cs index 54da42a8b..ad7db53e2 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookUpdateAuditLogData.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookUpdateAuditLogData.cs @@ -26,18 +26,18 @@ namespace Discord.Rest var channelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "channel_id"); var avatarHashModel = changes.FirstOrDefault(x => x.ChangedProperty == "avatar_hash"); - var oldName = nameModel?.OldValue?.ToObject(); - var oldChannelId = channelIdModel?.OldValue?.ToObject(); - var oldAvatar = avatarHashModel?.OldValue?.ToObject(); + var oldName = nameModel?.OldValue?.ToObject(discord.ApiClient.Serializer); + var oldChannelId = channelIdModel?.OldValue?.ToObject(discord.ApiClient.Serializer); + var oldAvatar = avatarHashModel?.OldValue?.ToObject(discord.ApiClient.Serializer); var before = new WebhookInfo(oldName, oldChannelId, oldAvatar); - var newName = nameModel?.NewValue?.ToObject(); - var newChannelId = channelIdModel?.NewValue?.ToObject(); - var newAvatar = avatarHashModel?.NewValue?.ToObject(); + var newName = nameModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + var newChannelId = channelIdModel?.NewValue?.ToObject(discord.ApiClient.Serializer); + var newAvatar = avatarHashModel?.NewValue?.ToObject(discord.ApiClient.Serializer); var after = new WebhookInfo(newName, newChannelId, newAvatar); var webhookInfo = log.Webhooks?.FirstOrDefault(x => x.Id == entry.TargetId); - var webhook = RestWebhook.Create(discord, (IGuild)null, webhookInfo); + var webhook = webhookInfo != null ? RestWebhook.Create(discord, (IGuild)null, webhookInfo) : null; return new WebhookUpdateAuditLogData(webhook, before, after); } diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/RestAuditLogEntry.cs b/src/Discord.Net.Rest/Entities/AuditLogs/RestAuditLogEntry.cs index 9e30a5014..d01e964ae 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/RestAuditLogEntry.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/RestAuditLogEntry.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using Model = Discord.API.AuditLog; using EntryModel = Discord.API.AuditLogEntry; @@ -26,6 +27,8 @@ namespace Discord.Rest return new RestAuditLogEntry(discord, fullLog, model, user); } + /// + public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); /// public ActionType Action { get; } /// diff --git a/src/Discord.Net.Rest/Entities/Channels/RestDMChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestDMChannel.cs index 64efcf24b..20a76aaf0 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestDMChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestDMChannel.cs @@ -10,7 +10,7 @@ using Model = Discord.API.Channel; namespace Discord.Rest { [DebuggerDisplay(@"{DebuggerDisplay,nq}")] - public class RestDMChannel : RestChannel, IDMChannel, IRestPrivateChannel, IRestMessageChannel, IUpdateable + public class RestDMChannel : RestChannel, IDMChannel, IRestPrivateChannel, IRestMessageChannel { public RestUser CurrentUser { get; private set; } public RestUser Recipient { get; private set; } diff --git a/src/Discord.Net.Rest/Entities/Channels/RestGroupChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestGroupChannel.cs index 5ac0f2c40..c6b5d6ad0 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestGroupChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestGroupChannel.cs @@ -11,7 +11,7 @@ using Model = Discord.API.Channel; namespace Discord.Rest { [DebuggerDisplay(@"{DebuggerDisplay,nq}")] - public class RestGroupChannel : RestChannel, IGroupChannel, IRestPrivateChannel, IRestMessageChannel, IRestAudioChannel, IUpdateable + public class RestGroupChannel : RestChannel, IGroupChannel, IRestPrivateChannel, IRestMessageChannel, IRestAudioChannel { private string _iconId; private ImmutableDictionary _users; diff --git a/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs index 7355e3673..1dbcf7e9a 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs @@ -7,7 +7,7 @@ using Model = Discord.API.Channel; namespace Discord.Rest { - public class RestGuildChannel : RestChannel, IGuildChannel, IUpdateable + public class RestGuildChannel : RestChannel, IGuildChannel { private ImmutableArray _overwrites; diff --git a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs index 9bf13fa07..e6819e8a4 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs @@ -168,7 +168,7 @@ namespace Discord.Rest public async Task> GetTextChannelsAsync(RequestOptions options = null) { var channels = await GuildHelper.GetChannelsAsync(this, Discord, options).ConfigureAwait(false); - return channels.Select(x => x as RestTextChannel).Where(x => x != null).ToImmutableArray(); + return channels.OfType().ToImmutableArray(); } public async Task GetVoiceChannelAsync(ulong id, RequestOptions options = null) { @@ -178,12 +178,12 @@ namespace Discord.Rest public async Task> GetVoiceChannelsAsync(RequestOptions options = null) { var channels = await GuildHelper.GetChannelsAsync(this, Discord, options).ConfigureAwait(false); - return channels.Select(x => x as RestVoiceChannel).Where(x => x != null).ToImmutableArray(); + return channels.OfType().ToImmutableArray(); } public async Task> GetCategoryChannelsAsync(RequestOptions options = null) { var channels = await GuildHelper.GetChannelsAsync(this, Discord, options).ConfigureAwait(false); - return channels.Select(x => x as RestCategoryChannel).Where(x => x != null).ToImmutableArray(); + return channels.OfType().ToImmutableArray(); } public async Task GetAFKChannelAsync(RequestOptions options = null) diff --git a/src/Discord.Net.Rest/Entities/Guilds/RestUserGuild.cs b/src/Discord.Net.Rest/Entities/Guilds/RestUserGuild.cs index 6bc9cea7a..de5a5f7d9 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/RestUserGuild.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/RestUserGuild.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; using System.Threading.Tasks; using Model = Discord.API.UserGuild; @@ -6,7 +6,7 @@ using Model = Discord.API.UserGuild; namespace Discord.Rest { [DebuggerDisplay(@"{DebuggerDisplay,nq}")] - public class RestUserGuild : RestEntity, ISnowflakeEntity, IUserGuild + public class RestUserGuild : RestEntity, IUserGuild { private string _iconId; diff --git a/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs b/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs index e571f8f73..3c47587cb 100644 --- a/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs +++ b/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; @@ -9,7 +9,7 @@ using Model = Discord.API.GuildMember; namespace Discord.Rest { [DebuggerDisplay(@"{DebuggerDisplay,nq}")] - public class RestGuildUser : RestUser, IGuildUser, IUpdateable + public class RestGuildUser : RestUser, IGuildUser { private long? _joinedAtTicks; private ImmutableArray _roleIds; diff --git a/src/Discord.Net.Rest/Net/DefaultRestClient.cs b/src/Discord.Net.Rest/Net/DefaultRestClient.cs index ec789be59..54fe3b681 100644 --- a/src/Discord.Net.Rest/Net/DefaultRestClient.cs +++ b/src/Discord.Net.Rest/Net/DefaultRestClient.cs @@ -131,14 +131,14 @@ namespace Discord.Net.Rest return new RestResponse(response.StatusCode, headers, stream); } - private static readonly HttpMethod _patch = new HttpMethod("PATCH"); + private static readonly HttpMethod Patch = new HttpMethod("PATCH"); private HttpMethod GetMethod(string method) { switch (method) { case "DELETE": return HttpMethod.Delete; case "GET": return HttpMethod.Get; - case "PATCH": return _patch; + case "PATCH": return Patch; case "POST": return HttpMethod.Post; case "PUT": return HttpMethod.Put; default: throw new ArgumentOutOfRangeException(nameof(method), $"Unknown HttpMethod: {method}"); diff --git a/src/Discord.Net.Rest/Net/Queue/ClientBucket.cs b/src/Discord.Net.Rest/Net/Queue/ClientBucket.cs index f32df1bcf..cd9d8aa54 100644 --- a/src/Discord.Net.Rest/Net/Queue/ClientBucket.cs +++ b/src/Discord.Net.Rest/Net/Queue/ClientBucket.cs @@ -1,4 +1,4 @@ -using System.Collections.Immutable; +using System.Collections.Immutable; namespace Discord.Net.Queue { @@ -9,8 +9,8 @@ namespace Discord.Net.Queue } internal struct ClientBucket { - private static readonly ImmutableDictionary _defsByType; - private static readonly ImmutableDictionary _defsById; + private static readonly ImmutableDictionary DefsByType; + private static readonly ImmutableDictionary DefsById; static ClientBucket() { @@ -23,16 +23,16 @@ namespace Discord.Net.Queue var builder = ImmutableDictionary.CreateBuilder(); foreach (var bucket in buckets) builder.Add(bucket.Type, bucket); - _defsByType = builder.ToImmutable(); + DefsByType = builder.ToImmutable(); var builder2 = ImmutableDictionary.CreateBuilder(); foreach (var bucket in buckets) builder2.Add(bucket.Id, bucket); - _defsById = builder2.ToImmutable(); + DefsById = builder2.ToImmutable(); } - public static ClientBucket Get(ClientBucketType type) => _defsByType[type]; - public static ClientBucket Get(string id) => _defsById[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; } diff --git a/src/Discord.Net.Rest/Net/Queue/RequestQueue.cs b/src/Discord.Net.Rest/Net/Queue/RequestQueue.cs index 943b76359..40b91e98e 100644 --- a/src/Discord.Net.Rest/Net/Queue/RequestQueue.cs +++ b/src/Discord.Net.Rest/Net/Queue/RequestQueue.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; #if DEBUG_LIMITS using System.Diagnostics; @@ -16,10 +16,10 @@ namespace Discord.Net.Queue private readonly ConcurrentDictionary _buckets; private readonly SemaphoreSlim _tokenLock; + private readonly CancellationTokenSource _cancelToken; //Dispose token private CancellationTokenSource _clearToken; private CancellationToken _parentToken; private CancellationToken _requestCancelToken; //Parent token + Clear token - private CancellationTokenSource _cancelToken; //Dispose token private DateTimeOffset _waitUntil; private Task _cleanupTask; @@ -115,7 +115,7 @@ namespace Discord.Net.Queue foreach (var bucket in _buckets.Select(x => x.Value)) { if ((now - bucket.LastAttemptAt).TotalMinutes > 1.0) - _buckets.TryRemove(bucket.Id, out RequestBucket ignored); + _buckets.TryRemove(bucket.Id, out _); } await Task.Delay(60000, _cancelToken.Token); //Runs each minute } diff --git a/src/Discord.Net.Rest/Net/RateLimitInfo.cs b/src/Discord.Net.Rest/Net/RateLimitInfo.cs index a517f290c..d31cc5cdd 100644 --- a/src/Discord.Net.Rest/Net/RateLimitInfo.cs +++ b/src/Discord.Net.Rest/Net/RateLimitInfo.cs @@ -15,7 +15,7 @@ namespace Discord.Net internal RateLimitInfo(Dictionary headers) { IsGlobal = headers.TryGetValue("X-RateLimit-Global", out string temp) && - bool.TryParse(temp, out var isGlobal) ? isGlobal : false; + bool.TryParse(temp, out var isGlobal) && isGlobal; Limit = headers.TryGetValue("X-RateLimit-Limit", out temp) && int.TryParse(temp, out var limit) ? limit : (int?)null; Remaining = headers.TryGetValue("X-RateLimit-Remaining", out temp) && diff --git a/src/Discord.Net.WebSocket/Audio/AudioClient.cs b/src/Discord.Net.WebSocket/Audio/AudioClient.cs index bbb65a298..9f197b5c5 100644 --- a/src/Discord.Net.WebSocket/Audio/AudioClient.cs +++ b/src/Discord.Net.WebSocket/Audio/AudioClient.cs @@ -16,7 +16,7 @@ using System.Collections.Generic; namespace Discord.Audio { //TODO: Add audio reconnecting - internal partial class AudioClient : IAudioClient, IDisposable + internal partial class AudioClient : IAudioClient { internal struct StreamPair { @@ -65,7 +65,7 @@ namespace Discord.Audio ApiClient = new DiscordVoiceAPIClient(guild.Id, Discord.WebSocketProvider, Discord.UdpSocketProvider); ApiClient.SentGatewayMessage += async opCode => await _audioLogger.DebugAsync($"Sent {opCode}").ConfigureAwait(false); - ApiClient.SentDiscovery += async () => await _audioLogger.DebugAsync($"Sent Discovery").ConfigureAwait(false); + ApiClient.SentDiscovery += async () => await _audioLogger.DebugAsync("Sent Discovery").ConfigureAwait(false); //ApiClient.SentData += async bytes => await _audioLogger.DebugAsync($"Sent {bytes} Bytes").ConfigureAwait(false); ApiClient.ReceivedEvent += ProcessMessageAsync; ApiClient.ReceivedPacket += ProcessPacketAsync; @@ -131,7 +131,7 @@ namespace Discord.Audio await keepaliveTask.ConfigureAwait(false); _keepaliveTask = null; - while (_heartbeatTimes.TryDequeue(out long time)) { } + while (_heartbeatTimes.TryDequeue(out _)) { } _lastMessageTime = 0; await ClearInputStreamsAsync().ConfigureAwait(false); @@ -292,7 +292,7 @@ namespace Discord.Audio { if (packet.Length != 70) { - await _audioLogger.DebugAsync($"Malformed Packet").ConfigureAwait(false); + await _audioLogger.DebugAsync("Malformed Packet").ConfigureAwait(false); return; } string ip; @@ -304,7 +304,7 @@ namespace Discord.Audio } catch (Exception ex) { - await _audioLogger.DebugAsync($"Malformed Packet", ex).ConfigureAwait(false); + await _audioLogger.DebugAsync("Malformed Packet", ex).ConfigureAwait(false); return; } @@ -331,7 +331,7 @@ namespace Discord.Audio { if (pair.Key == value) { - int latency = (int)(Environment.TickCount - pair.Value); + int latency = Environment.TickCount - pair.Value; int before = UdpLatency; UdpLatency = latency; @@ -344,7 +344,7 @@ namespace Discord.Audio { if (!RTPReadStream.TryReadSsrc(packet, 0, out var ssrc)) { - await _audioLogger.DebugAsync($"Malformed Frame").ConfigureAwait(false); + await _audioLogger.DebugAsync("Malformed Frame").ConfigureAwait(false); return; } if (!_ssrcMap.TryGetValue(ssrc, out var userId)) @@ -363,7 +363,7 @@ namespace Discord.Audio } catch (Exception ex) { - await _audioLogger.DebugAsync($"Malformed Frame", ex).ConfigureAwait(false); + await _audioLogger.DebugAsync("Malformed Frame", ex).ConfigureAwait(false); return; } //await _audioLogger.DebugAsync($"Received {packet.Length} bytes from user {userId}").ConfigureAwait(false); @@ -372,7 +372,7 @@ namespace Discord.Audio } catch (Exception ex) { - await _audioLogger.WarningAsync($"Failed to process UDP packet", ex).ConfigureAwait(false); + await _audioLogger.WarningAsync("Failed to process UDP packet", ex).ConfigureAwait(false); return; } } diff --git a/src/Discord.Net.WebSocket/Audio/Streams/BufferedWriteStream.cs b/src/Discord.Net.WebSocket/Audio/Streams/BufferedWriteStream.cs index fb302f132..47a7e2809 100644 --- a/src/Discord.Net.WebSocket/Audio/Streams/BufferedWriteStream.cs +++ b/src/Discord.Net.WebSocket/Audio/Streams/BufferedWriteStream.cs @@ -116,7 +116,7 @@ namespace Discord.Audio.Streams timestamp += OpusEncoder.FrameSamplesPerChannel; } #if DEBUG - var _ = _logger?.DebugAsync($"Buffer underrun"); + var _ = _logger?.DebugAsync("Buffer underrun"); #endif } } @@ -140,7 +140,7 @@ namespace Discord.Audio.Streams if (!_bufferPool.TryDequeue(out byte[] buffer)) { #if DEBUG - var _ = _logger?.DebugAsync($"Buffer overflow"); //Should never happen because of the queueLock + var _ = _logger?.DebugAsync("Buffer overflow"); //Should never happen because of the queueLock #endif return; } @@ -149,7 +149,7 @@ namespace Discord.Audio.Streams if (!_isPreloaded && _queuedFrames.Count == _queueLength) { #if DEBUG - var _ = _logger?.DebugAsync($"Preloaded"); + var _ = _logger?.DebugAsync("Preloaded"); #endif _isPreloaded = true; } @@ -169,8 +169,8 @@ namespace Discord.Audio.Streams { do cancelToken.ThrowIfCancellationRequested(); - while (_queuedFrames.TryDequeue(out Frame ignored)); + while (_queuedFrames.TryDequeue(out _)); return Task.Delay(0); } } -} \ No newline at end of file +} diff --git a/src/Discord.Net.WebSocket/ClientState.cs b/src/Discord.Net.WebSocket/ClientState.cs index f07976a0a..a119e5e28 100644 --- a/src/Discord.Net.WebSocket/ClientState.cs +++ b/src/Discord.Net.WebSocket/ClientState.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -72,7 +72,7 @@ namespace Discord.WebSocket switch (channel) { case SocketDMChannel dmChannel: - _dmChannels.TryRemove(dmChannel.Recipient.Id, out var ignored); + _dmChannels.TryRemove(dmChannel.Recipient.Id, out _); break; case SocketGroupChannel groupChannel: _groupChannels.TryRemove(id); diff --git a/src/Discord.Net.WebSocket/DiscordShardedClient.cs b/src/Discord.Net.WebSocket/DiscordShardedClient.cs index a4af5fea3..51a609ba3 100644 --- a/src/Discord.Net.WebSocket/DiscordShardedClient.cs +++ b/src/Discord.Net.WebSocket/DiscordShardedClient.cs @@ -13,11 +13,11 @@ namespace Discord.WebSocket { private readonly DiscordSocketConfig _baseConfig; private readonly SemaphoreSlim _connectionGroupLock; + private readonly Dictionary _shardIdsToIndex; + private readonly bool _automaticShards; private int[] _shardIds; - private Dictionary _shardIdsToIndex; private DiscordSocketClient[] _shards; private int _totalShards; - private bool _automaticShards; /// Gets the estimated round-trip latency, in milliseconds, to the gateway server. public override int Latency { get => GetLatency(); protected set { } } @@ -25,8 +25,8 @@ namespace Discord.WebSocket public override IActivity Activity { get => _shards[0].Activity; protected set { } } internal new DiscordSocketApiClient ApiClient => base.ApiClient as DiscordSocketApiClient; - public override IReadOnlyCollection Guilds => GetGuilds().ToReadOnlyCollection(() => GetGuildCount()); - public override IReadOnlyCollection PrivateChannels => GetPrivateChannels().ToReadOnlyCollection(() => GetPrivateChannelCount()); + public override IReadOnlyCollection Guilds => GetGuilds().ToReadOnlyCollection(GetGuildCount); + public override IReadOnlyCollection PrivateChannels => GetPrivateChannels().ToReadOnlyCollection(GetPrivateChannelCount); public IReadOnlyCollection Shards => _shards; public override IReadOnlyCollection VoiceRegions => _shards[0].VoiceRegions; diff --git a/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs b/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs index 8ae41cc59..d42bd7132 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs @@ -26,9 +26,9 @@ namespace Discord.API public event Func Disconnected { add { _disconnectedEvent.Add(value); } remove { _disconnectedEvent.Remove(value); } } private readonly AsyncEvent> _disconnectedEvent = new AsyncEvent>(); + private readonly bool _isExplicitUrl; private CancellationTokenSource _connectCancelToken; private string _gatewayUrl; - private bool _isExplicitUrl; //Store our decompression streams for zlib shared state private MemoryStream _compressed; diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.cs index c0e41adba..bbc8e041c 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketClient.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketClient.cs @@ -63,9 +63,9 @@ namespace Discord.WebSocket public override IReadOnlyCollection Guilds => State.Guilds; public override IReadOnlyCollection PrivateChannels => State.PrivateChannels; public IReadOnlyCollection DMChannels - => State.PrivateChannels.Select(x => x as SocketDMChannel).Where(x => x != null).ToImmutableArray(); + => State.PrivateChannels.OfType().ToImmutableArray(); public IReadOnlyCollection GroupChannels - => State.PrivateChannels.Select(x => x as SocketGroupChannel).Where(x => x != null).ToImmutableArray(); + => State.PrivateChannels.OfType().ToImmutableArray(); public override IReadOnlyCollection VoiceRegions => _voiceRegions.ToReadOnlyCollection(); /// Creates a new REST/WebSocket discord client. @@ -207,7 +207,7 @@ namespace Discord.WebSocket await heartbeatTask.ConfigureAwait(false); _heartbeatTask = null; - while (_heartbeatTimes.TryDequeue(out long time)) { } + while (_heartbeatTimes.TryDequeue(out _)) { } _lastMessageTime = 0; await _gatewayLogger.DebugAsync("Waiting for guild downloader").ConfigureAwait(false); @@ -218,7 +218,7 @@ namespace Discord.WebSocket //Clear large guild queue await _gatewayLogger.DebugAsync("Clearing large guild queue").ConfigureAwait(false); - while (_largeGuilds.TryDequeue(out ulong guildId)) { } + while (_largeGuilds.TryDequeue(out _)) { } //Raise virtual GUILD_UNAVAILABLEs await _gatewayLogger.DebugAsync("Raising virtual GuildUnavailables").ConfigureAwait(false); @@ -351,7 +351,7 @@ namespace Discord.WebSocket var gameModel = new GameModel(); // Discord only accepts rich presence over RPC, don't even bother building a payload - if (Activity is RichGame game) + if (Activity is RichGame) throw new NotSupportedException("Outgoing Rich Presences are not supported"); if (Activity != null) @@ -508,7 +508,7 @@ namespace Discord.WebSocket { type = "GUILD_AVAILABLE"; _lastGuildAvailableTime = Environment.TickCount; - await _gatewayLogger.DebugAsync($"Received Dispatch (GUILD_AVAILABLE)").ConfigureAwait(false); + await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_AVAILABLE)").ConfigureAwait(false); var guild = State.GetGuild(data.Id); if (guild != null) @@ -533,7 +533,7 @@ namespace Discord.WebSocket } else { - await _gatewayLogger.DebugAsync($"Received Dispatch (GUILD_CREATE)").ConfigureAwait(false); + await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_CREATE)").ConfigureAwait(false); var guild = AddGuild(data, State); if (guild != null) @@ -614,7 +614,7 @@ namespace Discord.WebSocket if (data.Unavailable == true) { type = "GUILD_UNAVAILABLE"; - await _gatewayLogger.DebugAsync($"Received Dispatch (GUILD_UNAVAILABLE)").ConfigureAwait(false); + await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_UNAVAILABLE)").ConfigureAwait(false); var guild = State.GetGuild(data.Id); if (guild != null) @@ -630,7 +630,7 @@ namespace Discord.WebSocket } else { - await _gatewayLogger.DebugAsync($"Received Dispatch (GUILD_DELETE)").ConfigureAwait(false); + await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_DELETE)").ConfigureAwait(false); var guild = RemoveGuild(data.Id); if (guild != null) @@ -1630,7 +1630,7 @@ namespace Discord.WebSocket var guild = State.RemoveGuild(id); if (guild != null) { - foreach (var channel in guild.Channels) + foreach (var _ in guild.Channels) State.RemoveChannel(id); foreach (var user in guild.Users) user.GlobalUser.RemoveRef(this); @@ -1683,7 +1683,7 @@ namespace Discord.WebSocket if (eventHandler.HasSubscribers) { if (HandlerTimeout.HasValue) - await TimeoutWrap(name, () => eventHandler.InvokeAsync()).ConfigureAwait(false); + await TimeoutWrap(name, eventHandler.InvokeAsync).ConfigureAwait(false); else await eventHandler.InvokeAsync().ConfigureAwait(false); } diff --git a/src/Discord.Net.WebSocket/DiscordVoiceApiClient.cs b/src/Discord.Net.WebSocket/DiscordVoiceApiClient.cs index 0eb92caed..80dec0fd4 100644 --- a/src/Discord.Net.WebSocket/DiscordVoiceApiClient.cs +++ b/src/Discord.Net.WebSocket/DiscordVoiceApiClient.cs @@ -39,8 +39,8 @@ namespace Discord.Audio private readonly JsonSerializer _serializer; private readonly SemaphoreSlim _connectionLock; + private readonly IUdpSocket _udp; private CancellationTokenSource _connectCancelToken; - private IUdpSocket _udp; private bool _isDisposed; private ulong _nextKeepalive; @@ -188,7 +188,7 @@ namespace Discord.Audio ConnectionState = ConnectionState.Connected; } - catch (Exception) + catch { await DisconnectInternalAsync().ConfigureAwait(false); throw; diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketDMChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketDMChannel.cs index 11b7ce25a..9a8be9703 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketDMChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketDMChannel.cs @@ -97,7 +97,7 @@ namespace Discord.WebSocket if (id == Recipient.Id) return Recipient; else if (id == Discord.CurrentUser.Id) - return Discord.CurrentUser as SocketSelfUser; + return Discord.CurrentUser; else return null; } diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketGroupChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketGroupChannel.cs index 125625456..74a1e3725 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketGroupChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketGroupChannel.cs @@ -18,10 +18,10 @@ namespace Discord.WebSocket public class SocketGroupChannel : SocketChannel, IGroupChannel, ISocketPrivateChannel, ISocketMessageChannel, ISocketAudioChannel { private readonly MessageCache _messages; + private readonly ConcurrentDictionary _voiceStates; private string _iconId; private ConcurrentDictionary _users; - private ConcurrentDictionary _voiceStates; public string Name { get; private set; } @@ -129,7 +129,7 @@ namespace Discord.WebSocket internal SocketGroupUser GetOrAddUser(UserModel model) { if (_users.TryGetValue(model.Id, out SocketGroupUser user)) - return user as SocketGroupUser; + return user; else { var privateUser = SocketGroupUser.Create(this, Discord.State, model); @@ -143,7 +143,7 @@ namespace Discord.WebSocket if (_users.TryRemove(id, out SocketGroupUser user)) { user.GlobalUser.RemoveRef(Discord); - return user as SocketGroupUser; + return user; } return null; } diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs index f967e6e6a..8e6e09a9f 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs @@ -43,7 +43,7 @@ namespace Discord.WebSocket public Task ModifyAsync(Action func, RequestOptions options = null) => ChannelHelper.ModifyAsync(this, Discord, func, options); - public async Task ConnectAsync(bool selfDeaf, bool selfMute, bool external) + public async Task ConnectAsync(bool selfDeaf = false, bool selfMute = false, bool external = false) { return await Guild.ConnectAudioAsync(Id, selfDeaf, selfMute, external).ConfigureAwait(false); } diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs index bf33ef569..78ea4004a 100644 --- a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs +++ b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs @@ -91,11 +91,11 @@ namespace Discord.WebSocket } } public IReadOnlyCollection TextChannels - => Channels.Select(x => x as SocketTextChannel).Where(x => x != null).ToImmutableArray(); + => Channels.OfType().ToImmutableArray(); public IReadOnlyCollection VoiceChannels - => Channels.Select(x => x as SocketVoiceChannel).Where(x => x != null).ToImmutableArray(); + => Channels.OfType().ToImmutableArray(); public IReadOnlyCollection CategoryChannels - => Channels.Select(x => x as SocketCategoryChannel).Where(x => x != null).ToImmutableArray(); + => Channels.OfType().ToImmutableArray(); public SocketGuildUser CurrentUser => _members.TryGetValue(Discord.CurrentUser.Id, out SocketGuildUser member) ? member : null; public SocketRole EveryoneRole => GetRole(Id); public IReadOnlyCollection Channels @@ -563,7 +563,7 @@ namespace Discord.WebSocket await Discord.ApiClient.SendVoiceStateUpdateAsync(Id, channelId, selfDeaf, selfMute).ConfigureAwait(false); } - catch (Exception) + catch { await DisconnectAudioInternalAsync().ConfigureAwait(false); throw; @@ -580,7 +580,7 @@ namespace Discord.WebSocket throw new TimeoutException(); return await promise.Task.ConfigureAwait(false); } - catch (Exception) + catch { await DisconnectAudioAsync().ConfigureAwait(false); throw; diff --git a/src/Discord.Net.WebSocket/Entities/Messages/MessageCache.cs b/src/Discord.Net.WebSocket/Entities/Messages/MessageCache.cs index c2cad4d86..6ebd0fa1c 100644 --- a/src/Discord.Net.WebSocket/Entities/Messages/MessageCache.cs +++ b/src/Discord.Net.WebSocket/Entities/Messages/MessageCache.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; @@ -28,7 +28,7 @@ namespace Discord.WebSocket _orderedMessages.Enqueue(message.Id); while (_orderedMessages.Count > _size && _orderedMessages.TryDequeue(out ulong msgId)) - _messages.TryRemove(msgId, out SocketMessage msg); + _messages.TryRemove(msgId, out _); } } diff --git a/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs b/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs index f8c15a986..bf817e008 100644 --- a/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs +++ b/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs @@ -12,12 +12,12 @@ namespace Discord.WebSocket [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class SocketUserMessage : SocketMessage, IUserMessage { + private readonly List _reactions = new List(); private bool _isMentioningEveryone, _isTTS, _isPinned; private long? _editedTimestampTicks; private ImmutableArray _attachments; private ImmutableArray _embeds; private ImmutableArray _tags; - private List _reactions = new List(); public override bool IsTTS => _isTTS; public override bool IsPinned => _isPinned; diff --git a/src/Discord.Net.WebSocket/Net/DefaultWebSocketClient.cs b/src/Discord.Net.WebSocket/Net/DefaultWebSocketClient.cs index c60368da0..dc5201ac1 100644 --- a/src/Discord.Net.WebSocket/Net/DefaultWebSocketClient.cs +++ b/src/Discord.Net.WebSocket/Net/DefaultWebSocketClient.cs @@ -22,8 +22,8 @@ namespace Discord.Net.WebSockets private readonly SemaphoreSlim _lock; private readonly Dictionary _headers; + private readonly IWebProxy _proxy; private ClientWebSocket _client; - private IWebProxy _proxy; private Task _task; private CancellationTokenSource _cancelTokenSource; private CancellationToken _cancelToken, _parentToken; diff --git a/test/Discord.Net.Tests/Tests.TokenUtils.cs b/test/Discord.Net.Tests/Tests.TokenUtils.cs new file mode 100644 index 000000000..dc5a93e34 --- /dev/null +++ b/test/Discord.Net.Tests/Tests.TokenUtils.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; + +namespace Discord +{ + public class TokenUtilsTests + { + /// + /// Tests the usage of + /// to see that when a null, empty or whitespace-only string is passed as the token, + /// it will throw an ArgumentNullException. + /// + [Theory] + [InlineData(null)] + [InlineData("")] // string.Empty isn't a constant type + [InlineData(" ")] + [InlineData(" ")] + [InlineData("\t")] + public void TestNullOrWhitespaceToken(string token) + { + // an ArgumentNullException should be thrown, regardless of the TokenType + Assert.Throws(() => TokenUtils.ValidateToken(TokenType.Bearer, token)); + Assert.Throws(() => TokenUtils.ValidateToken(TokenType.Bot, token)); + Assert.Throws(() => TokenUtils.ValidateToken(TokenType.Webhook, token)); + } + + /// + /// Tests the behavior of + /// to see that valid Webhook tokens do not throw Exceptions. + /// + /// + [Theory] + [InlineData("123123123")] + // bot token + [InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs")] + // bearer token taken from discord docs + [InlineData("6qrZcUqja7812RVdnEKjpzOL4CvHBFG")] + // client secret + [InlineData("937it3ow87i4ery69876wqire")] + public void TestWebhookTokenDoesNotThrowExceptions(string token) + { + TokenUtils.ValidateToken(TokenType.Webhook, token); + } + + // No tests for invalid webhook token behavior, because there is nothing there yet. + + /// + /// Tests the behavior of + /// to see that valid Webhook tokens do not throw Exceptions. + /// + /// + [Theory] + [InlineData("123123123")] + // bot token + [InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs")] + // bearer token taken from discord docs + [InlineData("6qrZcUqja7812RVdnEKjpzOL4CvHBFG")] + // client secret + [InlineData("937it3ow87i4ery69876wqire")] + public void TestBearerTokenDoesNotThrowExceptions(string token) + { + TokenUtils.ValidateToken(TokenType.Bearer, token); + } + + // No tests for invalid bearer token behavior, because there is nothing there yet. + + /// + /// Tests the behavior of + /// to see that valid Bot tokens do not throw Exceptions. + /// Valid Bot tokens can be strings of length 59 or above. + /// + [Theory] + [InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs")] + [InlineData("This appears to be completely invalid, however the current validation rules are not very strict.")] + [InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWss")] + [InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWsMTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs")] + public void TestBotTokenDoesNotThrowExceptions(string token) + { + // This example token is pulled from the Discord Docs + // https://discordapp.com/developers/docs/reference#authentication-example-bot-token-authorization-header + // should not throw any exception + TokenUtils.ValidateToken(TokenType.Bot, token); + } + + /// + /// Tests the usage of with + /// a Bot token that is invalid. + /// + [Theory] + [InlineData("This is invalid")] + // missing a single character from the end + [InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKW")] + // bearer token + [InlineData("6qrZcUqja7812RVdnEKjpzOL4CvHBFG")] + // client secret + [InlineData("937it3ow87i4ery69876wqire")] + public void TestBotTokenInvalidThrowsArgumentException(string token) + { + Assert.Throws(() => TokenUtils.ValidateToken(TokenType.Bot, token)); + } + + /// + /// Tests the behavior of + /// to see that an is thrown when an invalid + /// is supplied as a parameter. + /// + /// + /// The type is treated as an invalid . + /// + [Theory] + // TokenType.User + [InlineData(0)] + // out of range TokenType + [InlineData(4)] + [InlineData(7)] + public void TestUnrecognizedTokenType(int type) + { + Assert.Throws(() => + TokenUtils.ValidateToken((TokenType)type, "MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs")); + } + } +}