Browse Source

Command execution code rework and TypeConverters auto-scope fix (#2306)

* command execution rework and sync service scopes for typeconverters

* replace ValueTask with Task

* fix implementation bugs

Co-authored-by: Quin Lynch <49576606+quinchs@users.noreply.github.com>
tags/3.9.0
Cenk Ergen GitHub 2 years ago
parent
commit
6869817184
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 159 additions and 172 deletions
  1. +5
    -2
      src/Discord.Net.Interactions/Info/Commands/AutocompleteCommandInfo.cs
  2. +63
    -61
      src/Discord.Net.Interactions/Info/Commands/CommandInfo.cs
  3. +12
    -28
      src/Discord.Net.Interactions/Info/Commands/ComponentCommandInfo.cs
  4. +1
    -1
      src/Discord.Net.Interactions/Info/Commands/ContextCommands/ContextCommandInfo.cs
  5. +9
    -4
      src/Discord.Net.Interactions/Info/Commands/ContextCommands/MessageCommandInfo.cs
  6. +8
    -3
      src/Discord.Net.Interactions/Info/Commands/ContextCommands/UserCommandInfo.cs
  7. +16
    -21
      src/Discord.Net.Interactions/Info/Commands/ModalCommandInfo.cs
  8. +34
    -41
      src/Discord.Net.Interactions/Info/Commands/SlashCommandInfo.cs
  9. +3
    -3
      src/Discord.Net.Interactions/Info/ModalInfo.cs
  10. +2
    -2
      src/Discord.Net.Interactions/InteractionService.cs
  11. +6
    -6
      src/Discord.Net.Interactions/Results/ParseResult.cs

+ 5
- 2
src/Discord.Net.Interactions/Info/Commands/AutocompleteCommandInfo.cs View File

@@ -23,7 +23,7 @@ namespace Discord.Interactions
public string CommandName { get; }

/// <inheritdoc/>
public override IReadOnlyCollection<CommandParameterInfo> Parameters { get; }
public override IReadOnlyList<CommandParameterInfo> Parameters { get; }

/// <inheritdoc/>
public override bool SupportsWildCards => false;
@@ -41,9 +41,12 @@ namespace Discord.Interactions
if (context.Interaction is not IAutocompleteInteraction)
return ExecuteResult.FromError(InteractionCommandError.ParseFailed, $"Provided {nameof(IInteractionContext)} doesn't belong to a Autocomplete Interaction");

return await RunAsync(context, Array.Empty<object>(), services).ConfigureAwait(false);
return await base.ExecuteAsync(context, services).ConfigureAwait(false);
}

protected override Task<IResult> ParseArgumentsAsync(IInteractionContext context, IServiceProvider services)
=> Task.FromResult(ParseResult.FromSuccess(Array.Empty<object>()) as IResult);

/// <inheritdoc/>
protected override Task InvokeModuleEvent(IInteractionContext context, IResult result) =>
CommandService._autocompleteCommandExecutedEvent.InvokeAsync(this, context, result);


+ 63
- 61
src/Discord.Net.Interactions/Info/Commands/CommandInfo.cs View File

@@ -64,7 +64,7 @@ namespace Discord.Interactions
public IReadOnlyCollection<PreconditionAttribute> Preconditions { get; }

/// <inheritdoc cref="ICommandInfo.Parameters"/>
public abstract IReadOnlyCollection<TParameter> Parameters { get; }
public abstract IReadOnlyList<TParameter> Parameters { get; }

internal CommandInfo(Builders.ICommandBuilder builder, ModuleInfo module, InteractionService commandService)
{
@@ -85,71 +85,16 @@ namespace Discord.Interactions
}

/// <inheritdoc/>
public abstract Task<IResult> ExecuteAsync(IInteractionContext context, IServiceProvider services);
protected abstract Task InvokeModuleEvent(IInteractionContext context, IResult result);
protected abstract string GetLogString(IInteractionContext context);

