| @@ -0,0 +1,22 @@ | |||
| using System; | |||
| using System.Reflection; | |||
| namespace Discord.Commands | |||
| { | |||
| [AttributeUsage(AttributeTargets.Parameter)] | |||
| public class OverrideTypeReaderAttribute : Attribute | |||
| { | |||
| private readonly TypeInfo _typeReaderTypeInfo = typeof(TypeReader).GetTypeInfo(); | |||
| public Type TypeReader { get; } | |||
| public OverrideTypeReaderAttribute(Type overridenType) | |||
| { | |||
| if (!_typeReaderTypeInfo.IsAssignableFrom(overridenType.GetTypeInfo())) | |||
| throw new ArgumentException($"{nameof(overridenType)} must inherit from {nameof(TypeReader)}"); | |||
| TypeReader = overridenType; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,11 @@ | |||
| using System; | |||
| using System.Threading.Tasks; | |||
| namespace Discord.Commands | |||
| { | |||
| [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = true)] | |||
| public abstract class ParameterPreconditionAttribute : Attribute | |||
| { | |||
| public abstract Task<PreconditionResult> CheckPermissions(CommandContext context, ParameterInfo parameter, object value); | |||
| } | |||
| } | |||
| @@ -182,6 +182,10 @@ namespace Discord.Commands | |||
| // TODO: C#7 type switch | |||
| if (attribute is SummaryAttribute) | |||
| builder.Summary = (attribute as SummaryAttribute).Text; | |||
| else if (attribute is OverrideTypeReaderAttribute) | |||
| builder.TypeReader = service.GetTypeReader((attribute as OverrideTypeReaderAttribute).TypeReader); | |||
| else if (attribute is ParameterPreconditionAttribute) | |||
| builder.AddPrecondition(attribute as ParameterPreconditionAttribute); | |||
| else if (attribute is ParamArrayAttribute) | |||
| { | |||
| builder.IsMultiple = true; | |||
| @@ -1,10 +1,14 @@ | |||
| using System; | |||
| using System.Reflection; | |||
| using System.Collections.Generic; | |||
| namespace Discord.Commands.Builders | |||
| { | |||
| public class ParameterBuilder | |||
| { | |||
| private readonly List<ParameterPreconditionAttribute> _preconditions; | |||
| public CommandBuilder Command { get; } | |||
| public string Name { get; internal set; } | |||
| public Type ParameterType { get; internal set; } | |||
| @@ -16,16 +20,20 @@ namespace Discord.Commands.Builders | |||
| public object DefaultValue { get; set; } | |||
| public string Summary { get; set; } | |||
| public IReadOnlyList<ParameterPreconditionAttribute> Preconditions => _preconditions; | |||
| //Automatic | |||
| internal ParameterBuilder(CommandBuilder command) | |||
| { | |||
| _preconditions = new List<ParameterPreconditionAttribute>(); | |||
| Command = command; | |||
| } | |||
| //User-defined | |||
| internal ParameterBuilder(CommandBuilder command, string name, Type type) | |||
| : this(command) | |||
| { | |||
| Preconditions.NotNull(name, nameof(name)); | |||
| Discord.Preconditions.NotNull(name, nameof(name)); | |||
| Name = name; | |||
| SetType(type); | |||
| @@ -49,7 +57,7 @@ namespace Discord.Commands.Builders | |||
| } | |||
| public ParameterBuilder WithDefault(object defaultValue) | |||
| { | |||
| DefaultValue = defaultValue; | |||
| DefaultValue = defaultValue; | |||
| return this; | |||
| } | |||
| public ParameterBuilder WithIsOptional(bool isOptional) | |||
| @@ -68,6 +76,12 @@ namespace Discord.Commands.Builders | |||
| return this; | |||
| } | |||
| public ParameterBuilder AddPrecondition(ParameterPreconditionAttribute precondition) | |||
| { | |||
| _preconditions.Add(precondition); | |||
| return this; | |||
| } | |||
| internal ParameterInfo Build(CommandInfo info) | |||
| { | |||
| if (TypeReader == null) | |||
| @@ -135,9 +135,26 @@ namespace Discord.Commands | |||
| if (map == null) | |||
| map = DependencyMap.Empty; | |||
| object[] args = null; | |||
| try | |||
| { | |||
| args = GenerateArgs(argList, paramList); | |||
| } | |||
| catch (Exception ex) | |||
| { | |||
| return ExecuteResult.FromError(ex); | |||
| } | |||
| foreach (var parameter in Parameters) | |||
| { | |||
| var result = await parameter.CheckPreconditionsAsync(context, args, map).ConfigureAwait(false); | |||
| if (!result.IsSuccess) | |||
| return ExecuteResult.FromError(result); | |||
| } | |||
| try | |||
| { | |||
| var args = GenerateArgs(argList, paramList); | |||
| switch (RunMode) | |||
| { | |||
| case RunMode.Sync: //Always sync | |||
| @@ -1,5 +1,7 @@ | |||
| using System; | |||
| using System.Linq; | |||
| using System.Collections.Generic; | |||
| using System.Collections.Immutable; | |||
| using System.Threading.Tasks; | |||
| using Discord.Commands.Builders; | |||
| @@ -10,6 +12,17 @@ namespace Discord.Commands | |||
| { | |||
| private readonly TypeReader _reader; | |||
| public CommandInfo Command { get; } | |||
| public string Name { get; } | |||
| public string Summary { get; } | |||
| public bool IsOptional { get; } | |||
| public bool IsRemainder { get; } | |||
| public bool IsMultiple { get; } | |||
| public Type Type { get; } | |||
| public object DefaultValue { get; } | |||
| public IReadOnlyList<ParameterPreconditionAttribute> Preconditions { get; } | |||
| internal ParameterInfo(ParameterBuilder builder, CommandInfo command, CommandService service) | |||
| { | |||
| Command = command; | |||
| @@ -23,17 +36,30 @@ namespace Discord.Commands | |||
| Type = builder.ParameterType; | |||
| DefaultValue = builder.DefaultValue; | |||
| Preconditions = builder.Preconditions.ToImmutableArray(); | |||
| _reader = builder.TypeReader; | |||
| } | |||
| public CommandInfo Command { get; } | |||
| public string Name { get; } | |||
| public string Summary { get; } | |||
| public bool IsOptional { get; } | |||
| public bool IsRemainder { get; } | |||
| public bool IsMultiple { get; } | |||
| public Type Type { get; } | |||
| public object DefaultValue { get; } | |||
| public async Task<PreconditionResult> CheckPreconditionsAsync(CommandContext context, object[] args, IDependencyMap map = null) | |||
| { | |||
| if (map == null) | |||
| map = DependencyMap.Empty; | |||
| int position = 0; | |||
| for(position = 0; position < Command.Parameters.Count; position++) | |||
| if (Command.Parameters[position] == this) | |||
| break; | |||
| foreach (var precondition in Preconditions) | |||
| { | |||
| var result = await precondition.CheckPermissions(context, this, args[position]).ConfigureAwait(false); | |||
| if (!result.IsSuccess) | |||
| return result; | |||
| } | |||
| return PreconditionResult.FromSuccess(); | |||
| } | |||
| public async Task<TypeReaderResult> Parse(CommandContext context, string input) | |||
| { | |||