Add common incoming message check, fix auto role entry
This commit is contained in:
parent
94d4a27e85
commit
da31ce3e0d
6 changed files with 77 additions and 49 deletions
|
@ -14,8 +14,7 @@ public class AutoResponder : RegexbotModule {
|
|||
}
|
||||
|
||||
private async Task DiscordClient_MessageReceived(SocketMessage arg) {
|
||||
if (arg.Channel is not SocketGuildChannel ch) return;
|
||||
if (arg.Author.IsBot || arg.Author.IsWebhook) return;
|
||||
if (!Common.Misc.IsValidUserMessage(arg, out var ch)) return;
|
||||
|
||||
var definitions = GetGuildState<IEnumerable<Definition>>(ch.Guild.Id);
|
||||
if (definitions == null) return; // No configuration in this guild; do no further processing
|
||||
|
@ -49,7 +48,7 @@ public class AutoResponder : RegexbotModule {
|
|||
await msg.Channel.SendMessageAsync(def.GetResponse());
|
||||
} else {
|
||||
var ch = (SocketGuildChannel)msg.Channel;
|
||||
string[] cmdline = def.Command.Split(new char[] { ' ' }, 2);
|
||||
var cmdline = def.Command.Split(new char[] { ' ' }, 2);
|
||||
|
||||
var ps = new ProcessStartInfo() {
|
||||
FileName = cmdline[0],
|
||||
|
@ -63,13 +62,13 @@ public class AutoResponder : RegexbotModule {
|
|||
p.WaitForExit(5000); // waiting 5 seconds at most
|
||||
if (p.HasExited) {
|
||||
if (p.ExitCode != 0) {
|
||||
PLog($"Command execution in {ch.Guild.Id}: Process exited abnormally (with code {p.ExitCode}).");
|
||||
Log(ch.Guild, $"Command execution: Process exited abnormally (with code {p.ExitCode}).");
|
||||
}
|
||||
using var stdout = p.StandardOutput;
|
||||
var result = await stdout.ReadToEndAsync();
|
||||
if (!string.IsNullOrWhiteSpace(result)) await msg.Channel.SendMessageAsync(result);
|
||||
} else {
|
||||
PLog($"Command execution in {ch.Guild.Id}: Process has not exited in 5 seconds. Killing process.");
|
||||
Log(ch.Guild, $"Command execution: Process has not exited in 5 seconds. Killing process.");
|
||||
p.Kill();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
using System.Text;
|
||||
|
||||
namespace RegexBot.Modules.EntryTimeRole;
|
||||
namespace RegexBot.Modules.EntryRole;
|
||||
|
||||
/// <summary>
|
||||
/// Automatically sets a role onto users entering the guild after a predefined amount of time.
|
||||
/// </summary>
|
||||
[RegexbotModule]
|
||||
public class EntryTimeRole : RegexbotModule {
|
||||
public sealed class EntryRole : RegexbotModule, IDisposable {
|
||||
readonly Task _workerTask;
|
||||
readonly CancellationTokenSource _workerTaskToken; // TODO make use of this when possible
|
||||
readonly CancellationTokenSource _workerTaskToken;
|
||||
|
||||
public EntryTimeRole(RegexbotClient bot) : base(bot) {
|
||||
public EntryRole(RegexbotClient bot) : base(bot) {
|
||||
DiscordClient.GuildMembersDownloaded += DiscordClient_GuildMembersDownloaded;
|
||||
DiscordClient.UserJoined += DiscordClient_UserJoined;
|
||||
DiscordClient.UserLeft += DiscordClient_UserLeft;
|
||||
|
||||
|
@ -19,6 +20,28 @@ public class EntryTimeRole : RegexbotModule {
|
|||
TaskCreationOptions.LongRunning, TaskScheduler.Default);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose() {
|
||||
_workerTaskToken.Cancel();
|
||||
_workerTask.Wait(2000);
|
||||
_workerTask.Dispose();
|
||||
}
|
||||
|
||||
private Task DiscordClient_GuildMembersDownloaded(SocketGuild arg) {
|
||||
var data = GetGuildState<GuildData>(arg.Id);
|
||||
if (data == null) return Task.CompletedTask;
|
||||
|
||||
var rolecheck = data.TargetRole.FindRoleIn(arg);
|
||||
if (rolecheck == null) {
|
||||
Log(arg, "Unable to find target role to be applied. Initial check has been skipped.");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
foreach (var user in arg.Users.Where(u => !u.Roles.Contains(rolecheck))) {
|
||||
data.WaitlistAdd(user.Id);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task DiscordClient_UserJoined(SocketGuildUser arg) {
|
||||
GetGuildState<GuildData>(arg.Guild.Id)?.WaitlistAdd(arg.Id);
|
||||
return Task.CompletedTask;
|
||||
|
@ -88,7 +111,7 @@ public class EntryTimeRole : RegexbotModule {
|
|||
// Attempt to get role.
|
||||
var targetRole = gconf.TargetRole.FindRoleIn(g, true);
|
||||
if (targetRole == null) {
|
||||
ReportFailure(g.Id, "Unable to determine role to be applied. Does it still exist?", gusers);
|
||||
ReportFailure(g, "Unable to determine role to be applied. Does it still exist?", gusers);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -99,11 +122,11 @@ public class EntryTimeRole : RegexbotModule {
|
|||
await item.AddRoleAsync(targetRole);
|
||||
}
|
||||
} catch (Discord.Net.HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.Forbidden) {
|
||||
ReportFailure(g.Id, "Unable to set role due to a permissions issue.", gusers);
|
||||
ReportFailure(g, "Unable to set role due to a permissions issue.", gusers);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReportFailure(ulong gid, string message, IEnumerable<SocketGuildUser> failedUserList) {
|
||||
private void ReportFailure(SocketGuild g, string message, IEnumerable<SocketGuildUser> failedUserList) {
|
||||
var failList = new StringBuilder();
|
||||
var count = 0;
|
||||
foreach (var item in failedUserList) {
|
||||
|
@ -115,6 +138,6 @@ public class EntryTimeRole : RegexbotModule {
|
|||
}
|
||||
}
|
||||
failList.Remove(0, 2);
|
||||
Log(gid, message + " Failed while attempting to set role on the following users: " + failList.ToString());
|
||||
Log(g, message + " Failed while attempting to set role on the following users: " + failList.ToString());
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
using RegexBot.Common;
|
||||
|
||||
namespace RegexBot.Modules.EntryTimeRole;
|
||||
namespace RegexBot.Modules.EntryRole;
|
||||
|
||||
/// <summary>
|
||||
/// Contains configuration data as well as per-guild timers for those awaiting role assignment.
|
||||
|
@ -37,7 +37,7 @@ class GuildData {
|
|||
}
|
||||
|
||||
try {
|
||||
WaitTime = conf["WaitTime"].Value<int>();
|
||||
WaitTime = conf[nameof(WaitTime)]!.Value<int>();
|
||||
} catch (NullReferenceException) {
|
||||
throw new ModuleLoadException("WaitTime value not specified.");
|
||||
} catch (InvalidCastException) {
|
||||
|
@ -54,7 +54,9 @@ class GuildData {
|
|||
}
|
||||
|
||||
public void WaitlistAdd(ulong userId) {
|
||||
lock (WaitingList) WaitingList.Add(userId, DateTimeOffset.UtcNow.AddSeconds(WaitTime));
|
||||
lock (WaitingList) {
|
||||
if (!WaitingList.ContainsKey(userId)) WaitingList.Add(userId, DateTimeOffset.UtcNow.AddSeconds(WaitTime));
|
||||
}
|
||||
}
|
||||
|
||||
public void WaitlistRemove(ulong userId) {
|
|
@ -7,22 +7,22 @@
|
|||
[RegexbotModule]
|
||||
public class PendingOutRole : RegexbotModule {
|
||||
public PendingOutRole(RegexbotClient bot) : base(bot) {
|
||||
DiscordClient.GuildAvailable += DiscordClient_GuildAvailable;
|
||||
DiscordClient.GuildMembersDownloaded += DiscordClient_GuildMembersDownloaded;
|
||||
DiscordClient.GuildMemberUpdated += DiscordClient_GuildMemberUpdated;
|
||||
}
|
||||
|
||||
private async Task DiscordClient_GuildAvailable(SocketGuild arg) {
|
||||
private async Task DiscordClient_GuildMembersDownloaded(SocketGuild arg) {
|
||||
var conf = GetGuildState<ModuleConfig>(arg.Id);
|
||||
if (conf == null) return;
|
||||
var trole = GetRole(arg);
|
||||
if (trole == null) {
|
||||
Log(arg.Id, "Unable to find target role to be applied. Was it renamed or deleted?");
|
||||
var targetRole = conf.Role.FindRoleIn(arg, true);
|
||||
if (targetRole == null) {
|
||||
Log(arg, "Unable to find role to be applied. Initial check has been skipped.");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var user in arg.Users.Where(u => u.IsPending.HasValue && u.IsPending.Value == false)) {
|
||||
if (user.Roles.Contains(trole)) continue;
|
||||
await user.AddRoleAsync(trole);
|
||||
if (user.Roles.Contains(targetRole)) continue;
|
||||
await user.AddRoleAsync(targetRole);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,9 +32,9 @@ public class PendingOutRole : RegexbotModule {
|
|||
|
||||
if (!(previous.Value.IsPending.HasValue && current.IsPending.HasValue)) return;
|
||||
if (previous.Value.IsPending == true && current.IsPending == false) {
|
||||
var r = GetRole(current.Guild);
|
||||
var r = conf.Role.FindRoleIn(current.Guild, true);
|
||||
if (r == null) {
|
||||
Log(current.Guild.Id, $"Failed to update {current} - was the role renamed or deleted?");
|
||||
Log(current.Guild, $"Failed to update role for {current} - was the role renamed or deleted?");
|
||||
return;
|
||||
}
|
||||
await current.AddRoleAsync(r);
|
||||
|
@ -47,20 +47,4 @@ public class PendingOutRole : RegexbotModule {
|
|||
throw new ModuleLoadException("Configuration for this section is invalid.");
|
||||
return Task.FromResult<object?>(new ModuleConfig((JObject)config));
|
||||
}
|
||||
|
||||
private SocketRole? GetRole(SocketGuild g) {
|
||||
var conf = GetGuildState<ModuleConfig>(g.Id);
|
||||
if (conf == null) return null;
|
||||
|
||||
if (conf.Role.Id.HasValue) {
|
||||
var result = g.GetRole(conf.Role.Id.Value);
|
||||
if (result != null) return result;
|
||||
} else {
|
||||
foreach (var role in g.Roles) {
|
||||
if (string.Equals(conf.Role.Name, role.Name, StringComparison.OrdinalIgnoreCase)) return role;
|
||||
}
|
||||
}
|
||||
Log(g.Id, "Unable to find role in " + g.Name);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
23
RegexBot/Common/Misc.cs
Normal file
23
RegexBot/Common/Misc.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace RegexBot.Common;
|
||||
/// <summary>
|
||||
/// Miscellaneous useful functions that don't have a particular place anywhere else.
|
||||
/// </summary>
|
||||
public static class Misc {
|
||||
/// <summary>
|
||||
/// Performs common checks on the specified message to see if it fits all the criteria of a
|
||||
/// typical, ordinary message sent by an ordinary guild user.
|
||||
/// </summary>
|
||||
public static bool IsValidUserMessage(SocketMessage msg, [NotNullWhen(true)] out SocketTextChannel? channel) {
|
||||
channel = default;
|
||||
if (msg.Channel is not SocketTextChannel ch) return false;
|
||||
if (msg.Author.IsBot || msg.Author.IsWebhook) return false;
|
||||
if (((IMessage)msg).Type != MessageType.Default) return false;
|
||||
if (msg is SocketSystemMessage) return false;
|
||||
channel = ch;
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -16,16 +16,13 @@ class MessageCachingSubservice {
|
|||
bot.DiscordClient.MessageUpdated += DiscordClient_MessageUpdated;
|
||||
}
|
||||
|
||||
private Task DiscordClient_MessageReceived(SocketMessage arg) {
|
||||
if (arg.Channel is IDMChannel || arg is not SocketSystemMessage) return Task.CompletedTask;
|
||||
return AddOrUpdateCacheItemAsync(arg);
|
||||
}
|
||||
private Task DiscordClient_MessageUpdated(Cacheable<IMessage, ulong> arg1, SocketMessage arg2, ISocketMessageChannel arg3) {
|
||||
if (arg2.Channel is IDMChannel || arg2 is not SocketSystemMessage) return Task.CompletedTask;
|
||||
return AddOrUpdateCacheItemAsync(arg2);
|
||||
}
|
||||
private Task DiscordClient_MessageReceived(SocketMessage arg)
|
||||
=> AddOrUpdateCacheItemAsync(arg);
|
||||
private Task DiscordClient_MessageUpdated(Cacheable<IMessage, ulong> arg1, SocketMessage arg2, ISocketMessageChannel arg3)
|
||||
=> AddOrUpdateCacheItemAsync(arg2);
|
||||
|
||||
private async Task AddOrUpdateCacheItemAsync(SocketMessage arg) {
|
||||
if (!Common.Misc.IsValidUserMessage(arg, out _)) return;
|
||||
using var db = new BotDatabaseContext();
|
||||
|
||||
CachedGuildMessage? msg = db.GuildMessageCache.Where(m => m.MessageId == (long)arg.Id).SingleOrDefault();
|
||||
|
|
Loading…
Reference in a new issue