elliebot/src/EllieBot/Modules/Administration/Prune/PruneService.cs

100 lines
3.2 KiB
C#
Raw Normal View History

2024-09-21 00:13:18 +12:00
#nullable disable
namespace EllieBot.Modules.Administration.Services;
2025-03-22 12:10:17 +13:00
public class PruneService(ILogCommandService logService) : IEService
2024-09-21 00:13:18 +12:00
{
private readonly ConcurrentDictionary<ulong, CancellationTokenSource> _pruningGuilds = new();
private readonly TimeSpan _twoWeeks = TimeSpan.FromDays(14);
public async Task<PruneResult> PruneWhere(
2025-03-22 12:10:17 +13:00
ulong runningUserId,
IMessageChannel channel,
2024-09-21 00:13:18 +12:00
int amount,
Func<IMessage, bool> predicate,
IProgress<(int deleted, int total)> progress,
ulong? after = null
)
{
ArgumentNullException.ThrowIfNull(channel, nameof(channel));
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(amount);
var originalAmount = amount;
var gid = (channel as ITextChannel)?.GuildId ?? channel.Id;
2024-09-21 00:13:18 +12:00
using var cancelSource = new CancellationTokenSource();
if (!_pruningGuilds.TryAdd(gid, cancelSource))
2024-09-21 00:13:18 +12:00
return PruneResult.AlreadyRunning;
try
{
var now = DateTime.UtcNow;
IMessage[] msgs;
IMessage lastMessage = null;
while (amount > 0 && !cancelSource.IsCancellationRequested)
{
var dled = lastMessage is null
? await channel.GetMessagesAsync(50).FlattenAsync()
: await channel.GetMessagesAsync(lastMessage, Direction.Before, 50).FlattenAsync();
msgs = dled
.Where(predicate)
.Where(x => after is not ulong a || x.Id > a)
.Take(amount)
.ToArray();
if (!msgs.Any())
return PruneResult.Success;
lastMessage = msgs[^1];
var bulkDeletable = new List<IMessage>();
var singleDeletable = new List<IMessage>();
foreach (var x in msgs)
{
2025-03-22 12:10:17 +13:00
logService.AddDeleteIgnore(x.Id);
2024-09-21 00:13:18 +12:00
if (now - x.CreatedAt < _twoWeeks)
bulkDeletable.Add(x);
else
singleDeletable.Add(x);
}
if (channel is ITextChannel tc2 && bulkDeletable.Count > 0)
2024-09-21 00:13:18 +12:00
{
await tc2.DeleteMessagesAsync(bulkDeletable);
2024-09-21 00:13:18 +12:00
amount -= msgs.Length;
progress.Report((originalAmount - amount, originalAmount));
await Task.Delay(2000, cancelSource.Token);
}
foreach (var group in singleDeletable.Chunk(5))
{
await group.Select(x => x.DeleteAsync()).WhenAll();
amount -= 5;
progress.Report((originalAmount - amount, originalAmount));
await Task.Delay(5000, cancelSource.Token);
}
}
}
catch
{
//ignore
}
finally
{
_pruningGuilds.TryRemove(gid, out _);
2024-09-21 00:13:18 +12:00
}
return PruneResult.Success;
}
public async Task<bool> CancelAsync(ulong guildId)
{
if (!_pruningGuilds.TryRemove(guildId, out var source))
return false;
await source.CancelAsync();
return true;
}
}