From 1ee5e6d7716c519e65747d13016798b4c284ec92 Mon Sep 17 00:00:00 2001 From: RogueException Date: Sun, 15 May 2016 02:07:52 -0300 Subject: [PATCH] Explicitly select json converters, added Image and Int53 attributes, fixed a couple of routes. --- src/Discord.Net/API/Common/Overwrite.cs | 4 +- src/Discord.Net/API/Common/Role.cs | 2 +- src/Discord.Net/API/Common/UserGuild.cs | 4 +- src/Discord.Net/API/DiscordRawClient.cs | 22 ++----- src/Discord.Net/API/ImageAttribute.cs | 7 ++ src/Discord.Net/API/Int53Attribute.cs | 7 ++ src/Discord.Net/API/Rest/CreateGuildParams.cs | 2 +- .../API/Rest/ModifyCurrentUserParams.cs | 2 +- src/Discord.Net/API/Rest/ModifyGuildParams.cs | 4 +- src/Discord.Net/Discord.Net.csproj | 4 +- .../Net/Converters/ChannelTypeConverter.cs | 4 +- .../Net/Converters/DiscordContractResolver.cs | 65 +++++++++++++++++++ .../Net/Converters/ImageConverter.cs | 4 +- .../Net/Converters/NullableUInt64Converter.cs | 4 +- .../Converters/OptionalContractResolver.cs | 34 ---------- .../Net/Converters/OptionalConverter.cs | 6 +- .../Converters/PermissionTargetConverter.cs | 4 +- .../Net/Converters/StringEntityConverter.cs | 4 +- .../Net/Converters/UInt64ArrayConverter.cs | 4 +- .../Net/Converters/UInt64Converter.cs | 4 +- .../Net/Converters/UInt64EntityConverter.cs | 7 +- .../Net/Converters/UserStatusConverter.cs | 4 +- 22 files changed, 132 insertions(+), 70 deletions(-) create mode 100644 src/Discord.Net/API/ImageAttribute.cs create mode 100644 src/Discord.Net/API/Int53Attribute.cs create mode 100644 src/Discord.Net/Net/Converters/DiscordContractResolver.cs delete mode 100644 src/Discord.Net/Net/Converters/OptionalContractResolver.cs diff --git a/src/Discord.Net/API/Common/Overwrite.cs b/src/Discord.Net/API/Common/Overwrite.cs index ab9799f71..0d041e163 100644 --- a/src/Discord.Net/API/Common/Overwrite.cs +++ b/src/Discord.Net/API/Common/Overwrite.cs @@ -8,9 +8,9 @@ namespace Discord.API public ulong TargetId { get; set; } [JsonProperty("type")] public PermissionTarget TargetType { get; set; } - [JsonProperty("deny")] + [JsonProperty("deny"), Int53] public ulong Deny { get; set; } - [JsonProperty("allow")] + [JsonProperty("allow"), Int53] public ulong Allow { get; set; } } } diff --git a/src/Discord.Net/API/Common/Role.cs b/src/Discord.Net/API/Common/Role.cs index 55f1933b7..721b2a50b 100644 --- a/src/Discord.Net/API/Common/Role.cs +++ b/src/Discord.Net/API/Common/Role.cs @@ -14,7 +14,7 @@ namespace Discord.API public bool? Hoist { get; set; } [JsonProperty("position")] public int? Position { get; set; } - [JsonProperty("permissions")] + [JsonProperty("permissions"), Int53] public ulong? Permissions { get; set; } [JsonProperty("managed")] public bool? Managed { get; set; } diff --git a/src/Discord.Net/API/Common/UserGuild.cs b/src/Discord.Net/API/Common/UserGuild.cs index 124f64688..7eaefca39 100644 --- a/src/Discord.Net/API/Common/UserGuild.cs +++ b/src/Discord.Net/API/Common/UserGuild.cs @@ -12,7 +12,7 @@ namespace Discord.API public string Icon { get; set; } [JsonProperty("owner")] public bool Owner { get; set; } - [JsonProperty("permissions")] - public uint Permissions { get; set; } + [JsonProperty("permissions"), Int53] + public ulong Permissions { get; set; } } } diff --git a/src/Discord.Net/API/DiscordRawClient.cs b/src/Discord.Net/API/DiscordRawClient.cs index 218964937..64055db84 100644 --- a/src/Discord.Net/API/DiscordRawClient.cs +++ b/src/Discord.Net/API/DiscordRawClient.cs @@ -29,7 +29,7 @@ namespace Discord.API public TokenType AuthTokenType { get; private set; } public IRestClient RestClient { get; private set; } public IRequestQueue RequestQueue { get; private set; } - + internal DiscordRawClient(RestClientProvider restClientProvider) { _restClient = restClientProvider(DiscordConfig.ClientAPIUrl); @@ -38,18 +38,10 @@ namespace Discord.API _requestQueue = new RequestQueue(_restClient); - _serializer = new JsonSerializer(); - _serializer.Converters.Add(new OptionalConverter()); - _serializer.Converters.Add(new ChannelTypeConverter()); - _serializer.Converters.Add(new ImageConverter()); - _serializer.Converters.Add(new NullableUInt64Converter()); - _serializer.Converters.Add(new PermissionTargetConverter()); - _serializer.Converters.Add(new StringEntityConverter()); - _serializer.Converters.Add(new UInt64ArrayConverter()); - _serializer.Converters.Add(new UInt64Converter()); - _serializer.Converters.Add(new UInt64EntityConverter()); - _serializer.Converters.Add(new UserStatusConverter()); - _serializer.ContractResolver = new OptionalContractResolver(); + _serializer = new JsonSerializer() + { + ContractResolver = new DiscordContractResolver() + }; } public async Task Login(TokenType tokenType, string token, CancellationToken cancelToken) @@ -202,7 +194,7 @@ namespace Discord.API { if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); - return await Send>("GET", $"guild/{guildId}/channels").ConfigureAwait(false); + return await Send>("GET", $"guilds/{guildId}/channels").ConfigureAwait(false); } public async Task CreateGuildChannel(ulong guildId, CreateGuildChannelParams args) { @@ -539,7 +531,7 @@ namespace Discord.API { if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); - return await Send>("GET", $"guild/{guildId}/roles").ConfigureAwait(false); + return await Send>("GET", $"guilds/{guildId}/roles").ConfigureAwait(false); } public async Task CreateGuildRole(ulong guildId) { diff --git a/src/Discord.Net/API/ImageAttribute.cs b/src/Discord.Net/API/ImageAttribute.cs new file mode 100644 index 000000000..c31c6d982 --- /dev/null +++ b/src/Discord.Net/API/ImageAttribute.cs @@ -0,0 +1,7 @@ +using System; + +namespace Discord.API +{ + [AttributeUsage(AttributeTargets.Property)] + public class ImageAttribute : Attribute { } +} diff --git a/src/Discord.Net/API/Int53Attribute.cs b/src/Discord.Net/API/Int53Attribute.cs new file mode 100644 index 000000000..7ac6f5467 --- /dev/null +++ b/src/Discord.Net/API/Int53Attribute.cs @@ -0,0 +1,7 @@ +using System; + +namespace Discord.API +{ + [AttributeUsage(AttributeTargets.Property)] + public class Int53Attribute : Attribute { } +} diff --git a/src/Discord.Net/API/Rest/CreateGuildParams.cs b/src/Discord.Net/API/Rest/CreateGuildParams.cs index dd6e5b8fd..6cf0ed149 100644 --- a/src/Discord.Net/API/Rest/CreateGuildParams.cs +++ b/src/Discord.Net/API/Rest/CreateGuildParams.cs @@ -11,7 +11,7 @@ namespace Discord.API.Rest [JsonProperty("region")] public string Region { get; set; } - [JsonProperty("icon"), JsonConverter(typeof(ImageConverter))] + [JsonProperty("icon"), Image] public Optional Icon { get; set; } } } diff --git a/src/Discord.Net/API/Rest/ModifyCurrentUserParams.cs b/src/Discord.Net/API/Rest/ModifyCurrentUserParams.cs index 64aab3181..a29a9c8b4 100644 --- a/src/Discord.Net/API/Rest/ModifyCurrentUserParams.cs +++ b/src/Discord.Net/API/Rest/ModifyCurrentUserParams.cs @@ -14,7 +14,7 @@ namespace Discord.API.Rest public Optional Password { get; set; } [JsonProperty("new_password")] public Optional NewPassword { get; set; } - [JsonProperty("avatar"), JsonConverter(typeof(ImageConverter))] + [JsonProperty("avatar"), Image] public Optional Avatar { get; set; } } } diff --git a/src/Discord.Net/API/Rest/ModifyGuildParams.cs b/src/Discord.Net/API/Rest/ModifyGuildParams.cs index e92b1f63c..6e7ff2e34 100644 --- a/src/Discord.Net/API/Rest/ModifyGuildParams.cs +++ b/src/Discord.Net/API/Rest/ModifyGuildParams.cs @@ -16,11 +16,11 @@ namespace Discord.API.Rest public Optional AFKChannelId { get; set; } [JsonProperty("afk_timeout")] public Optional AFKTimeout { get; set; } - [JsonProperty("icon"), JsonConverter(typeof(ImageConverter))] + [JsonProperty("icon"), Image] public Optional Icon { get; set; } [JsonProperty("owner_id")] public Optional Owner { get; set; } - [JsonProperty("splash"), JsonConverter(typeof(ImageConverter))] + [JsonProperty("splash"), Image] public Optional Splash { get; set; } } } diff --git a/src/Discord.Net/Discord.Net.csproj b/src/Discord.Net/Discord.Net.csproj index e8fc2649c..f5e9372e3 100644 --- a/src/Discord.Net/Discord.Net.csproj +++ b/src/Discord.Net/Discord.Net.csproj @@ -67,6 +67,7 @@ + @@ -105,7 +106,8 @@ - + + diff --git a/src/Discord.Net/Net/Converters/ChannelTypeConverter.cs b/src/Discord.Net/Net/Converters/ChannelTypeConverter.cs index 95c4479df..48bcbd755 100644 --- a/src/Discord.Net/Net/Converters/ChannelTypeConverter.cs +++ b/src/Discord.Net/Net/Converters/ChannelTypeConverter.cs @@ -5,7 +5,9 @@ namespace Discord.Net.Converters { public class ChannelTypeConverter : JsonConverter { - public override bool CanConvert(Type objectType) => objectType == typeof(ChannelType); + public static readonly ChannelTypeConverter Instance = new ChannelTypeConverter(); + + public override bool CanConvert(Type objectType) => true; public override bool CanRead => true; public override bool CanWrite => true; diff --git a/src/Discord.Net/Net/Converters/DiscordContractResolver.cs b/src/Discord.Net/Net/Converters/DiscordContractResolver.cs new file mode 100644 index 000000000..a77d3cf28 --- /dev/null +++ b/src/Discord.Net/Net/Converters/DiscordContractResolver.cs @@ -0,0 +1,65 @@ +using Discord.API; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection; + +namespace Discord.Net.Converters +{ + public class DiscordContractResolver : DefaultContractResolver + { + protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) + { + var property = base.CreateProperty(member, memberSerialization); + var type = property.PropertyType; + JsonConverter converter = null; + + if (member.MemberType == MemberTypes.Property) + { + //Primitives + if (type == typeof(ulong) && member.GetCustomAttribute() == null) + converter = UInt64Converter.Instance; + else if (type == typeof(ulong?) && member.GetCustomAttribute() == null) + converter = NullableUInt64Converter.Instance; + else if (typeof(IEnumerable).IsAssignableFrom(type) && member.GetCustomAttribute() == null) + converter = NullableUInt64Converter.Instance; + + //Enums + else if (type == typeof(ChannelType)) + converter = ChannelTypeConverter.Instance; + else if (type == typeof(PermissionTarget)) + converter = PermissionTargetConverter.Instance; + else if (type == typeof(UserStatus)) + converter = UserStatusConverter.Instance; + + //Entities + else if (typeof(IEntity).IsAssignableFrom(type)) + converter = UInt64EntityConverter.Instance; + else if (typeof(IEntity).IsAssignableFrom(type)) + converter = StringEntityConverter.Instance; + + //Special + else if (type == typeof(string) && member.GetCustomAttribute() != null) + converter = ImageConverter.Instance; + else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Optional<>)) + { + var parentArg = Expression.Parameter(typeof(object)); + var optional = Expression.Property(Expression.Convert(parentArg, property.DeclaringType), member as PropertyInfo); + var isSpecified = Expression.Property(optional, OptionalConverter.IsSpecifiedProperty); + var lambda = Expression.Lambda>(isSpecified, parentArg).Compile(); + property.ShouldSerialize = x => lambda(x); + converter = OptionalConverter.Instance; + } + } + if (converter != null) + { + property.Converter = converter; + property.MemberConverter = converter; + } + + return property; + } + } +} diff --git a/src/Discord.Net/Net/Converters/ImageConverter.cs b/src/Discord.Net/Net/Converters/ImageConverter.cs index 5fc25e8d2..a40b5bf86 100644 --- a/src/Discord.Net/Net/Converters/ImageConverter.cs +++ b/src/Discord.Net/Net/Converters/ImageConverter.cs @@ -7,7 +7,9 @@ namespace Discord.Net.Converters { public class ImageConverter : JsonConverter { - public override bool CanConvert(Type objectType) => objectType == typeof(Stream) || objectType == typeof(Optional); + public static readonly ImageConverter Instance = new ImageConverter(); + + public override bool CanConvert(Type objectType) => true; public override bool CanRead => true; public override bool CanWrite => true; diff --git a/src/Discord.Net/Net/Converters/NullableUInt64Converter.cs b/src/Discord.Net/Net/Converters/NullableUInt64Converter.cs index e28460abc..050ac7c32 100644 --- a/src/Discord.Net/Net/Converters/NullableUInt64Converter.cs +++ b/src/Discord.Net/Net/Converters/NullableUInt64Converter.cs @@ -6,7 +6,9 @@ namespace Discord.Net.Converters { public class NullableUInt64Converter : JsonConverter { - public override bool CanConvert(Type objectType) => objectType == typeof(ulong?); + public static readonly NullableUInt64Converter Instance = new NullableUInt64Converter(); + + public override bool CanConvert(Type objectType) => true; public override bool CanRead => true; public override bool CanWrite => true; diff --git a/src/Discord.Net/Net/Converters/OptionalContractResolver.cs b/src/Discord.Net/Net/Converters/OptionalContractResolver.cs deleted file mode 100644 index cc0705671..000000000 --- a/src/Discord.Net/Net/Converters/OptionalContractResolver.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Discord.API; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; -using System; -using System.Linq.Expressions; -using System.Reflection; - -namespace Discord.Net.Converters -{ - public class OptionalContractResolver : DefaultContractResolver - { - private static readonly PropertyInfo _isSpecified = typeof(IOptional).GetProperty(nameof(IOptional.IsSpecified)); - - protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) - { - var property = base.CreateProperty(member, memberSerialization); - var type = property.PropertyType; - - if (member.MemberType == MemberTypes.Property) - { - if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Optional<>)) - { - var parentArg = Expression.Parameter(typeof(object)); - var optional = Expression.Property(Expression.Convert(parentArg, property.DeclaringType), member as PropertyInfo); - var isSpecified = Expression.Property(optional, _isSpecified); - var lambda = Expression.Lambda>(isSpecified, parentArg).Compile(); - property.ShouldSerialize = x => lambda(x); - } - } - - return property; - } - } -} diff --git a/src/Discord.Net/Net/Converters/OptionalConverter.cs b/src/Discord.Net/Net/Converters/OptionalConverter.cs index e75769e5f..44c670d76 100644 --- a/src/Discord.Net/Net/Converters/OptionalConverter.cs +++ b/src/Discord.Net/Net/Converters/OptionalConverter.cs @@ -1,12 +1,16 @@ using Discord.API; using Newtonsoft.Json; using System; +using System.Reflection; namespace Discord.Net.Converters { public class OptionalConverter : JsonConverter { - public override bool CanConvert(Type objectType) => objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeof(Optional<>); + public static readonly OptionalConverter Instance = new OptionalConverter(); + internal static readonly PropertyInfo IsSpecifiedProperty = typeof(IOptional).GetProperty(nameof(IOptional.IsSpecified)); + + public override bool CanConvert(Type objectType) => true; public override bool CanRead => false; public override bool CanWrite => true; diff --git a/src/Discord.Net/Net/Converters/PermissionTargetConverter.cs b/src/Discord.Net/Net/Converters/PermissionTargetConverter.cs index a7ef55409..6dc74932f 100644 --- a/src/Discord.Net/Net/Converters/PermissionTargetConverter.cs +++ b/src/Discord.Net/Net/Converters/PermissionTargetConverter.cs @@ -5,7 +5,9 @@ namespace Discord.Net.Converters { public class PermissionTargetConverter : JsonConverter { - public override bool CanConvert(Type objectType) => objectType == typeof(PermissionTarget); + public static readonly PermissionTargetConverter Instance = new PermissionTargetConverter(); + + public override bool CanConvert(Type objectType) => true; public override bool CanRead => true; public override bool CanWrite => true; diff --git a/src/Discord.Net/Net/Converters/StringEntityConverter.cs b/src/Discord.Net/Net/Converters/StringEntityConverter.cs index 49c52bd9d..902fb1a75 100644 --- a/src/Discord.Net/Net/Converters/StringEntityConverter.cs +++ b/src/Discord.Net/Net/Converters/StringEntityConverter.cs @@ -5,7 +5,9 @@ namespace Discord.Net.Converters { public class StringEntityConverter : JsonConverter { - public override bool CanConvert(Type objectType) => objectType == typeof(IEntity); + public static readonly StringEntityConverter Instance = new StringEntityConverter(); + + public override bool CanConvert(Type objectType) => true; public override bool CanRead => false; public override bool CanWrite => true; diff --git a/src/Discord.Net/Net/Converters/UInt64ArrayConverter.cs b/src/Discord.Net/Net/Converters/UInt64ArrayConverter.cs index 8e94b51f5..d0a8d170b 100644 --- a/src/Discord.Net/Net/Converters/UInt64ArrayConverter.cs +++ b/src/Discord.Net/Net/Converters/UInt64ArrayConverter.cs @@ -7,7 +7,9 @@ namespace Discord.Net.Converters { public class UInt64ArrayConverter : JsonConverter { - public override bool CanConvert(Type objectType) => objectType == typeof(IEnumerable); + public static readonly UInt64ArrayConverter Instance = new UInt64ArrayConverter(); + + public override bool CanConvert(Type objectType) => true; public override bool CanRead => true; public override bool CanWrite => true; diff --git a/src/Discord.Net/Net/Converters/UInt64Converter.cs b/src/Discord.Net/Net/Converters/UInt64Converter.cs index 4983759ab..6cbcd81f6 100644 --- a/src/Discord.Net/Net/Converters/UInt64Converter.cs +++ b/src/Discord.Net/Net/Converters/UInt64Converter.cs @@ -6,7 +6,9 @@ namespace Discord.Net.Converters { public class UInt64Converter : JsonConverter { - public override bool CanConvert(Type objectType) => objectType == typeof(ulong); + public static readonly UInt64Converter Instance = new UInt64Converter(); + + public override bool CanConvert(Type objectType) => true; public override bool CanRead => true; public override bool CanWrite => true; diff --git a/src/Discord.Net/Net/Converters/UInt64EntityConverter.cs b/src/Discord.Net/Net/Converters/UInt64EntityConverter.cs index 6a0705e3a..8a102ab22 100644 --- a/src/Discord.Net/Net/Converters/UInt64EntityConverter.cs +++ b/src/Discord.Net/Net/Converters/UInt64EntityConverter.cs @@ -1,11 +1,14 @@ using Newtonsoft.Json; using System; +using System.Globalization; namespace Discord.Net.Converters { public class UInt64EntityConverter : JsonConverter { - public override bool CanConvert(Type objectType) => objectType == typeof(IEntity); + public static readonly UInt64EntityConverter Instance = new UInt64EntityConverter(); + + public override bool CanConvert(Type objectType) => true; public override bool CanRead => false; public override bool CanWrite => true; @@ -17,7 +20,7 @@ namespace Discord.Net.Converters public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { if (value != null) - writer.WriteValue((value as IEntity).Id); + writer.WriteValue((value as IEntity).Id.ToString(CultureInfo.InvariantCulture)); else writer.WriteNull(); } diff --git a/src/Discord.Net/Net/Converters/UserStatusConverter.cs b/src/Discord.Net/Net/Converters/UserStatusConverter.cs index 7ed690421..d2c25d3b8 100644 --- a/src/Discord.Net/Net/Converters/UserStatusConverter.cs +++ b/src/Discord.Net/Net/Converters/UserStatusConverter.cs @@ -5,7 +5,9 @@ namespace Discord.Net.Converters { public class UserStatusConverter : JsonConverter { - public override bool CanConvert(Type objectType) => objectType == typeof(UserStatus); + public static readonly UserStatusConverter Instance = new UserStatusConverter(); + + public override bool CanConvert(Type objectType) => true; public override bool CanRead => true; public override bool CanWrite => true;