Parameter preconditions and typereader overriding

This commit is contained in:
FiniteReality
2016-11-19 15:12:04 +00:00
parent d8c0f0aa4c
commit b7a5ee6542
6 changed files with 105 additions and 11 deletions

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}

View File

@@ -182,6 +182,10 @@ namespace Discord.Commands
// TODO: C#7 type switch // TODO: C#7 type switch
if (attribute is SummaryAttribute) if (attribute is SummaryAttribute)
builder.Summary = (attribute as SummaryAttribute).Text; 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) else if (attribute is ParamArrayAttribute)
{ {
builder.IsMultiple = true; builder.IsMultiple = true;

View File

@@ -1,10 +1,14 @@
using System; using System;
using System.Reflection; using System.Reflection;
using System.Collections.Generic;
namespace Discord.Commands.Builders namespace Discord.Commands.Builders
{ {
public class ParameterBuilder public class ParameterBuilder
{ {
private readonly List<ParameterPreconditionAttribute> _preconditions;
public CommandBuilder Command { get; } public CommandBuilder Command { get; }
public string Name { get; internal set; } public string Name { get; internal set; }
public Type ParameterType { get; internal set; } public Type ParameterType { get; internal set; }
@@ -16,16 +20,20 @@ namespace Discord.Commands.Builders
public object DefaultValue { get; set; } public object DefaultValue { get; set; }
public string Summary { get; set; } public string Summary { get; set; }
public IReadOnlyList<ParameterPreconditionAttribute> Preconditions => _preconditions;
//Automatic //Automatic
internal ParameterBuilder(CommandBuilder command) internal ParameterBuilder(CommandBuilder command)
{ {
_preconditions = new List<ParameterPreconditionAttribute>();
Command = command; Command = command;
} }
//User-defined //User-defined
internal ParameterBuilder(CommandBuilder command, string name, Type type) internal ParameterBuilder(CommandBuilder command, string name, Type type)
: this(command) : this(command)
{ {
Preconditions.NotNull(name, nameof(name)); Discord.Preconditions.NotNull(name, nameof(name));
Name = name; Name = name;
SetType(type); SetType(type);
@@ -49,7 +57,7 @@ namespace Discord.Commands.Builders
} }
public ParameterBuilder WithDefault(object defaultValue) public ParameterBuilder WithDefault(object defaultValue)
{ {
DefaultValue = defaultValue; DefaultValue = defaultValue;
return this; return this;
} }
public ParameterBuilder WithIsOptional(bool isOptional) public ParameterBuilder WithIsOptional(bool isOptional)
@@ -68,6 +76,12 @@ namespace Discord.Commands.Builders
return this; return this;
} }
public ParameterBuilder AddPrecondition(ParameterPreconditionAttribute precondition)
{
_preconditions.Add(precondition);
return this;
}
internal ParameterInfo Build(CommandInfo info) internal ParameterInfo Build(CommandInfo info)
{ {
if (TypeReader == null) if (TypeReader == null)

View File

@@ -135,9 +135,26 @@ namespace Discord.Commands
if (map == null) if (map == null)
map = DependencyMap.Empty; 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 try
{ {
var args = GenerateArgs(argList, paramList);
switch (RunMode) switch (RunMode)
{ {
case RunMode.Sync: //Always sync case RunMode.Sync: //Always sync

View File

@@ -1,5 +1,7 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading.Tasks; using System.Threading.Tasks;
using Discord.Commands.Builders; using Discord.Commands.Builders;
@@ -10,6 +12,17 @@ namespace Discord.Commands
{ {
private readonly TypeReader _reader; 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) internal ParameterInfo(ParameterBuilder builder, CommandInfo command, CommandService service)
{ {
Command = command; Command = command;
@@ -23,17 +36,30 @@ namespace Discord.Commands
Type = builder.ParameterType; Type = builder.ParameterType;
DefaultValue = builder.DefaultValue; DefaultValue = builder.DefaultValue;
Preconditions = builder.Preconditions.ToImmutableArray();
_reader = builder.TypeReader; _reader = builder.TypeReader;
} }
public CommandInfo Command { get; } public async Task<PreconditionResult> CheckPreconditionsAsync(CommandContext context, object[] args, IDependencyMap map = null)
public string Name { get; } {
public string Summary { get; } if (map == null)
public bool IsOptional { get; } map = DependencyMap.Empty;
public bool IsRemainder { get; }
public bool IsMultiple { get; } int position = 0;
public Type Type { get; } for(position = 0; position < Command.Parameters.Count; position++)
public object DefaultValue { get; } 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) public async Task<TypeReaderResult> Parse(CommandContext context, string input)
{ {