Skip to content

Commit

Permalink
Add requested changes
Browse files Browse the repository at this point in the history
Changes:
- Use IResult instead of Optional CommandMatch

- Rework branching workflow
  • Loading branch information
alikindsys committed Nov 25, 2021
1 parent d1b31c8 commit a92ec56
Showing 1 changed file with 36 additions and 19 deletions.
55 changes: 36 additions & 19 deletions src/Discord.Net.Commands/CommandService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -507,27 +507,44 @@ public async Task<IResult> ExecuteAsync(ICommandContext context, string input, I

var searchResult = Search(input);

//Since ValidateAndGetBestMatch is deterministic on the return type, we can use pattern matching on the type for infering the code flow.
var (validationResult, commandMatch) = await ValidateAndGetBestMatch(searchResult, context, services, multiMatchHandling);
var validationResult = await ValidateAndGetBestMatch(searchResult, context, services, multiMatchHandling);

if(validationResult is SearchResult)
if (validationResult is SearchResult result)
{
await _commandExecutedEvent.InvokeAsync(Optional.Create<CommandInfo>(), context, searchResult).ConfigureAwait(false);
}
else if(validationResult is ParseResult parseResult)
{
var result = await commandMatch.Value.Command.ExecuteAsync(context, parseResult, services).ConfigureAwait(false);
if (!result.IsSuccess && !(result is RuntimeResult || result is ExecuteResult)) // succesful results raise the event in CommandInfo#ExecuteInternalAsync (have to raise it there b/c deffered execution)
await _commandExecutedEvent.InvokeAsync(commandMatch.Value.Command, context, result);
await _commandExecutedEvent.InvokeAsync(Optional.Create<CommandInfo>(), context, result).ConfigureAwait(false);
return result;
}
else

if (validationResult is MatchResult matchResult)
{
await _commandExecutedEvent.InvokeAsync(commandMatch.Value.Command, context, validationResult).ConfigureAwait(false);
return await handleCommandPipeline(matchResult, context, services);
}

return validationResult;
}

private async Task<IResult> handleCommandPipeline(MatchResult matchResult, ICommandContext context, IServiceProvider services)
{
if (!matchResult.IsSuccess)
return matchResult;

if (matchResult.Pipeline is ParseResult parseResult)
{
var executeResult = await matchResult.Match.Value.ExecuteAsync(context, parseResult, services);

if (!executeResult.IsSuccess && !(executeResult is RuntimeResult || executeResult is ExecuteResult)) // succesful results raise the event in CommandInfo#ExecuteInternalAsync (have to raise it there b/c deffered execution)
await _commandExecutedEvent.InvokeAsync(matchResult.Match.Value.Command, context, executeResult);
return executeResult;
}

if (matchResult.Pipeline is PreconditionResult preconditionResult)
{
await _commandExecutedEvent.InvokeAsync(matchResult.Match.Value.Command, context, preconditionResult).ConfigureAwait(false);
}

return matchResult;
}

// Calculates the 'score' of a command given a parse result
float CalculateScore(CommandMatch match, ParseResult parseResult)
{
Expand All @@ -554,11 +571,11 @@ float CalculateScore(CommandMatch match, ParseResult parseResult)
/// <param name="provider">The service provider to be used on the command's dependency injection.</param>
/// <param name="multiMatchHandling">The handling mode when multiple command matches are found.</param>
/// <returns>A task that represents the asynchronous validation operation. The task result contains the result of the
/// command validation and the command matched, if a match was found.</returns>
public async Task<(IResult, Optional<CommandMatch>)> ValidateAndGetBestMatch(SearchResult matches, ICommandContext context, IServiceProvider provider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
/// command validation as a <see cref="MatchResult"/> or a <see cref="SearchResult"/> if no matches were found.</returns>
public async Task<IResult> ValidateAndGetBestMatch(SearchResult matches, ICommandContext context, IServiceProvider provider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
{
if (!matches.IsSuccess)
return (matches, Optional.Create<CommandMatch>());
return matches;

var commands = matches.Commands;
var preconditionResults = new Dictionary<CommandMatch, PreconditionResult>();
Expand All @@ -574,11 +591,11 @@ float CalculateScore(CommandMatch match, ParseResult parseResult)

if (successfulPreconditions.Length == 0)
{
//All preconditions failed, return the one from the highest priority command
var bestCandidate = preconditionResults
.OrderByDescending(x => x.Key.Command.Priority)
.FirstOrDefault(x => !x.Value.IsSuccess);

return (bestCandidate.Value, bestCandidate.Key);
return MatchResult.FromSuccess(bestCandidate.Key,bestCandidate.Value);
}

var parseResults = new Dictionary<CommandMatch, ParseResult>();
Expand Down Expand Up @@ -615,12 +632,12 @@ float CalculateScore(CommandMatch match, ParseResult parseResult)
var bestMatch = parseResults
.FirstOrDefault(x => !x.Value.IsSuccess);

return (bestMatch.Value, bestMatch.Key);
return MatchResult.FromSuccess(bestMatch.Key,bestMatch.Value);
}

var chosenOverload = successfulParses[0];

return (chosenOverload.Value, chosenOverload.Key);
return MatchResult.FromSuccess(chosenOverload.Key,chosenOverload.Value);
}

protected virtual void Dispose(bool disposing)
Expand Down

0 comments on commit a92ec56

Please sign in to comment.