From fcb8927fc1a75e2ab23e3939f7a266ce2830365a Mon Sep 17 00:00:00 2001 From: Cenk Ergen <57065323+Cenngo@users.noreply.github.com> Date: Fri, 28 Jan 2022 13:26:48 +0300 Subject: [PATCH] seperate custom id readers with component typeconverters --- .../ComponentCommandParameterBuilder.cs | 2 +- .../CompTypeConverter.cs} | 10 +-- .../Entities/ITypeConverter.cs | 12 +++ .../Entities/ITypeHandler.cs | 9 -- .../Entities/TypeReaderTarget.cs | 11 --- .../Extensions/EnumExtensions.cs | 2 +- .../ComponentCommandParameterInfo.cs | 2 +- .../InteractionService.cs | 84 ++++++------------ src/Discord.Net.Interactions/Map/TypeMap.cs | 17 ++-- .../TypeConverters/TypeConverter.cs | 2 +- .../TypeReaders/ArrayReader.cs | 31 ------- .../TypeReaders/ChannelTypeReader.cs | 54 ------------ .../TypeReaders/EnumTypeReader.cs | 25 ------ .../TypeReaders/MessageTypeReader.cs | 25 ------ .../TypeReaders/NullableTypeReader.cs | 35 -------- .../TypeReaders/RoleTypeReader.cs | 44 ---------- .../TypeReaders/TimeSpanTypeReader.cs | 57 ------------ .../TypeReaders/UserTypeReader.cs | 88 ------------------- 18 files changed, 58 insertions(+), 452 deletions(-) rename src/Discord.Net.Interactions/{TypeReaders/TypeReader.cs => ComponentTypeConverters/CompTypeConverter.cs} (69%) create mode 100644 src/Discord.Net.Interactions/Entities/ITypeConverter.cs delete mode 100644 src/Discord.Net.Interactions/Entities/ITypeHandler.cs delete mode 100644 src/Discord.Net.Interactions/Entities/TypeReaderTarget.cs delete mode 100644 src/Discord.Net.Interactions/TypeReaders/ArrayReader.cs delete mode 100644 src/Discord.Net.Interactions/TypeReaders/ChannelTypeReader.cs delete mode 100644 src/Discord.Net.Interactions/TypeReaders/EnumTypeReader.cs delete mode 100644 src/Discord.Net.Interactions/TypeReaders/MessageTypeReader.cs delete mode 100644 src/Discord.Net.Interactions/TypeReaders/NullableTypeReader.cs delete mode 100644 src/Discord.Net.Interactions/TypeReaders/RoleTypeReader.cs delete mode 100644 src/Discord.Net.Interactions/TypeReaders/TimeSpanTypeReader.cs delete mode 100644 src/Discord.Net.Interactions/TypeReaders/UserTypeReader.cs diff --git a/src/Discord.Net.Interactions/Builders/Parameters/ComponentCommandParameterBuilder.cs b/src/Discord.Net.Interactions/Builders/Parameters/ComponentCommandParameterBuilder.cs index a6a100f46..051772b8b 100644 --- a/src/Discord.Net.Interactions/Builders/Parameters/ComponentCommandParameterBuilder.cs +++ b/src/Discord.Net.Interactions/Builders/Parameters/ComponentCommandParameterBuilder.cs @@ -4,7 +4,7 @@ namespace Discord.Interactions.Builders { public class ComponentCommandParameterBuilder : ParameterBuilder { - public TypeReader TypeReader { get; private set; } + public CompTypeConverter TypeReader { get; private set; } protected override ComponentCommandParameterBuilder Instance => this; public ComponentCommandParameterBuilder(ICommandBuilder command) : base(command) { } diff --git a/src/Discord.Net.Interactions/TypeReaders/TypeReader.cs b/src/Discord.Net.Interactions/ComponentTypeConverters/CompTypeConverter.cs similarity index 69% rename from src/Discord.Net.Interactions/TypeReaders/TypeReader.cs rename to src/Discord.Net.Interactions/ComponentTypeConverters/CompTypeConverter.cs index 62276c973..741287dfe 100644 --- a/src/Discord.Net.Interactions/TypeReaders/TypeReader.cs +++ b/src/Discord.Net.Interactions/ComponentTypeConverters/CompTypeConverter.cs @@ -4,12 +4,12 @@ using System.Threading.Tasks; namespace Discord.Interactions { /// - /// Base class for creating s. uses s to parse string values into entities. + /// Base class for creating s. uses s to parse string values into entities. /// /// - /// s are mainly used to parse message component values. For interfacing with Slash Command parameters use s instead. + /// s are mainly used to parse message component values. For interfacing with Slash Command parameters use s instead. /// - public abstract class TypeReader : ITypeHandler + public abstract class CompTypeConverter : ITypeConverter { /// /// Will be used to search for alternative TypeReaders whenever the Command Service encounters an unknown parameter type. @@ -25,7 +25,7 @@ namespace Discord.Interactions /// Raw string input value. /// Service provider that will be used to initialize the command module. /// The result of the read process. - public abstract Task ReadAsync(IInteractionContext context, object input, IServiceProvider services); + public abstract Task ReadAsync(IInteractionContext context, IComponentInteractionData data, IServiceProvider services); /// /// Will be used to manipulate the outgoing command option, before the command gets registered to Discord. @@ -34,7 +34,7 @@ namespace Discord.Interactions } /// - public abstract class TypeReader : TypeReader + public abstract class CompTypeConverter : CompTypeConverter { /// public sealed override bool CanConvertTo(Type type) => diff --git a/src/Discord.Net.Interactions/Entities/ITypeConverter.cs b/src/Discord.Net.Interactions/Entities/ITypeConverter.cs new file mode 100644 index 000000000..c692b29cb --- /dev/null +++ b/src/Discord.Net.Interactions/Entities/ITypeConverter.cs @@ -0,0 +1,12 @@ +using System; +using System.Threading.Tasks; + +namespace Discord.Interactions +{ + internal interface ITypeConverter + { + public bool CanConvertTo(Type type); + + public Task ReadAsync(IInteractionContext context, T option, IServiceProvider services); + } +} diff --git a/src/Discord.Net.Interactions/Entities/ITypeHandler.cs b/src/Discord.Net.Interactions/Entities/ITypeHandler.cs deleted file mode 100644 index 4626ed850..000000000 --- a/src/Discord.Net.Interactions/Entities/ITypeHandler.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace Discord.Interactions -{ - internal interface ITypeHandler - { - public bool CanConvertTo(Type type); - } -} diff --git a/src/Discord.Net.Interactions/Entities/TypeReaderTarget.cs b/src/Discord.Net.Interactions/Entities/TypeReaderTarget.cs deleted file mode 100644 index 5556b19c2..000000000 --- a/src/Discord.Net.Interactions/Entities/TypeReaderTarget.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace Discord.Interactions -{ - [Flags] - public enum TypeReaderTarget - { - CustomId = 1, - SelectMenu = 2 - } -} diff --git a/src/Discord.Net.Interactions/Extensions/EnumExtensions.cs b/src/Discord.Net.Interactions/Extensions/EnumExtensions.cs index af6bfc85f..182e5b6a6 100644 --- a/src/Discord.Net.Interactions/Extensions/EnumExtensions.cs +++ b/src/Discord.Net.Interactions/Extensions/EnumExtensions.cs @@ -18,7 +18,7 @@ namespace Discord.Interactions (componentType) switch { ComponentType.SelectMenu => TypeReaderTarget.SelectMenu, - _ => throw new InvalidOperationException($"{componentType} isn't supported by {nameof(TypeReader)}s."); + _ => throw new InvalidOperationException($"{componentType} isn't supported by {nameof(CompTypeConverter)}s."); }; } } diff --git a/src/Discord.Net.Interactions/Info/Parameters/ComponentCommandParameterInfo.cs b/src/Discord.Net.Interactions/Info/Parameters/ComponentCommandParameterInfo.cs index 33d529411..a8aa19c33 100644 --- a/src/Discord.Net.Interactions/Info/Parameters/ComponentCommandParameterInfo.cs +++ b/src/Discord.Net.Interactions/Info/Parameters/ComponentCommandParameterInfo.cs @@ -11,7 +11,7 @@ namespace Discord.Interactions /// Gets the that will be used to convert a message component value into /// . /// - public TypeReader TypeReader { get; } + public CompTypeConverter TypeReader { get; } internal ComponentCommandParameterInfo(ComponentCommandParameterBuilder builder, ICommandInfo command) : base(builder, command) { diff --git a/src/Discord.Net.Interactions/InteractionService.cs b/src/Discord.Net.Interactions/InteractionService.cs index 08db2e8f6..8a8ce0716 100644 --- a/src/Discord.Net.Interactions/InteractionService.cs +++ b/src/Discord.Net.Interactions/InteractionService.cs @@ -66,8 +66,8 @@ namespace Discord.Interactions private readonly CommandMap _autocompleteCommandMap; private readonly CommandMap _modalCommandMap; private readonly HashSet _moduleDefs; - private readonly TypeMap _typeConverterMap; - private readonly ConcurrentDictionary> _typeReaderMaps; + private readonly TypeMap _typeConverterMap; + private readonly TypeMap _compTypeConverterMap; private readonly ConcurrentDictionary _autocompleteHandlers = new(); private readonly ConcurrentDictionary _modalInfos = new(); private readonly SemaphoreSlim _lock; @@ -179,7 +179,7 @@ namespace Discord.Interactions _autoServiceScopes = config.AutoServiceScopes; _restResponseCallback = config.RestResponseCallback; - _typeConverterMap = new TypeMap(this, new Dictionary + _typeConverterMap = new TypeMap(this, new Dictionary { [typeof(TimeSpan)] = new TimeSpanConverter() }, new Dictionary @@ -194,7 +194,11 @@ namespace Discord.Interactions [typeof(Nullable<>)] = typeof(NullableConverter<>), }); - _typeReaderMaps = new ConcurrentDictionary>(); + _compTypeConverterMap = new TypeMap(this, new Dictionary + { + }, new Dictionary + { + }); } /// @@ -805,76 +809,44 @@ namespace Discord.Interactions public void AddGenericTypeConverter(Type targetType, Type converterType) => _typeConverterMap.AddGeneric(targetType, converterType); - internal IEnumerable GetTypeReader(Type type, TypeReaderTarget targets, IServiceProvider services = null) - { - var flattenedTargets = targets.GetFlags(); - - foreach (var target in flattenedTargets) - yield return _typeReaderMaps[target].Get(type, services); - } + internal CompTypeConverter GetComponentTypeConverter(Type type, IServiceProvider services = null) => + _compTypeConverterMap.Get(type, services); /// /// Add a concrete type . /// /// Primary target of the . - /// The instance. - public void AddTypeReader(TypeReader reader, TypeReaderTarget targets) - { - var flattenedTargets = targets.GetFlags(); - - foreach (var target in flattenedTargets) - _typeReaderMaps[target].AddConcrete(reader); - } + /// The instance. + public void AddComponentTypeConverter(CompTypeConverter converter) => + AddComponentTypeConverter(typeof(T), converter); /// /// Add a concrete type . /// /// Primary target of the . - /// The instance. - public void AddTypeReader(Type type, TypeReader reader, TypeReaderTarget targets) - { - var flattenedTargets = targets.GetFlags(); - - foreach (var target in flattenedTargets) - _typeReaderMaps[target].AddConcrete(type, reader); - } + /// The instance. + public void AddComponentTypeConverter(Type type, CompTypeConverter converter) => + _compTypeConverterMap.AddConcrete(type, converter); /// - /// Add a generic type . + /// Add a generic type . /// - /// Generic Type constraint of the of the . - /// Type of the . - - public void AddGenericTypeReader(Type readerType, TypeReaderTarget targets) - { - var flattenedTargets = targets.GetFlags(); + /// Generic Type constraint of the of the . + /// Type of the . - foreach (var target in flattenedTargets) - _typeReaderMaps[target].AddGeneric(readerType); - } + public void AddGenericComponentTypeConverter(Type converterType) => + AddGenericComponentTypeConverter(typeof(T), converterType); /// - /// Add a generic type . + /// Add a generic type . /// - /// Generic Type constraint of the of the . - /// Type of the . - public void AddGenericTypeReader(Type targetType, Type readerType, TypeReaderTarget targets) - { - var flattenedTargets = targets.GetFlags(); + /// Generic Type constraint of the of the . + /// Type of the . + public void AddGenericComponentTypeConverter(Type targetType, Type converterType) => + _compTypeConverterMap.AddGeneric(targetType, converterType); - foreach(var target in flattenedTargets) - _typeReaderMaps[target].AddGeneric(targetType, readerType); - } - - public string SerializeWithTypeReader(object obj, TypeReaderTarget targets, IServiceProvider services = null) - { - var flattenedTargets = targets.GetFlags(); - - if (flattenedTargets.Count() != 1) - throw new ArgumentException("Cannot serialize object for multiple targets.", nameof(targets)); - - return _typeReaderMaps[flattenedTargets.First()].Get(typeof(T), services)?.Serialize(obj); - } + public string SerializeWithTypeReader(object obj, IServiceProvider services = null) => + _compTypeConverterMap.Get(typeof(T), services).Serialize(obj); internal IAutocompleteHandler GetAutocompleteHandler(Type autocompleteHandlerType, IServiceProvider services = null) { diff --git a/src/Discord.Net.Interactions/Map/TypeMap.cs b/src/Discord.Net.Interactions/Map/TypeMap.cs index d08423657..092c48627 100644 --- a/src/Discord.Net.Interactions/Map/TypeMap.cs +++ b/src/Discord.Net.Interactions/Map/TypeMap.cs @@ -6,20 +6,21 @@ using System.Reflection; namespace Discord.Interactions { - internal class TypeMap where T : class, ITypeHandler + internal class TypeMap + where TConverter : class, ITypeConverter { - private readonly ConcurrentDictionary _concretes; + private readonly ConcurrentDictionary _concretes; private readonly ConcurrentDictionary _generics; private readonly InteractionService _interactionService; - public TypeMap(InteractionService interactionService, IDictionary concretes = null, IDictionary generics = null) + public TypeMap(InteractionService interactionService, IDictionary concretes = null, IDictionary generics = null) { _interactionService = interactionService; _concretes = concretes is not null ? new(concretes) : new(); _generics = generics is not null ? new(generics) : new(); } - internal T Get(Type type, IServiceProvider services = null) + internal TConverter Get(Type type, IServiceProvider services = null) { if (_concretes.TryGetValue(type, out var specific)) return specific; @@ -30,7 +31,7 @@ namespace Discord.Interactions services ??= EmptyServiceProvider.Instance; var converterType = GetMostSpecific(type); - var converter = ReflectionUtils.CreateObject(converterType.MakeGenericType(type).GetTypeInfo(), _interactionService, services); + var converter = ReflectionUtils.CreateObject(converterType.MakeGenericType(type).GetTypeInfo(), _interactionService, services); _concretes[type] = converter; return converter; } @@ -38,13 +39,13 @@ namespace Discord.Interactions else if (_concretes.Any(x => x.Value.CanConvertTo(type))) return _concretes.First(x => x.Value.CanConvertTo(type)).Value; - throw new ArgumentException($"No type {nameof(T)} is defined for this {type.FullName}", "type"); + throw new ArgumentException($"No type {nameof(TConverter)} is defined for this {type.FullName}", "type"); } - public void AddConcrete(T converter) => + public void AddConcrete(TConverter converter) => AddConcrete(typeof(TTarget), converter); - public void AddConcrete(Type type, T converter) + public void AddConcrete(Type type, TConverter converter) { if (!converter.CanConvertTo(type)) throw new ArgumentException($"This {converter.GetType().FullName} cannot read {type.FullName} and cannot be registered as its {nameof(TypeConverter)}"); diff --git a/src/Discord.Net.Interactions/TypeConverters/TypeConverter.cs b/src/Discord.Net.Interactions/TypeConverters/TypeConverter.cs index 8361831be..09cbc56d4 100644 --- a/src/Discord.Net.Interactions/TypeConverters/TypeConverter.cs +++ b/src/Discord.Net.Interactions/TypeConverters/TypeConverter.cs @@ -6,7 +6,7 @@ namespace Discord.Interactions /// /// Base class for creating TypeConverters. uses TypeConverters to interface with Slash Command parameters. /// - public abstract class TypeConverter : ITypeHandler + public abstract class TypeConverter : ITypeConverter { /// /// Will be used to search for alternative TypeConverters whenever the Command Service encounters an unknown parameter type. diff --git a/src/Discord.Net.Interactions/TypeReaders/ArrayReader.cs b/src/Discord.Net.Interactions/TypeReaders/ArrayReader.cs deleted file mode 100644 index 8cdb17417..000000000 --- a/src/Discord.Net.Interactions/TypeReaders/ArrayReader.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Discord.Interactions -{ - internal class ArrayReader : TypeReader where T : IEnumerable - { - private readonly TypeReader _baseReader; - - public ArrayReader(InteractionService interactionService) - { - if() - - interactionService.GetTypeReader(typeof) - } - - public override TypeReaderTarget[] TypeReaderTargets { get; } - - public override bool CanConvertTo(Type type) => throw new NotImplementedException(); - - public override Task ReadAsync(IInteractionContext context, object input, IServiceProvider services) - { - if(input is IEnumerable enumerable) - return Task.FromResult(TypeConverterResult.FromSuccess(new )) - } - } -} diff --git a/src/Discord.Net.Interactions/TypeReaders/ChannelTypeReader.cs b/src/Discord.Net.Interactions/TypeReaders/ChannelTypeReader.cs deleted file mode 100644 index 93e89587c..000000000 --- a/src/Discord.Net.Interactions/TypeReaders/ChannelTypeReader.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using System.Linq; -using System.Threading.Tasks; - -namespace Discord.Interactions -{ - /// - /// A for parsing objects implementing . - /// - /// - /// This is shipped with Discord.Net and is used by default to parse any - /// implemented object within a command. The TypeReader will attempt to first parse the - /// input by mention, then the snowflake identifier, then by name; the highest candidate will be chosen as the - /// final output; otherwise, an erroneous is returned. - /// - /// The type to be checked; must implement . - internal class ChannelTypeReader : TypeReader where T : class, IChannel - { - /// - public override async Task ReadAsync(IInteractionContext context, object input, IServiceProvider services) - { - if (context.Guild is not null) - { - var str = input as string; - - if (ulong.TryParse(str, out var channelId)) - { - var channel = await context.Guild.GetChannelAsync(channelId).ConfigureAwait(false); - - if(channel is not null) - return TypeConverterResult.FromSuccess(channel as T); - } - - if (MentionUtils.TryParseChannel(str, out channelId)) - { - var channel = await context.Guild.GetChannelAsync(channelId).ConfigureAwait(false); - - if(channel is not null) - return TypeConverterResult.FromSuccess(channel as T); - } - - var channels = await context.Guild.GetChannelsAsync().ConfigureAwait(false); - var nameMatch = channels.FirstOrDefault(x => string.Equals(x.Name, str, StringComparison.OrdinalIgnoreCase)); - - if (nameMatch is not null) - return TypeConverterResult.FromSuccess(nameMatch as T); - } - - return TypeConverterResult.FromError(InteractionCommandError.ConvertFailed, "Channel not found."); - } - - public override string Serialize(object value) => (value as IChannel)?.Id.ToString(); - } -} diff --git a/src/Discord.Net.Interactions/TypeReaders/EnumTypeReader.cs b/src/Discord.Net.Interactions/TypeReaders/EnumTypeReader.cs deleted file mode 100644 index 064b0f329..000000000 --- a/src/Discord.Net.Interactions/TypeReaders/EnumTypeReader.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace Discord.Interactions -{ - internal class EnumTypeReader : TypeReader where T : struct, Enum - { - /// - public override Task ReadAsync(IInteractionContext context, object input, IServiceProvider services) - { - if (Enum.TryParse(input as string, out var result)) - return Task.FromResult(TypeConverterResult.FromSuccess(result)); - else - return Task.FromResult(TypeConverterResult.FromError(InteractionCommandError.ConvertFailed, $"Value {input} cannot be converted to {nameof(T)}")); - } - - public override string Serialize(object value) - { - if (value is not Enum) - throw new ArgumentException($"{value} isn't an {nameof(Enum)}.", nameof(value)); - - return value.ToString(); - } - } -} diff --git a/src/Discord.Net.Interactions/TypeReaders/MessageTypeReader.cs b/src/Discord.Net.Interactions/TypeReaders/MessageTypeReader.cs deleted file mode 100644 index 31db6e075..000000000 --- a/src/Discord.Net.Interactions/TypeReaders/MessageTypeReader.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Globalization; -using System.Threading.Tasks; - -namespace Discord.Interactions -{ - /// - /// A for parsing objects implementing . - /// - /// The type to be checked; must implement . - internal class MessageTypeReader : TypeReader where T : class, IMessage - { - /// - public override async Task ReadAsync(IInteractionContext context, object input, IServiceProvider services) - { - if (ulong.TryParse(input as string, NumberStyles.None, CultureInfo.InvariantCulture, out ulong id)) - { - if (await context.Channel.GetMessageAsync(id, CacheMode.CacheOnly).ConfigureAwait(false) is T msg) - return TypeConverterResult.FromSuccess(msg); - } - - return TypeConverterResult.FromError(InteractionCommandError.ConvertFailed, "Message not found."); - } - } -} diff --git a/src/Discord.Net.Interactions/TypeReaders/NullableTypeReader.cs b/src/Discord.Net.Interactions/TypeReaders/NullableTypeReader.cs deleted file mode 100644 index f68bf6e2c..000000000 --- a/src/Discord.Net.Interactions/TypeReaders/NullableTypeReader.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; - -namespace Discord.Commands -{ - internal static class NullableTypeReader - { - public static TypeReader Create(Type type, TypeReader reader) - { - var constructor = typeof(NullableTypeReader<>).MakeGenericType(type).GetTypeInfo().DeclaredConstructors.First(); - return (TypeReader)constructor.Invoke(new object[] { reader }); - } - } - - internal class NullableTypeReader : TypeReader - where T : struct - { - private readonly TypeReader _baseTypeReader; - - public NullableTypeReader(TypeReader baseTypeReader) - { - _baseTypeReader = baseTypeReader; - } - - /// - public override async Task ReadAsync(ICommandContext context, string input, IServiceProvider services) - { - if (string.Equals(input, "null", StringComparison.OrdinalIgnoreCase) || string.Equals(input, "nothing", StringComparison.OrdinalIgnoreCase)) - return TypeReaderResult.FromSuccess(new T?()); - return await _baseTypeReader.ReadAsync(context, input, services).ConfigureAwait(false); - } - } -} diff --git a/src/Discord.Net.Interactions/TypeReaders/RoleTypeReader.cs b/src/Discord.Net.Interactions/TypeReaders/RoleTypeReader.cs deleted file mode 100644 index 3e3d8c0c1..000000000 --- a/src/Discord.Net.Interactions/TypeReaders/RoleTypeReader.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Linq; -using System.Threading.Tasks; - -namespace Discord.Interactions -{ - /// - /// A for parsing objects implementing . - /// - /// The type to be checked; must implement . - internal class RoleTypeReader : TypeReader where T : class, IRole - { - /// - public override Task ReadAsync(IInteractionContext context, object input, IServiceProvider services) - { - if (context.Guild is not null) - { - if (ulong.TryParse(input as string, out var id)) - { - var role = context.Guild.GetRole(id); - - if (role is not null) - return Task.FromResult(TypeConverterResult.FromSuccess(role as T)); - } - - if (MentionUtils.TryParseRole(input as string, out id)) - { - var role = context.Guild.GetRole(id); - - if (role is not null) - return Task.FromResult(TypeConverterResult.FromSuccess(role as T)); - } - - var channels = context.Guild.Roles; - var nameMatch = channels.First(x => string.Equals(x, input as string)); - - if (nameMatch is not null) - return Task.FromResult(TypeConverterResult.FromSuccess(nameMatch as T)); - } - - return Task.FromResult(TypeConverterResult.FromError(InteractionCommandError.ConvertFailed, "Role not found.")); - } - } -} diff --git a/src/Discord.Net.Interactions/TypeReaders/TimeSpanTypeReader.cs b/src/Discord.Net.Interactions/TypeReaders/TimeSpanTypeReader.cs deleted file mode 100644 index e93665e85..000000000 --- a/src/Discord.Net.Interactions/TypeReaders/TimeSpanTypeReader.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using System.Globalization; -using System.Threading.Tasks; - -namespace Discord.Interactions -{ - internal class TimeSpanTypeReader : TypeReader - { - /// - /// TimeSpan try parse formats. - /// - 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 - "%d'd'%h'h'", // 4d3h - "%d'd'%m'm'%s's'", // 4d 2m1s - "%d'd'%m'm'", // 4d 2m - "%d'd'%s's'", // 4d 1s - "%d'd'", // 4d - "%h'h'%m'm'%s's'", // 3h2m1s - "%h'h'%m'm'", // 3h2m - "%h'h'%s's'", // 3h 1s - "%h'h'", // 3h - "%m'm'%s's'", // 2m1s - "%m'm'", // 2m - "%s's'", // 1s - }; - - /// - public override Task ReadAsync(IInteractionContext context, object input, IServiceProvider services) - { - var str = input as string; - - if (string.IsNullOrEmpty(str)) - throw new ArgumentException($"{nameof(input)} must not be null or empty.", nameof(input)); - - var isNegative = str[0] == '-'; // Char for CultureInfo.InvariantCulture.NumberFormat.NegativeSign - if (isNegative) - { - str = str.Substring(1); - } - - if (TimeSpan.TryParseExact(str.ToLowerInvariant(), Formats, CultureInfo.InvariantCulture, out var timeSpan)) - { - return isNegative - ? Task.FromResult(TypeConverterResult.FromSuccess(-timeSpan)) - : Task.FromResult(TypeConverterResult.FromSuccess(timeSpan)); - } - else - { - return Task.FromResult(TypeConverterResult.FromError(InteractionCommandError.ParseFailed, "Failed to parse TimeSpan")); - } - } - } -} diff --git a/src/Discord.Net.Interactions/TypeReaders/UserTypeReader.cs b/src/Discord.Net.Interactions/TypeReaders/UserTypeReader.cs deleted file mode 100644 index 236d50a3b..000000000 --- a/src/Discord.Net.Interactions/TypeReaders/UserTypeReader.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Globalization; -using System.Linq; -using System.Threading.Tasks; - -namespace Discord.Interactions -{ - /// - /// A for parsing objects implementing . - /// - /// The type to be checked; must implement . - public class UserTypeReader : TypeReader where T : class, IUser - { - /// - public override async Task ReadAsync(IInteractionContext context, string input, IServiceProvider services) - { - var results = new Dictionary(); - IAsyncEnumerable channelUsers = context.Channel.GetUsersAsync(CacheMode.CacheOnly).Flatten(); // it's better - IReadOnlyCollection guildUsers = ImmutableArray.Create(); - - if (context.Guild != null) - guildUsers = await context.Guild.GetUsersAsync(CacheMode.CacheOnly).ConfigureAwait(false); - - //By Mention (1.0) - if (MentionUtils.TryParseUser(input, out var id)) - { - if (context.Guild != null) - AddResult(results, await context.Guild.GetUserAsync(id, CacheMode.CacheOnly).ConfigureAwait(false) as T, 1.00f); - else - AddResult(results, await context.Channel.GetUserAsync(id, CacheMode.CacheOnly).ConfigureAwait(false) as T, 1.00f); - } - - //By Id (0.9) - if (ulong.TryParse(input, NumberStyles.None, CultureInfo.InvariantCulture, out id)) - { - if (context.Guild != null) - AddResult(results, await context.Guild.GetUserAsync(id, CacheMode.CacheOnly).ConfigureAwait(false) as T, 0.90f); - else - AddResult(results, await context.Channel.GetUserAsync(id, CacheMode.CacheOnly).ConfigureAwait(false) as T, 0.90f); - } - - //By Username + Discriminator (0.7-0.85) - int index = input.LastIndexOf('#'); - if (index >= 0) - { - string username = input.Substring(0, index); - if (ushort.TryParse(input.Substring(index + 1), out ushort discriminator)) - { - var channelUser = await channelUsers.FirstOrDefaultAsync(x => x.DiscriminatorValue == discriminator && - string.Equals(username, x.Username, StringComparison.OrdinalIgnoreCase)).ConfigureAwait(false); - AddResult(results, channelUser as T, channelUser?.Username == username ? 0.85f : 0.75f); - - var guildUser = guildUsers.FirstOrDefault(x => x.DiscriminatorValue == discriminator && - string.Equals(username, x.Username, StringComparison.OrdinalIgnoreCase)); - AddResult(results, guildUser as T, guildUser?.Username == username ? 0.80f : 0.70f); - } - } - - //By Username (0.5-0.6) - { - await channelUsers - .Where(x => string.Equals(input, x.Username, StringComparison.OrdinalIgnoreCase)) - .ForEachAsync(channelUser => AddResult(results, channelUser as T, channelUser.Username == input ? 0.65f : 0.55f)) - .ConfigureAwait(false); - - foreach (var guildUser in guildUsers.Where(x => string.Equals(input, x.Username, StringComparison.OrdinalIgnoreCase))) - AddResult(results, guildUser as T, guildUser.Username == input ? 0.60f : 0.50f); - } - - //By Nickname (0.5-0.6) - { - await channelUsers - .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)) - .ConfigureAwait(false); - - 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) - return TypeReaderResult.FromSuccess(results.Values.ToImmutableArray()); - return TypeReaderResult.FromError(CommandError.ObjectNotFound, "User not found."); - } - } -}