Skip to content

Commit

Permalink
Null channels within private thread channels. (#335)
Browse files Browse the repository at this point in the history
#!components: grid-bot
#!deployable-components: grid-bot

* Update ScriptLogger.cs

~ Take into account that forum channels exist.
~ Allow logging of already existing script hashes (just log the hash instead of the whole content)

* Implement channel patches

discord-net/Discord.Net#2997 and #335

In the case of interactions, fallback to ChannelId.
In the case of messages, fallback to Thread ID.

* Update build.yml

Add ability to append suffixes to versions

* Add fixture

* Correct ref mistake

* #335: SocketInteractionContext extensions

Implement extension methods for the socket interaction context class for the following purposes:
~ Getting the channel as a string, taking into consideration that the channel can be null when interactions are executed within private thread channels.
~ Getting the guild as an object from the interaction context when the interaction is coming from a private thread channel, as the conventional method of checking the type of the interaction's channel against SocketGuildChannel will not work.

* LuaUtility.cs

~ Move Regex for format parts to a GeneratedRegex function to improve performance.
~ Only read the LuaVM template once, as it is read from the resources on every subsequent use.
~ Account for the absence of the LuaVM in results.

* #335: Private threads hotfix.

ExecuteScript.cs:
~ Take reference to current DiscordShardedClient.
~ Move correspondence calls when errors are called to use LuaError instead of regular follow ups.
~ Add detection of scripts containing code blocks within zero content (causes exception)
~ Rewrite error for scripts that contain unicode to reduce ambiguity.
~ Rename GridJob to ClientJob.
~ Clean up call to PollDeletion
~ Integrate use of GetChannelAsString and GetGuild.

OnSlashCommand, OnSlashCommandExecuted, LoggerFactory, ScriptLogger:
~ Clean up usings.
~ Rewrite GetGuildId to use extension methods.
~ Change around references to channel to use extension methods.
  • Loading branch information
jf-06 authored Sep 17, 2024
1 parent 7ce11b0 commit d8bf48d
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 66 deletions.
12 changes: 12 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ on:
default: true
type: boolean

version_suffix:
description: "Version Suffix"
required: false
type: string

permissions:
contents: write
deployments: write
Expand Down Expand Up @@ -85,6 +90,8 @@ jobs:

COMPONENT_NAMES: ${{ github.event.inputs.components || needs.get-component-names.outputs.components }}

VERSION_SUFFIX: ${{ github.event.inputs.version_suffix || '' }}

outputs:
components: ${{ steps.build-components.outputs.components }}
version: ${{ steps.version.outputs.version }}
Expand Down Expand Up @@ -125,6 +132,11 @@ jobs:
VERSION="$VERSION-dev"
fi
# If we have a version suffix, append it
if [ -n "${{ env.VERSION_SUFFIX }}" ]; then
VERSION="${VERSION}${{ env.VERSION_SUFFIX }}"
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Build Components
Expand Down
30 changes: 21 additions & 9 deletions services/grid-bot/lib/commands/Modules/ExecuteScript.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ namespace Grid.Bot.Interactions.Public;
using System.Text.RegularExpressions;

using Discord;
using Discord.WebSocket;
using Discord.Interactions;

using Loretta.CodeAnalysis;
Expand All @@ -25,7 +26,7 @@ namespace Grid.Bot.Interactions.Public;
using Commands;
using Extensions;

using GridJob = Client.Job;
using ClientJob = Client.Job;

/// <summary>
/// Interaction handler for executing Luau code.
Expand All @@ -36,6 +37,7 @@ namespace Grid.Bot.Interactions.Public;
/// <param name="logger">The <see cref="ILogger"/>.</param>
/// <param name="gridSettings">The <see cref="GridSettings"/>.</param>
/// <param name="scriptsSettings">The <see cref="ScriptsSettings"/>.</param>
/// <param name="discordClient">The <see cref="DiscordShardedClient"/>.</param>
/// <param name="luaUtility">The <see cref="ILuaUtility"/>.</param>
/// <param name="floodCheckerRegistry">The <see cref="IFloodCheckerRegistry"/>.</param>
/// <param name="backtraceUtility">The <see cref="IBacktraceUtility"/>.</param>
Expand All @@ -48,6 +50,7 @@ namespace Grid.Bot.Interactions.Public;
/// - <paramref name="logger"/> cannot be null.
/// - <paramref name="gridSettings"/> cannot be null.
/// - <paramref name="scriptsSettings"/> cannot be null.
/// - <paramref name="discordClient"/> cannot be null.
/// - <paramref name="luaUtility"/> cannot be null.
/// - <paramref name="floodCheckerRegistry"/> cannot be null.
/// - <paramref name="backtraceUtility"/> cannot be null.
Expand All @@ -64,6 +67,7 @@ public partial class ExecuteScript(
ILogger logger,
GridSettings gridSettings,
ScriptsSettings scriptsSettings,
DiscordShardedClient discordClient,
ILuaUtility luaUtility,
IFloodCheckerRegistry floodCheckerRegistry,
IBacktraceUtility backtraceUtility,
Expand All @@ -83,6 +87,7 @@ IGridServerFileHelper gridServerFileHelper
private readonly GridSettings _gridSettings = gridSettings ?? throw new ArgumentNullException(nameof(gridSettings));
private readonly ScriptsSettings _scriptsSettings = scriptsSettings ?? throw new ArgumentNullException(nameof(scriptsSettings));

private readonly DiscordShardedClient _discordClient = discordClient ?? throw new ArgumentNullException(nameof(discordClient));
private readonly ILuaUtility _luaUtility = luaUtility ?? throw new ArgumentNullException(nameof(luaUtility));
private readonly IFloodCheckerRegistry _floodCheckerRegistry = floodCheckerRegistry ?? throw new ArgumentNullException(nameof(floodCheckerRegistry));
private readonly IBacktraceUtility _backtraceUtility = backtraceUtility ?? throw new ArgumentNullException(nameof(backtraceUtility));
Expand Down Expand Up @@ -304,12 +309,20 @@ string script
{
if (string.IsNullOrWhiteSpace(script))
{
await FollowupAsync("The script cannot be empty.");
await LuaErrorAsync("The script cannot be empty!");

return;
}

script = GetCodeBlockContents(script);

if (string.IsNullOrEmpty(script))
{
await LuaErrorAsync("There must be content within a code block!");

return;
}

script = EscapeQuotes(script);

var originalScript = script;
Expand All @@ -318,7 +331,7 @@ string script

if (ContainsUnicode(script))
{
await FollowupAsync("The script cannot contain unicode characters as grid-servers cannot support unicode in transit.");
await LuaErrorAsync("Scripts can only contain ASCII characters!");

return;
}
Expand Down Expand Up @@ -352,7 +365,7 @@ string script
#endif


var gridJob = new GridJob() { id = scriptId, expirationInSeconds = _gridSettings.ScriptExecutionJobMaxTimeout.TotalSeconds };
var gridJob = new ClientJob() { id = scriptId, expirationInSeconds = _gridSettings.ScriptExecutionJobMaxTimeout.TotalSeconds };
var job = new Job(Guid.NewGuid().ToString());

var sw = Stopwatch.StartNew();
Expand Down Expand Up @@ -461,9 +474,8 @@ string script
scriptName
);
scriptName.PollDeletion(
10,
ex => _logger.Warning("Failed to delete '{0}' because: {1}", scriptName, ex.Message),
() => _logger.Debug(
onFailure: ex => _logger.Warning("Failed to delete '{0}' because: {1}", scriptName, ex.Message),
onSuccess: () => _logger.Debug(
"Successfully deleted the script '{0}' at path '{1}'!",
scriptId,
scriptName
Expand Down Expand Up @@ -493,8 +505,8 @@ private async Task AlertForSystem(string script, string originalScript, string s
_backtraceUtility.UploadException(ex);

var userInfo = Context.User.ToString();
var guildInfo = Context.Guild?.ToString() ?? "DMs";
var channelInfo = Context.Channel.ToString();
var guildInfo = Context.Interaction.GetGuild(_discordClient)?.ToString() ?? "DMs";
var channelInfo = Context.Interaction.GetChannelAsString();

// Script & original script in attachments
var scriptAttachment = new FileAttachment(new MemoryStream(Encoding.ASCII.GetBytes(script)), "script.lua");
Expand Down
4 changes: 2 additions & 2 deletions services/grid-bot/lib/events/Events/OnMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ public async Task Invoke(SocketMessage rawMessage)

_totalUsersBypassedMaintenance.WithLabels(
message.Author.Id.ToString(),
message.Channel.Id.ToString(),
message.Channel?.Id.ToString() ?? message.Thread?.Id.ToString(),
GetGuildId(message)
).Inc();
}
Expand All @@ -182,7 +182,7 @@ public async Task Invoke(SocketMessage rawMessage)
{
_totalBlacklistedUserAttemptedMessages.WithLabels(
message.Author.Id.ToString(),
message.Channel.Id.ToString(),
message.Channel?.Id.ToString() ?? message.Thread?.Id.ToString(),
GetGuildId(message)
).Inc();

Expand Down
25 changes: 6 additions & 19 deletions services/grid-bot/lib/events/Events/OnSlashCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
using System.Threading.Tasks;
using System.Collections.Generic;

using Discord;
using Discord.WebSocket;
using Discord.Interactions;

using Prometheus;

using Utility;
using Discord;
using Extensions;

/// <summary>
/// Event handler for interactions.
Expand Down Expand Up @@ -87,13 +88,8 @@ ILoggerFactory loggerFactory
}
);

private static string GetGuildId(SocketInteraction interaction)
{
if (interaction.Channel is SocketGuildChannel guildChannel)
return guildChannel.Guild.Id.ToString();

return "DM";
}
private string GetGuildId(SocketInteraction interaction)
=> interaction.GetGuild(_client).ToString() ?? "DM";

/// <summary>
/// Invoke the event handler.
Expand Down Expand Up @@ -123,15 +119,6 @@ public async Task Invoke(SocketInteraction interaction)
interaction.Type.ToString()
).Inc();

var guildName = string.Empty;
var guildId = 0UL;

if (interaction.Channel is SocketGuildChannel guildChannel)
{
guildName = guildChannel.Guild.Name;
guildId = guildChannel.Guild.Id;
}

logger.Warning("Maintenance enabled user tried to use the bot.");

var failureMessage = _maintenanceSettings.MaintenanceStatus;
Expand All @@ -157,7 +144,7 @@ public async Task Invoke(SocketInteraction interaction)

_totalUsersBypassedMaintenance.WithLabels(
interaction.User.Id.ToString(),
interaction.Channel.Id.ToString(),
interaction.GetChannelAsString(),
GetGuildId(interaction)
).Inc();
}
Expand All @@ -166,7 +153,7 @@ public async Task Invoke(SocketInteraction interaction)
{
_totalBlacklistedUserAttemptedInteractions.WithLabels(
interaction.User.Id.ToString(),
interaction.Channel.Id.ToString(),
interaction.GetChannelAsString(),
GetGuildId(interaction)
).Inc();

Expand Down
21 changes: 15 additions & 6 deletions services/grid-bot/lib/events/Events/OnSlashCommandExecuted.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ namespace Grid.Bot.Events;
using System.Threading.Tasks;

using Discord;
using Discord.WebSocket;
using Discord.Interactions;

using Prometheus;

using Logging;

using Utility;
using Extensions;


/// <summary>
/// Invoked when slash commands are executed.
Expand All @@ -23,15 +26,18 @@ namespace Grid.Bot.Events;
/// <param name="logger">The <see cref="ILogger"/>.</param>
/// <param name="backtraceUtility">The <see cref="BacktraceUtility"/>.</param>
/// <param name="discordRolesSettings">The <see cref="DiscordRolesSettings"/>.</param>
/// <param name="discordClient">The <see cref="DiscordShardedClient"/>.</param>
/// <exception cref="ArgumentNullException">
/// - <paramref name="logger"/> cannot be null.
/// - <paramref name="backtraceUtility"/> cannot be null.
/// - <paramref name="discordRolesSettings"/> cannot be null.
/// - <paramref name="discordClient"/> cannot be null.
/// </exception>
public class OnInteractionExecuted(
ILogger logger,
IBacktraceUtility backtraceUtility,
DiscordRolesSettings discordRolesSettings
DiscordRolesSettings discordRolesSettings,
DiscordShardedClient discordClient
)
{
private const string UnhandledExceptionOccurredFromCommand = "An error occured with the command:";
Expand All @@ -40,6 +46,7 @@ DiscordRolesSettings discordRolesSettings

private readonly ILogger _logger = logger ?? throw new ArgumentNullException(nameof(logger));
private readonly IBacktraceUtility _backtraceUtility = backtraceUtility ?? throw new ArgumentNullException(nameof(backtraceUtility));
private readonly DiscordShardedClient _discordClient = discordClient ?? throw new ArgumentNullException(nameof(discordClient));

private readonly Counter _totalInteractionsFailed = Metrics.CreateCounter(
"grid_interactions_failed_total",
Expand All @@ -51,9 +58,9 @@ DiscordRolesSettings discordRolesSettings
"interaction_guild_id"
);

private string GetGuildId(IInteractionContext context)
private string GetGuildId(SocketInteraction interaction)
{
return context.Guild?.Id.ToString() ?? "DM";
return interaction.GetGuild(_discordClient)?.Id.ToString() ?? "DM";
}

/// <summary>
Expand All @@ -64,7 +71,8 @@ private string GetGuildId(IInteractionContext context)
/// <param name="result">The <see cref="IResult"/>.</param>
public async Task Invoke(ICommandInfo command, IInteractionContext context, IResult result)
{
var interaction = context.Interaction;
if (context.Interaction is not SocketInteraction interaction)
return;

if (!result.IsSuccess)
{
Expand All @@ -74,8 +82,9 @@ public async Task Invoke(ICommandInfo command, IInteractionContext context, IRes
interaction.Type.ToString(),
interaction.Id.ToString(),
interaction.User.Id.ToString(),
interaction.ChannelId.ToString(),
GetGuildId(context)
/* Temporary until mfdlabs/grid-bot#335 is resolved */
interaction.GetChannelAsString(),
GetGuildId(interaction)
).Inc();

if (result is not ExecuteResult executeResult)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
namespace Grid.Bot.Extensions;

using Discord;
using Discord.WebSocket;

using Threading.Extensions;

/// <summary>
/// Extension methods for <see cref="SocketInteraction" />
/// </summary>
public static class SocketInteractionExtensions
{
/// <summary>
/// Gets the channel from the <see cref="SocketInteraction" />, taking private threads into consideration.
/// </summary>
/// <param name="interaction">The current <see cref="SocketInteraction"/></param>
/// <returns>A string version of either <see cref="ISocketMessageChannel"/> or <see cref="IMessageChannel"/></returns>
public static string GetChannelAsString(this SocketInteraction interaction)
{
if (interaction.Channel is not null) return interaction.Channel.ToString();

return interaction.InteractionChannel.ToString();
}

/// <summary>
/// Gets an <see cref="IGuild"/> for a specific <see cref="SocketInteraction"/>, taking private threads into consideration.
/// </summary>
/// <param name="interaction"></param>
/// <param name="client"></param>
/// <returns></returns>
public static IGuild GetGuild(this SocketInteraction interaction, IDiscordClient client)
{
if (interaction.GuildId == null) return null;

if (interaction.Channel is SocketGuildChannel guildChannel)
return guildChannel.Guild;

return client.GetGuildAsync(interaction.GuildId.Value).SyncOrDefault();
}
}
Loading

0 comments on commit d8bf48d

Please sign in to comment.