-
Notifications
You must be signed in to change notification settings - Fork 47
/
Copy pathEmpathySimulationHandler.cs
104 lines (86 loc) · 3.84 KB
/
EmpathySimulationHandler.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
using System.Collections.Concurrent;
using Microsoft.Extensions.Caching.Memory;
namespace CompatBot.EventHandlers;
using TCache = ConcurrentDictionary<ulong, ConcurrentQueue<DiscordMessage>>;
internal static class EmpathySimulationHandler
{
private static readonly TCache MessageQueue = new();
internal static readonly TimeSpan ThrottleDuration = TimeSpan.FromHours(1);
internal static readonly MemoryCache Throttling = new(new MemoryCacheOptions {ExpirationScanFrequency = TimeSpan.FromMinutes(30)});
public static async Task OnMessageCreated(DiscordClient _, MessageCreatedEventArgs args)
{
if (DefaultHandlerFilter.IsFluff(args.Message))
return;
if (args.Channel.IsPrivate)
return;
if (args.Author.IsCurrent)
return;
if (args.Author.Id == 197163728867688448ul)
return;
if (!MessageQueue.TryGetValue(args.Channel.Id, out var queue))
MessageQueue[args.Channel.Id] = queue = new();
queue.Enqueue(args.Message);
while (queue.Count > 10)
queue.TryDequeue(out var _);
var content = args.Message.Content;
if (string.IsNullOrEmpty(content))
return;
//todo: throttle multiple strings at the same time
if (Throttling.TryGetValue(args.Channel.Id, out List<DiscordMessage>? mark)
&& mark is not null
&& content.Equals(mark.FirstOrDefault()?.Content, StringComparison.OrdinalIgnoreCase))
{
mark.Add(args.Message);
Config.Log.Debug($"Bailed out of repeating '{content}' due to throttling");
return;
}
var similarList = queue.Where(msg => content.Equals(msg.Content, StringComparison.OrdinalIgnoreCase)).ToList();
if (similarList.Count > 2)
{
var uniqueUsers = similarList.Select(msg => msg.Author.Id).Distinct().Count();
if (uniqueUsers > 2)
{
Throttling.Set(args.Channel.Id, similarList, ThrottleDuration);
var msgContent = GetAvgContent(similarList.Select(m => m.Content).ToList());
var botMsg = await args.Channel.SendMessageAsync(new DiscordMessageBuilder().WithContent(msgContent).AddMention(UserMention.All)).ConfigureAwait(false);
similarList.Add(botMsg);
}
else
Config.Log.Debug($"Bailed out of repeating '{content}' due to {uniqueUsers} unique users");
}
}
public static Task OnMessageUpdated(DiscordClient _, MessageUpdatedEventArgs e) => Backtrack(e.Channel, e.MessageBefore, false);
public static Task OnMessageDeleted(DiscordClient _, MessageDeletedEventArgs e) => Backtrack(e.Channel, e.Message, true);
private static async Task Backtrack(DiscordChannel channel, DiscordMessage? message, bool removeFromQueue)
{
if (channel.IsPrivate)
return;
if (message?.Author is null)
return;
if (message.Author.IsCurrent)
return;
if (!Throttling.TryGetValue(channel.Id, out List<DiscordMessage>? msgList) || msgList is null)
return;
if (msgList.Any(m => m.Id == message.Id))
{
var botMsg = msgList.Last();
if (botMsg.Id == message.Id)
return;
try
{
await channel.DeleteMessageAsync(botMsg).ConfigureAwait(false);
if (removeFromQueue)
MessageQueue.TryRemove(message.Id, out _);
}
catch { }
}
}
private static string GetAvgContent(List<string> samples)
{
var rng = new Random();
var result = new StringBuilder(samples[0].Length);
for (var i = 0; i < samples[0].Length; i++)
result.Append(samples[rng.Next(samples.Count)][i]);
return result.ToString();
}
}