Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Command Handler #3

Open
OoLunar opened this issue May 3, 2023 · 1 comment
Open

Feature Request: Command Handler #3

OoLunar opened this issue May 3, 2023 · 1 comment
Assignees
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@OoLunar
Copy link
Owner

OoLunar commented May 3, 2023

Is your feature request related to a problem? Please describe.
As it is now, we only have a singular command: /create-cookie. While future commands aren't specifically planned out, they are desired. Right now we hardcode the first command id returned from the Discord API and check if the command id matches the interaction id.

Registration:

JsonDocument slashCommand = await response.Content.ReadFromJsonAsync<JsonDocument>() ?? throw new InvalidOperationException("Failed to parse slash command response.");
CreateCookieCommandId = slashCommand.RootElement[0].GetProperty("id").GetString() ?? throw new InvalidOperationException("Missing 'id' property.");

Execution:

DiscordInteractionApplicationCommandDataStructure? data = interaction.Data.Deserialize<DiscordInteractionApplicationCommandDataStructure>();
if (data is null)
{
throw new ProviderException(ResponseStatus.BadRequest, "Invalid interaction data");
}
else if (data.Id != _slashCommandHandler.CreateCookieCommandId)
{
throw new ProviderException(ResponseStatus.BadRequest, $"Unknown command id: {data.Id}");
}

Describe the solution you'd like
Instead of hardcoding the functionality for a singular command, I'd prefer to use reflection or possibly source generation to auto-register the commands on startup. Ideally we'd pass the command id from the interaction, index from a frozen dictionary and execute a static delegate which returns an IResponse, however depending on the feature/command added we may have to make room for object initialization via dependency injection. Additionally, if we add multiple commands, we would have to provide a way to pass the command name and short description, optimistically with translations available. I propose an interface like the following:

public interface ICommand
{
    public IReadOnlyDictionary<CultureInfo, string> Names { get; init; }
    public IReadOnlyDictionary<CultureInfo, string> Descriptions { get; init; }

    public Task<object?> ExecuteAsync(DiscordInteractionApplicationCommandDataStructure data);
}

With this design, I chose to forsake the static modifer and instead opt to initialize the ICommand as a singleton and then pass the ExecuteAsync method to the FrozenDictionary as a delegate. By creating the object, this allows us to use dependency injection to grab the logger or load translations from an external file.

Error handling inside the command handler is to be decided. I'll likely embed the error handling logic inside of the commands themselves, or maybe I'll add another method to the interface:

public Task<object?> OnErrorAsync(DiscordInteractionApplicationCommandDataStructure data, Exception error);

Describe alternatives you've considered
I am not using a switch case for this.

@OoLunar OoLunar added enhancement New feature or request help wanted Extra attention is needed labels May 3, 2023
@OoLunar OoLunar self-assigned this May 3, 2023
@OoLunar
Copy link
Owner Author

OoLunar commented May 3, 2023

I forgot to mention that this comes at the cost of having to fully implement the Discord entities we choose to use. We can either switch to a Discord library that allows for external deserialization (possibly Remora or Starnight) or continue to create the entities ourselves.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

1 participant