Skip to content

Commit

Permalink
Merge pull request #499 from Ixrec/recent-message-storage
Browse files Browse the repository at this point in the history
implement RecentMessage storage and a simple .recentmessages command
  • Loading branch information
Ixrec authored Nov 8, 2023
2 parents da3fea4 + 06b40b5 commit e65ed63
Show file tree
Hide file tree
Showing 12 changed files with 77 additions and 22 deletions.
24 changes: 22 additions & 2 deletions Izzy-Moonbot/EventListeners/MessageListener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ public class MessageListener
private readonly LoggingService _logger;
private readonly Config _config;
private readonly ModLoggingService _modLogger;
private readonly State _state;
private readonly TransientState _state;

public MessageListener(LoggingService logger, Config config, ModLoggingService modLogger, State state)
public MessageListener(LoggingService logger, Config config, ModLoggingService modLogger, TransientState state)
{
_logger = logger;
_config = config;
Expand All @@ -36,7 +36,27 @@ private async Task ProcessMessageReceived(
IIzzyMessage message,
IIzzyClient client)
{
// RecentMessages updating

var author = message.Author;
if (!_state.RecentMessages.ContainsKey(author.Id))
_state.RecentMessages[author.Id] = new();
var recentMessages = _state.RecentMessages[author.Id];
recentMessages.Add((message.Timestamp, message.Content));

if (recentMessages.Count > 5)
{
var secondsUntilIrrelevant = _config.SpamPressureDecay * (_config.SpamMaxPressure / _config.SpamBasePressure);
while (
(DateTimeOffset.UtcNow - recentMessages[0].Item1).TotalSeconds > secondsUntilIrrelevant &&
recentMessages.Count > 5
) {
recentMessages.RemoveAt(0);
}
}

// Witty processing

if (author.Id == client.CurrentUser.Id) return; // Don't process self.
if (author.IsBot) return; // Don't listen to bots

Expand Down
4 changes: 2 additions & 2 deletions Izzy-Moonbot/Modules/DevModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ public class DevModule : ModuleBase<SocketCommandContext>
private readonly RaidService _raidService;
private readonly ScheduleService _scheduleService;
private readonly Config _config;
private readonly State _state;
private readonly TransientState _state;
private readonly Dictionary<ulong, User> _users;

public DevModule(Config config, Dictionary<ulong, User> users, FilterService filterService,
LoggingService loggingService, ModLoggingService modLoggingService, ModService modService,
SpamService pressureService, RaidService raidService, ScheduleService scheduleService, State state)
SpamService pressureService, RaidService raidService, ScheduleService scheduleService, TransientState state)
{
_config = config;
_users = users;
Expand Down
34 changes: 33 additions & 1 deletion Izzy-Moonbot/Modules/ModMiscModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@ public class ModMiscModule : ModuleBase<SocketCommandContext>
private readonly ScheduleService _schedule;
private readonly Dictionary<ulong, User> _users;
private readonly LoggingService _logger;
private readonly TransientState _state;

public ModMiscModule(Config config, Dictionary<ulong, User> users, ScheduleService schedule, LoggingService logger)
public ModMiscModule(Config config, Dictionary<ulong, User> users, ScheduleService schedule, LoggingService logger, TransientState state)
{
_config = config;
_schedule = schedule;
_users = users;
_logger = logger;
_state = state;
}

[Command("panic")]
Expand Down Expand Up @@ -849,4 +851,34 @@ public async Task SetBannnerCommandAsync([Remainder] string url = "")
}
await ReplyAsync(msg);
}

[Command("recentmessages")]
[Summary("Dump all of the recent messages Izzy has cached for a specific user.")]
[Remarks("Izzy records at least 5 messages for each user, and will not throw away a message until it becomes irrelevant for spam pressure (see SpamPressureDecay, SpamMaxPressure and SpamBasePressure). Edits and deletes are ignored; only the original version of the message is cached. Restarting Izzy clears this cache.")]
[RequireContext(ContextType.Guild)]
[ModCommand(Group = "Permissions")]
[DevCommand(Group = "Permissions")]
[Parameter("user", ParameterType.UserResolvable, "The user to show messages for")]
[Example(".recentmessages @Izzy Moonbot")]
public async Task RecentMessagesCommandAsync([Remainder] string user = "")
{
var (userId, userError) = await ParseHelper.TryParseUserResolvable(user, new SocketGuildAdapter(Context.Guild));
if (userId == null)
{
await ReplyAsync($"I couldn't find that user's id: {userError}");
return;
}

var recentMessages = _state.RecentMessages[(ulong)userId];
if (recentMessages == null || recentMessages.Count == 0)
{
await ReplyAsync($"I haven't seen any messages from <@{userId}> since my last restart. Sorry.");
return;
}

await ReplyAsync($"These are all the recent messages (without edits or deletions) I have cached from <@{userId}>:\n" +
"\n" +
String.Join("\n", recentMessages.Select(rm => $"[<t:{rm.Item1.ToUnixTimeSeconds()}:R>] {rm.Item2}"))
);
}
}
4 changes: 2 additions & 2 deletions Izzy-Moonbot/Modules/RaidModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ public class RaidModule : ModuleBase<SocketCommandContext>
private readonly RaidService _raidService;
private readonly ScheduleService _scheduleService;
private readonly Config _config;
private readonly State _state;
private readonly TransientState _state;
private readonly GeneralStorage _generalStorage;