/// <inheritdoc/>
public async Task<PreconditionResult> CheckPreconditionsAsync(IInteractionContext context, IServiceProvider services)
{
async Task<PreconditionResult> CheckGroups(ILookup<string, PreconditionAttribute> preconditions, string type)
{
foreach (IGrouping<string, PreconditionAttribute> preconditionGroup in preconditions)
{
if (preconditionGroup.Key == null)
{
foreach (PreconditionAttribute precondition in preconditionGroup)
{
var result = await precondition.CheckRequirementsAsync(context, this, services).ConfigureAwait(false);
if (!result.IsSuccess)
return result;
}
}
else
{
var results = new List<PreconditionResult>();
foreach (PreconditionAttribute precondition in preconditionGroup)
results.Add(await precondition.CheckRequirementsAsync(context, this, services).ConfigureAwait(false));

if (!results.Any(p => p.IsSuccess))
return PreconditionGroupResult.FromError($"{type} precondition group {preconditionGroup.Key} failed.", results);
}
}
return PreconditionGroupResult.FromSuccess();
}

var moduleResult = await CheckGroups(Module.GroupedPreconditions, "Module").ConfigureAwait(false);
if (!moduleResult.IsSuccess)
return moduleResult;

var commandResult = await CheckGroups(_groupedPreconditions, "Command").ConfigureAwait(false);
return !commandResult.IsSuccess ? commandResult : PreconditionResult.FromSuccess();
}

