Allow Interaction Commands to run for up to 15 minutes by replying to discord immediately and handling the command in a separate thread

This commit is contained in:
Daan Boerlage 2021-11-14 03:39:36 +01:00
parent 699a93200b
commit 17cb5951ee
Signed by: daan
GPG key ID: FCE070E1E4956606
4 changed files with 43 additions and 16 deletions

View file

@ -7,6 +7,6 @@ namespace Geekbot.Interactions
public interface IInteractionCommandManager
{
Dictionary<string, Command> CommandsInfo { get; init; }
Task<InteractionResponse> RunCommand(Interaction interaction);
InteractionResponse? RunCommand(Interaction interaction);
}
}

View file

@ -1,6 +1,8 @@
using System.Globalization;
using System.Reflection;
using Geekbot.Core;
using Geekbot.Core.GuildSettingsManager;
using Geekbot.Core.Logger;
using Geekbot.Interactions.ApplicationCommand;
using Geekbot.Interactions.Request;
using Geekbot.Interactions.Response;
@ -14,6 +16,8 @@ namespace Geekbot.Interactions
private readonly IGuildSettingsManager _guildSettingsManager;
private readonly IGeekbotLogger _logger;
private readonly Dictionary<CommandType, Dictionary<string, Type>> _commands = new() {
{ CommandType.Message, new Dictionary<string, Type>() },
{ CommandType.User, new Dictionary<string, Type>() },
@ -22,10 +26,12 @@ namespace Geekbot.Interactions
public Dictionary<string, Command> CommandsInfo { get; init; }
public InteractionCommandManager(IServiceProvider provider, IGuildSettingsManager guildSettingsManager)
public InteractionCommandManager(IServiceProvider provider, IGuildSettingsManager guildSettingsManager, IGeekbotLogger logger)
{
_provider = provider;
_guildSettingsManager = guildSettingsManager;
_logger = logger;
var interactions = Assembly.GetCallingAssembly()
.GetTypes()
.Where(type => type.IsClass && !type.IsAbstract && type.IsSubclassOf(typeof(InteractionBase)))
@ -42,16 +48,8 @@ namespace Geekbot.Interactions
}
}
public async Task<InteractionResponse> RunCommand(Interaction interaction)
private async Task HandleInteraction(Interaction interaction, InteractionBase command)
{
var type = _commands[interaction.Data.Type][interaction.Data.Name];
var command = ActivatorUtilities.CreateInstance(_provider, type) as InteractionBase;
if (command == null)
{
return null;
}
var guildSettings = _guildSettingsManager.GetSettings(ulong.Parse(interaction.GuildId));
var language = guildSettings.Language;
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(language);
@ -72,7 +70,36 @@ namespace Geekbot.Interactions
command.AfterExecute(interaction);
}
return response;
try
{
await HttpAbstractions.Patch(
new Uri($"https://discord.com/api/v8/webhooks/{interaction.ApplicationId}/{interaction.Token}/messages/@original"),
response.Data
);
}
catch (Exception e)
{
_logger.Error(LogSource.Interaction, "Failed to send interaction response", e);
throw;
}
}
public InteractionResponse? RunCommand(Interaction interaction)
{
var type = _commands[interaction.Data.Type][interaction.Data.Name];
var command = ActivatorUtilities.CreateInstance(_provider, type) as InteractionBase;
if (command == null)
{
return null;
}
Task.Run(() => HandleInteraction(interaction, command).ConfigureAwait(false));
return new InteractionResponse()
{
Type = InteractionResponseType.DeferredChannelMessageWithSource
};
}
}
}

View file

@ -49,7 +49,7 @@ public class InteractionController : ControllerBase
return (interaction.Type, interaction.Version) switch
{
(InteractionType.Ping, 1) => Ping(),
(InteractionType.ApplicationCommand, 1) => await ApplicationCommand(interaction),
(InteractionType.ApplicationCommand, 1) => ApplicationCommand(interaction),
(InteractionType.MessageComponent, 1) => MessageComponent(interaction),
_ => StatusCode(501)
};
@ -64,9 +64,9 @@ public class InteractionController : ControllerBase
return Ok(response);
}
private async Task<IActionResult> ApplicationCommand(Interaction interaction)
private IActionResult ApplicationCommand(Interaction interaction)
{
var result = await _interactionCommandManager.RunCommand(interaction);
var result = _interactionCommandManager.RunCommand(interaction);
if (result == null)
{

View file

@ -28,7 +28,7 @@ public static class WebApiStartup
builder.Services.AddControllers();
builder.Services.AddCors(options => options.AddPolicy("AllowSpecificOrigin", cors => cors.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()));
var interactionCommandManager = new InteractionCommandManager(commandProvider, commandProvider.GetService<IGuildSettingsManager>());
var interactionCommandManager = new InteractionCommandManager(commandProvider, commandProvider.GetService<IGuildSettingsManager>(), logger);
var highscoreManager = new HighscoreManager(commandProvider.GetService<DatabaseContext>(), commandProvider.GetService<IUserRepository>());
builder.Services.AddSingleton(databaseContext);