public RaidModule(Config config, RaidService raidService, State state,
public RaidModule(Config config, RaidService raidService, TransientState state,
ScheduleService scheduleService, ModService modService, GeneralStorage generalStorage)
{
_config = config;
Expand Down
2 changes: 1 addition & 1 deletion Izzy-Moonbot/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ private static IHostBuilder CreateHostBuilder(string[] args)
services.AddSingleton(scheduledTasks);
var generalStorage = FileHelper.LoadGeneralStorageAsync().GetAwaiter().GetResult();
services.AddSingleton(generalStorage);
var stateStorage = new State();
var stateStorage = new TransientState();
services.AddSingleton(stateStorage);
var quoteStorage = FileHelper.LoadQuoteStorageAsync().GetAwaiter().GetResult();
services.AddSingleton(quoteStorage);
Expand Down
4 changes: 2 additions & 2 deletions Izzy-Moonbot/Service/RaidService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ public class RaidService
private readonly ModLoggingService _modLog;
private readonly ModService _modService;
private readonly Config _config;
private readonly State _state;
private readonly TransientState _state;
private readonly GeneralStorage _generalStorage;
private readonly ScheduleService _schedule;

public RaidService(Config config, ModService modService, LoggingService log, ModLoggingService modLog,
State state, GeneralStorage generalStorage, ScheduleService schedule)
TransientState state, GeneralStorage generalStorage, ScheduleService schedule)
{
_config = config;
_modService = modService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

namespace Izzy_Moonbot.Settings;

// Storage for Izzy's internal states.
// This is used for volatile data that needs to persist across Izzy's various services and modules.
public class State
// Storage for Izzy's transient shared state.
// This is used for volatile data that needs to be used by multiple services and modules.
public class TransientState
{
public int CurrentLargeJoinCount = 0;
public int CurrentSmallJoinCount = 0;
Expand All @@ -17,4 +17,6 @@ public class State

// RaidService
public List<ulong> RecentJoins = new();

public Dictionary<ulong, List<(DateTimeOffset, string)>> RecentMessages = new();
}
4 changes: 2 additions & 2 deletions Izzy-Moonbot/Worker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public class Worker : BackgroundService
private readonly ScheduleService _scheduleService;
private readonly IServiceCollection _services;
private readonly Config _config;
private readonly State _state;
private readonly TransientState _state;
private readonly Dictionary<ulong, User> _users;
private readonly QuoteService _quoteService;
private readonly ConfigListener _configListener;
Expand All @@ -49,7 +49,7 @@ public class Worker : BackgroundService

public Worker(ILogger<Worker> logger, ModLoggingService modLog, IServiceCollection services, ModService modService, RaidService raidService,
FilterService filterService, ScheduleService scheduleService, IOptions<DiscordSettings> discordSettings,
Config config, State state, Dictionary<ulong, User> users, UserListener userListener, SpamService spamService, QuoteService quoteService,
Config config, TransientState state, Dictionary<ulong, User> users, UserListener userListener, SpamService spamService, QuoteService quoteService,
ConfigListener configListener, MessageListener messageListener)
{
_logger = logger;
Expand Down
2 changes: 1 addition & 1 deletion Izzy-MoonbotTests/Tests/MiscModuleTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public static async Task<CommandService> SetupCommandService()
services.AddSingleton(new Dictionary<ulong, User>());
services.AddSingleton(new List<ScheduledJob>());
services.AddSingleton(new GeneralStorage());
services.AddSingleton(new State());
services.AddSingleton(new TransientState());
services.AddSingleton(new QuoteStorage());

services.AddSingleton<ConfigDescriber>();
Expand Down
3 changes: 2 additions & 1 deletion Izzy-MoonbotTests/Tests/ModMiscModuleTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public class ModMiscModuleTests
var ss = new ScheduleService(cfg, mod, modLog, logger, scheduledJobs);

var users = new Dictionary<ulong, User>();
return (ss, new ModMiscModule(cfg, users, ss, logger));
var state = new TransientState();
return (ss, new ModMiscModule(cfg, users, ss, logger, state));
}

[TestMethod()]
Expand Down
4 changes: 2 additions & 2 deletions Izzy-MoonbotTests/Tests/RaidServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ namespace Izzy_Moonbot_Tests.Services;
[TestClass()]
public class RaidServiceTests
{
public static (RaidService, ScheduleService, State) SetupRaidService(Config cfg, Dictionary<ulong, User> users)
public static (RaidService, ScheduleService, TransientState) SetupRaidService(Config cfg, Dictionary<ulong, User> users)
{
var mod = new ModService(cfg, users);
var modLog = new ModLoggingService(cfg);
var logger = new LoggingService(new TestLogger<Worker>());
var gs = new GeneralStorage();
var s = new State();
var s = new TransientState();

var scheduledJobs = new List<ScheduledJob>();
var ss = new ScheduleService(cfg, mod, modLog, logger, scheduledJobs);
Expand Down
6 changes: 3 additions & 3 deletions Izzy-MoonbotTests/Tests/SettingsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public void ConstructSettingsAndTypesObjects()
new DiscordSettings();
new GeneralStorage();
new QuoteStorage();
new State();
new TransientState();

new User();
new Dictionary<ulong, User>();
Expand Down Expand Up @@ -58,9 +58,9 @@ public void RoundTripSerializeSettingsObjects()
fileContents2 = JsonConvert.SerializeObject(quoteStorage2, Formatting.Indented);
Assert.AreEqual(fileContents, fileContents2);

var state = new State();
var state = new TransientState();
fileContents = JsonConvert.SerializeObject(state, Formatting.Indented);
var state2 = JsonConvert.DeserializeObject<State>(fileContents);
var state2 = JsonConvert.DeserializeObject<TransientState>(fileContents);
fileContents2 = JsonConvert.SerializeObject(state2, Formatting.Indented);
Assert.AreEqual(fileContents, fileContents2);
}
Expand Down

0 comments on commit e65ed63

Please sign in to comment.