protected async Task<IResult> RunAsync(IInteractionContext context, object[] args, IServiceProvider services)
public virtual async Task<IResult> ExecuteAsync(IInteractionContext context, IServiceProvider services)
{
switch (RunMode)
{
case RunMode.Sync:
{
if (CommandService._autoServiceScopes)
{
using var scope = services?.CreateScope();
return await ExecuteInternalAsync(context, args, scope?.ServiceProvider ?? EmptyServiceProvider.Instance).ConfigureAwait(false);
}

return await ExecuteInternalAsync(context, args, services).ConfigureAwait(false);
}
return await ExecuteInternalAsync(context, services).ConfigureAwait(false);
case RunMode.Async:
_ = Task.Run(async () =>
{
if (CommandService._autoServiceScopes)
{
using var scope = services?.CreateScope();
await ExecuteInternalAsync(context, args, scope?.ServiceProvider ?? EmptyServiceProvider.Instance).ConfigureAwait(false);
}
else
await ExecuteInternalAsync(context, args, services).ConfigureAwait(false);
await ExecuteInternalAsync(context, services).ConfigureAwait(false);
});
break;
default:
@@ -159,16 +104,33 @@ namespace Discord.Interactions
return ExecuteResult.FromSuccess();
}

private async Task<IResult> ExecuteInternalAsync(IInteractionContext context, object[] args, IServiceProvider services)
protected abstract Task<IResult> ParseArgumentsAsync(IInteractionContext context, IServiceProvider services);

private async Task<IResult> ExecuteInternalAsync(IInteractionContext context, IServiceProvider services)
{
await CommandService._cmdLogger.DebugAsync($"Executing {GetLogString(context)}").ConfigureAwait(false);

using var scope = services?.CreateScope();
if (CommandService._autoServiceScopes)
services = scope?.ServiceProvider ?? EmptyServiceProvider.Instance;

try
{
var preconditionResult = await CheckPreconditionsAsync(context, services).ConfigureAwait(false);
if (!preconditionResult.IsSuccess)
return await InvokeEventAndReturn(context, preconditionResult).ConfigureAwait(false);

var argsResult = await ParseArgumentsAsync(context, services).ConfigureAwait(false);

if (!argsResult.IsSuccess)
return await InvokeEventAndReturn(context, argsResult).ConfigureAwait(false);

if(argsResult is not ParseResult parseResult)
return ExecuteResult.FromError(InteractionCommandError.BadArgs, "Complex command parsing failed for an unknown reason.");

var args = parseResult.Args;

var index = 0;
foreach (var parameter in Parameters)
{
@@ -221,7 +183,47 @@ namespace Discord.Interactions
}
}

protected async ValueTask<IResult> InvokeEventAndReturn(IInteractionContext context, IResult result)
protected abstract Task InvokeModuleEvent(IInteractionContext context, IResult result);
protected abstract string GetLogString(IInteractionContext context);

/// <inheritdoc/>
public async Task<PreconditionResult> CheckPreconditionsAsync(IInteractionContext context, IServiceProvider services)
{
async Task<PreconditionResult> CheckGroups(ILookup<string, PreconditionAttribute> preconditions, string type)
{
foreach (IGrouping<string, PreconditionAttribute> preconditionGroup in preconditions)
{
if (preconditionGroup.Key == null)
{
foreach (PreconditionAttribute precondition in preconditionGroup)
{
var result = await precondition.CheckRequirementsAsync(context, this, services).ConfigureAwait(false);
if (!result.IsSuccess)
return result;
}
}
else
{
var results = new List<PreconditionResult>();
foreach (PreconditionAttribute precondition in preconditionGroup)
results.Add(await precondition.CheckRequirementsAsync(context, this, services).ConfigureAwait(false));

if (!results.Any(p => p.IsSuccess))
return PreconditionGroupResult.FromError($"{type} precondition group {preconditionGroup.Key} failed.", results);
}
}
return PreconditionGroupResult.FromSuccess();
}

var moduleResult = await CheckGroups(Module.GroupedPreconditions, "Module").ConfigureAwait(false);
if (!moduleResult.IsSuccess)
return moduleResult;

var commandResult = await CheckGroups(_groupedPreconditions, "Command").ConfigureAwait(false);
return !commandResult.IsSuccess ? commandResult : PreconditionResult.FromSuccess();
}

protected async Task<T> InvokeEventAndReturn<T>(IInteractionContext context, T result) where T : IResult
{
await InvokeModuleEvent(context, result).ConfigureAwait(false);
return result;


+ 12
- 28
src/Discord.Net.Interactions/Info/Commands/ComponentCommandInfo.cs View File

@@ -13,7 +13,7 @@ namespace Discord.Interactions
public class ComponentCommandInfo : CommandInfo<ComponentCommandParameterInfo>
{
/// <inheritdoc/>
public override IReadOnlyCollection<ComponentCommandParameterInfo> Parameters { get; }
public override IReadOnlyList<ComponentCommandParameterInfo> Parameters { get; }

/// <inheritdoc/>
public override bool SupportsWildCards => true;
@@ -25,48 +25,32 @@ namespace Discord.Interactions

/// <inheritdoc/>
public override async Task<IResult> ExecuteAsync(IInteractionContext context, IServiceProvider services)
=> await ExecuteAsync(context, services, null).ConfigureAwait(false);

/// <summary>
/// Execute this command using dependency injection.
/// </summary>
/// <param name="context">Context that will be injected to the <see cref="InteractionModuleBase{T}"/>.</param>
/// <param name="services">Services that will be used while initializing the <see cref="InteractionModuleBase{T}"/>.</param>
/// <param name="additionalArgs">Provide additional string parameters to the method along with the auto generated parameters.</param>
/// <returns>
/// A task representing the asynchronous command execution process.
/// </returns>
public async Task<IResult> ExecuteAsync(IInteractionContext context, IServiceProvider services, params string[] additionalArgs)
{
if (context.Interaction is not IComponentInteraction componentInteraction)
if (context.Interaction is not IComponentInteraction)
return ExecuteResult.FromError(InteractionCommandError.ParseFailed, $"Provided {nameof(IInteractionContext)} doesn't belong to a Message Component Interaction");

return await ExecuteAsync(context, Parameters, additionalArgs, componentInteraction.Data, services);
return await base.ExecuteAsync(context, services).ConfigureAwait(false);
}

/// <inheritdoc/>
public async Task<IResult> ExecuteAsync(IInteractionContext context, IEnumerable<CommandParameterInfo> paramList, IEnumerable<string> wildcardCaptures, IComponentInteractionData data,
IServiceProvider services)
protected override async Task<IResult> ParseArgumentsAsync(IInteractionContext context, IServiceProvider services)
{
var paramCount = paramList.Count();
var captureCount = wildcardCaptures?.Count() ?? 0;

if (context.Interaction is not IComponentInteraction messageComponent)
return ExecuteResult.FromError(InteractionCommandError.ParseFailed, $"Provided {nameof(IInteractionContext)} doesn't belong to a Component Command Interaction");
var captures = (context as IRouteMatchContainer)?.SegmentMatches?.ToList();
var captureCount = captures?.Count() ?? 0;

try
{
var args = new object[paramCount];
var data = (context.Interaction as IComponentInteraction).Data;
var args = new object[Parameters.Count];

for (var i = 0; i < paramCount; i++)
for(var i = 0; i < Parameters.Count; i++)
{
var parameter = Parameters.ElementAt(i);
var parameter = Parameters[i];
var isCapture = i < captureCount;

if (isCapture ^ parameter.IsRouteSegmentParameter)
return await InvokeEventAndReturn(context, ExecuteResult.FromError(InteractionCommandError.BadArgs, "Argument type and parameter type didn't match (Wild Card capture/Component value)")).ConfigureAwait(false);

var readResult = isCapture ? await parameter.TypeReader.ReadAsync(context, wildcardCaptures.ElementAt(i), services).ConfigureAwait(false) :
var readResult = isCapture ? await parameter.TypeReader.ReadAsync(context, captures[i].Value, services).ConfigureAwait(false) :
await parameter.TypeConverter.ReadAsync(context, data, services).ConfigureAwait(false);

if (!readResult.IsSuccess)
@@ -75,7 +59,7 @@ namespace Discord.Interactions
args[i] = readResult.Value;
}

return await RunAsync(context, args, services).ConfigureAwait(false);
return ParseResult.FromSuccess(args);
}
catch (Exception ex)
{


+ 1
- 1
src/Discord.Net.Interactions/Info/Commands/ContextCommands/ContextCommandInfo.cs View File

@@ -24,7 +24,7 @@ namespace Discord.Interactions
public GuildPermission? DefaultMemberPermissions { get; }

/// <inheritdoc/>
public override IReadOnlyCollection<CommandParameterInfo> Parameters { get; }
public override IReadOnlyList<CommandParameterInfo> Parameters { get; }

/// <inheritdoc/>
public override bool SupportsWildCards => false;


+ 9
- 4
src/Discord.Net.Interactions/Info/Commands/ContextCommands/MessageCommandInfo.cs View File

@@ -14,18 +14,23 @@ namespace Discord.Interactions
/// <inheritdoc/>
public override async Task<IResult> ExecuteAsync(IInteractionContext context, IServiceProvider services)
{
if (context.Interaction is not IMessageCommandInteraction messageCommand)
if (context.Interaction is not IMessageCommandInteraction)
return ExecuteResult.FromError(InteractionCommandError.ParseFailed, $"Provided {nameof(IInteractionContext)} doesn't belong to a Message Command Interation");

return await base.ExecuteAsync(context, services).ConfigureAwait(false);
}

protected override Task<IResult> ParseArgumentsAsync(IInteractionContext context, IServiceProvider services)
{
try
{
object[] args = new object[1] { messageCommand.Data.Message };
object[] args = new object[1] { (context.Interaction as IMessageCommandInteraction).Data.Message };

return await RunAsync(context, args, services).ConfigureAwait(false);
return Task.FromResult(ParseResult.FromSuccess(args) as IResult);
}
catch (Exception ex)
{
return ExecuteResult.FromError(ex);
return Task.FromResult(ParseResult.FromError(ex) as IResult);
}
}



+ 8
- 3
src/Discord.Net.Interactions/Info/Commands/ContextCommands/UserCommandInfo.cs View File

@@ -17,15 +17,20 @@ namespace Discord.Interactions
if (context.Interaction is not IUserCommandInteraction userCommand)
return ExecuteResult.FromError(InteractionCommandError.ParseFailed, $"Provided {nameof(IInteractionContext)} doesn't belong to a Message Command Interation");

return await base.ExecuteAsync(context, services).ConfigureAwait(false);
}

protected override Task<IResult> ParseArgumentsAsync(IInteractionContext context, IServiceProvider services)
{
try
{
object[] args = new object[1] { userCommand.Data.User };
object[] args = new object[1] { (context.Interaction as IUserCommandInteraction).Data.User };

return await RunAsync(context, args, services).ConfigureAwait(false);
return Task.FromResult(ParseResult.FromSuccess(args) as IResult);
}
catch (Exception ex)
{
return ExecuteResult.FromError(ex);
return Task.FromResult(ParseResult.FromError(ex) as IResult);
}
}



+ 16
- 21
src/Discord.Net.Interactions/Info/Commands/ModalCommandInfo.cs View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.Tracing;
using System.Linq;
using System.Threading.Tasks;
namespace Discord.Interactions
@@ -20,7 +19,7 @@ namespace Discord.Interactions
public override bool SupportsWildCards => true;

/// <inheritdoc/>
public override IReadOnlyCollection<ModalCommandParameterInfo> Parameters { get; }
public override IReadOnlyList<ModalCommandParameterInfo> Parameters { get; }

internal ModalCommandInfo(Builders.ModalCommandBuilder builder, ModuleInfo module, InteractionService commandService) : base(builder, module, commandService)
{
@@ -30,34 +29,29 @@ namespace Discord.Interactions

/// <inheritdoc/>
public override async Task<IResult> ExecuteAsync(IInteractionContext context, IServiceProvider services)
=> await ExecuteAsync(context, services, null).ConfigureAwait(false);

/// <summary>
/// Execute this command using dependency injection.
/// </summary>
/// <param name="context">Context that will be injected to the <see cref="InteractionModuleBase{T}"/>.</param>
/// <param name="services">Services that will be used while initializing the <see cref="InteractionModuleBase{T}"/>.</param>
/// <param name="additionalArgs">Provide additional string parameters to the method along with the auto generated parameters.</param>
/// <returns>
/// A task representing the asynchronous command execution process.
/// </returns>
public async Task<IResult> ExecuteAsync(IInteractionContext context, IServiceProvider services, params string[] additionalArgs)
{
if (context.Interaction is not IModalInteraction modalInteraction)
return ExecuteResult.FromError(InteractionCommandError.ParseFailed, $"Provided {nameof(IInteractionContext)} doesn't belong to a Modal Interaction.");

return await base.ExecuteAsync(context, services).ConfigureAwait(false);
}

protected override async Task<IResult> ParseArgumentsAsync(IInteractionContext context, IServiceProvider services)
{
var captures = (context as IRouteMatchContainer)?.SegmentMatches?.ToList();
var captureCount = captures?.Count() ?? 0;

try
{
var args = new object[Parameters.Count];
var captureCount = additionalArgs?.Length ?? 0;

for(var i = 0; i < Parameters.Count; i++)
for (var i = 0; i < Parameters.Count; i++)
{
var parameter = Parameters.ElementAt(i);

if(i < captureCount)
if (i < captureCount)
{
var readResult = await parameter.TypeReader.ReadAsync(context, additionalArgs[i], services).ConfigureAwait(false);
var readResult = await parameter.TypeReader.ReadAsync(context, captures[i].Value, services).ConfigureAwait(false);
if (!readResult.IsSuccess)
return await InvokeEventAndReturn(context, readResult).ConfigureAwait(false);

@@ -69,13 +63,14 @@ namespace Discord.Interactions
if (!modalResult.IsSuccess)
return await InvokeEventAndReturn(context, modalResult).ConfigureAwait(false);

if (modalResult is not ParseResult parseResult)
if (modalResult is not TypeConverterResult converterResult)
return await InvokeEventAndReturn(context, ExecuteResult.FromError(InteractionCommandError.BadArgs, "Command parameter parsing failed for an unknown reason."));

args[i] = parseResult.Value;
args[i] = converterResult.Value;
}
}
return await RunAsync(context, args, services);

return ParseResult.FromSuccess(args);
}
catch (Exception ex)
{


+ 34
- 41
src/Discord.Net.Interactions/Info/Commands/SlashCommandInfo.cs View File

@@ -33,7 +33,7 @@ namespace Discord.Interactions
public GuildPermission? DefaultMemberPermissions { get; }

/// <inheritdoc/>
public override IReadOnlyCollection<SlashCommandParameterInfo> Parameters { get; }
public override IReadOnlyList<SlashCommandParameterInfo> Parameters { get; }

/// <inheritdoc/>
public override bool SupportsWildCards => false;
@@ -41,9 +41,9 @@ namespace Discord.Interactions
/// <summary>
/// Gets the flattened collection of command parameters and complex parameter fields.
/// </summary>
public IReadOnlyCollection<SlashCommandParameterInfo> FlattenedParameters { get; }
public IReadOnlyList<SlashCommandParameterInfo> FlattenedParameters { get; }

internal SlashCommandInfo (Builders.SlashCommandBuilder builder, ModuleInfo module, InteractionService commandService) : base(builder, module, commandService)
internal SlashCommandInfo(Builders.SlashCommandBuilder builder, ModuleInfo module, InteractionService commandService) : base(builder, module, commandService)
{
Description = builder.Description;
DefaultPermission = builder.DefaultPermission;
@@ -60,49 +60,45 @@ namespace Discord.Interactions
}

/// <inheritdoc/>
public override async Task<IResult> ExecuteAsync (IInteractionContext context, IServiceProvider services)
public override async Task<IResult> ExecuteAsync(IInteractionContext context, IServiceProvider services)
{
if(context.Interaction is not ISlashCommandInteraction slashCommand)
if (context.Interaction is not ISlashCommandInteraction)
return ExecuteResult.FromError(InteractionCommandError.ParseFailed, $"Provided {nameof(IInteractionContext)} doesn't belong to a Slash Command Interaction");

var options = slashCommand.Data.Options;

while (options != null && options.Any(x => x.Type == ApplicationCommandOptionType.SubCommand || x.Type == ApplicationCommandOptionType.SubCommandGroup))
options = options.ElementAt(0)?.Options;

return await ExecuteAsync(context, Parameters, options?.ToList(), services);
return await base.ExecuteAsync(context, services);
}

private async Task<IResult> ExecuteAsync (IInteractionContext context, IEnumerable<SlashCommandParameterInfo> paramList,
List<IApplicationCommandInteractionDataOption> argList, IServiceProvider services)
protected override async Task<IResult> ParseArgumentsAsync(IInteractionContext context, IServiceProvider services)
{
try
List<IApplicationCommandInteractionDataOption> GetOptions()
{
var slashCommandParameterInfos = paramList.ToList();
var args = new object[slashCommandParameterInfos.Count];

for (var i = 0; i < slashCommandParameterInfos.Count; i++)
{
var parameter = slashCommandParameterInfos[i];
var result = await ParseArgument(parameter, context, argList, services).ConfigureAwait(false);

if (!result.IsSuccess)
return await InvokeEventAndReturn(context, result).ConfigureAwait(false);
var options = (context.Interaction as ISlashCommandInteraction).Data.Options;

if (result is not ParseResult parseResult)
return ExecuteResult.FromError(InteractionCommandError.BadArgs, "Command parameter parsing failed for an unknown reason.");
while (options != null && options.Any(x => x.Type == ApplicationCommandOptionType.SubCommand || x.Type == ApplicationCommandOptionType.SubCommandGroup))
options = options.ElementAt(0)?.Options;

args[i] = parseResult.Value;
}
return await RunAsync(context, args, services).ConfigureAwait(false);
return options.ToList();
}
catch(Exception ex)

var options = GetOptions();
var args = new object[Parameters.Count];
for(var i = 0; i < Parameters.Count; i++)
{
return await InvokeEventAndReturn(context, ExecuteResult.FromError(ex)).ConfigureAwait(false);
var parameter = Parameters[i];
var result = await ParseArgumentAsync(parameter, context, options, services).ConfigureAwait(false);

if (!result.IsSuccess)
return await InvokeEventAndReturn(context, ParseResult.FromError(result)).ConfigureAwait(false);

if (result is not TypeConverterResult converterResult)
return ExecuteResult.FromError(InteractionCommandError.BadArgs, "Complex command parsing failed for an unknown reason.");

args[i] = converterResult.Value;
}
return ParseResult.FromSuccess(args);
}

private async Task<IResult> ParseArgument(SlashCommandParameterInfo parameterInfo, IInteractionContext context, List<IApplicationCommandInteractionDataOption> argList,
private async ValueTask<IResult> ParseArgumentAsync(SlashCommandParameterInfo parameterInfo, IInteractionContext context, List<IApplicationCommandInteractionDataOption> argList,
IServiceProvider services)
{
if (parameterInfo.IsComplexParameter)
@@ -111,32 +107,29 @@ namespace Discord.Interactions

for (var i = 0; i < ctorArgs.Length; i++)
{
var result = await ParseArgument(parameterInfo.ComplexParameterFields.ElementAt(i), context, argList, services).ConfigureAwait(false);
var result = await ParseArgumentAsync(parameterInfo.ComplexParameterFields.ElementAt(i), context, argList, services).ConfigureAwait(false);

if (!result.IsSuccess)
return result;

if (result is not ParseResult parseResult)
if (result is not TypeConverterResult converterResult)
return ExecuteResult.FromError(InteractionCommandError.BadArgs, "Complex command parsing failed for an unknown reason.");

ctorArgs[i] = parseResult.Value;
ctorArgs[i] = converterResult.Value;
}

return ParseResult.FromSuccess(parameterInfo._complexParameterInitializer(ctorArgs));
return TypeConverterResult.FromSuccess(parameterInfo._complexParameterInitializer(ctorArgs));
}

var arg = argList?.Find(x => string.Equals(x.Name, parameterInfo.Name, StringComparison.OrdinalIgnoreCase));

if (arg == default)
return parameterInfo.IsRequired ? ExecuteResult.FromError(InteractionCommandError.BadArgs, "Command was invoked with too few parameters") :
ParseResult.FromSuccess(parameterInfo.DefaultValue);
TypeConverterResult.FromSuccess(parameterInfo.DefaultValue);

var typeConverter = parameterInfo.TypeConverter;
var readResult = await typeConverter.ReadAsync(context, arg, services).ConfigureAwait(false);
if (!readResult.IsSuccess)
return readResult;

return ParseResult.FromSuccess(readResult.Value);
return readResult;
}

protected override Task InvokeModuleEvent (IInteractionContext context, IResult result)


+ 3
- 3
src/Discord.Net.Interactions/Info/ModalInfo.cs View File

@@ -103,7 +103,7 @@ namespace Discord.Interactions
public async Task<IResult> CreateModalAsync(IInteractionContext context, IServiceProvider services = null, bool throwOnMissingField = false)
{
if (context.Interaction is not IModalInteraction modalInteraction)
return ParseResult.FromError(InteractionCommandError.Unsuccessful, "Provided context doesn't belong to a Modal Interaction.");
return TypeConverterResult.FromError(InteractionCommandError.Unsuccessful, "Provided context doesn't belong to a Modal Interaction.");

services ??= EmptyServiceProvider.Instance;

@@ -120,7 +120,7 @@ namespace Discord.Interactions
if (!throwOnMissingField)
args[i] = input.DefaultValue;
else
return ParseResult.FromError(InteractionCommandError.BadArgs, $"Modal interaction is missing the required field: {input.CustomId}");
return TypeConverterResult.FromError(InteractionCommandError.BadArgs, $"Modal interaction is missing the required field: {input.CustomId}");
}
else
{
@@ -133,7 +133,7 @@ namespace Discord.Interactions
}
}

return ParseResult.FromSuccess(_initializer(args));
return TypeConverterResult.FromSuccess(_initializer(args));
}
}
}

+ 2
- 2
src/Discord.Net.Interactions/InteractionService.cs View File

@@ -822,7 +822,7 @@ namespace Discord.Interactions

SetMatchesIfApplicable(context, result);

return await result.Command.ExecuteAsync(context, services, result.RegexCaptureGroups).ConfigureAwait(false);
return await result.Command.ExecuteAsync(context, services).ConfigureAwait(false);
}

private async Task<IResult> ExecuteAutocompleteAsync (IInteractionContext context, IAutocompleteInteraction interaction, IServiceProvider services )
@@ -869,7 +869,7 @@ namespace Discord.Interactions

SetMatchesIfApplicable(context, result);

return await result.Command.ExecuteAsync(context, services, result.RegexCaptureGroups).ConfigureAwait(false);
return await result.Command.ExecuteAsync(context, services).ConfigureAwait(false);
}

private static void SetMatchesIfApplicable<T>(IInteractionContext context, SearchResult<T> searchResult)


+ 6
- 6
src/Discord.Net.Interactions/Results/ParseResult.cs View File

@@ -2,9 +2,9 @@ using System;

namespace Discord.Interactions
{
internal struct ParseResult : IResult
public struct ParseResult : IResult
{
public object Value { get; }
public object[] Args { get; }

public InteractionCommandError? Error { get; }

@@ -12,15 +12,15 @@ namespace Discord.Interactions

public bool IsSuccess => !Error.HasValue;

private ParseResult(object value, InteractionCommandError? error, string reason)
private ParseResult(object[] args, InteractionCommandError? error, string reason)
{
Value = value;
Args = args;
Error = error;
ErrorReason = reason;
}

public static ParseResult FromSuccess(object value) =>
new ParseResult(value, null, null);
public static ParseResult FromSuccess(object[] args) =>
new ParseResult(args, null, null);

public static ParseResult FromError(Exception exception) =>
new ParseResult(null, InteractionCommandError.Exception, exception.Message);


Loading…
Cancel
Save