Implemented .leaveunkeptservers which will cause the bot to leave all...
Implemented .leaveunkeptservers which will cause the bot to leave all servers unmarked by .keep. Extremely dangerous and irreversible. Meant for use on public bot.
This commit is contained in:
parent
37438f33a2
commit
ec403bbe5d
5 changed files with 134 additions and 21 deletions
|
@ -39,5 +39,27 @@ public partial class Administration
|
|||
|
||||
await Response().Text("This guild's bot data will be saved.").SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public async Task LeaveUnkeptServers()
|
||||
{
|
||||
var keptGuildCount = await _svc.GetKeptGuildCount();
|
||||
|
||||
var response = await PromptUserConfirmAsync(new EmbedBuilder()
|
||||
.WithDescription($"""
|
||||
Do you want the bot to leave all unkept servers?
|
||||
|
||||
There are currently {keptGuildCount} kept servers.
|
||||
|
||||
**This is a highly destructive and irreversible action.**
|
||||
"""));
|
||||
|
||||
if (!response)
|
||||
return;
|
||||
|
||||
await _svc.LeaveUnkeptServers();
|
||||
await ctx.OkAsync();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,16 +2,21 @@
|
|||
using LinqToDB.Data;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using LinqToDB.Mapping;
|
||||
using LinqToDB.Tools;
|
||||
using EllieBot.Common.ModuleBehaviors;
|
||||
using EllieBot.Db.Models;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace EllieBot.Modules.Administration.DangerousCommands;
|
||||
|
||||
public sealed class CleanupService : ICleanupService, IReadyExecutor, IEService
|
||||
{
|
||||
private TypedKey<KeepReport> _cleanupReportKey = new("cleanup:report");
|
||||
private TypedKey<bool> _cleanupTriggerKey = new("cleanup:trigger");
|
||||
|
||||
private TypedKey<bool> _keepTriggerKey = new("keep:trigger");
|
||||
|
||||
private readonly IPubSub _pubSub;
|
||||
private TypedKey<KeepReport> _keepReportKey = new("cleanup:report");
|
||||
private TypedKey<bool> _keepTriggerKey = new("cleanup:trigger");
|
||||
private readonly DiscordSocketClient _client;
|
||||
private ConcurrentDictionary<int, ulong[]> guildIds = new();
|
||||
private readonly IBotCredsProvider _creds;
|
||||
|
@ -29,11 +34,82 @@ public sealed class CleanupService : ICleanupService, IReadyExecutor, IEService
|
|||
_db = db;
|
||||
}
|
||||
|
||||
public async Task OnReadyAsync()
|
||||
{
|
||||
await _pubSub.Sub(_cleanupTriggerKey, OnCleanupTrigger);
|
||||
await _pubSub.Sub(_keepTriggerKey, InternalTriggerKeep);
|
||||
|
||||
_client.JoinedGuild += ClientOnJoinedGuild;
|
||||
|
||||
if (_client.ShardId == 0)
|
||||
await _pubSub.Sub(_cleanupReportKey, OnKeepReport);
|
||||
}
|
||||
|
||||
private bool keepTriggered = false;
|
||||
|
||||
private async ValueTask InternalTriggerKeep(bool arg)
|
||||
{
|
||||
if (keepTriggered)
|
||||
return;
|
||||
|
||||
keepTriggered = true;
|
||||
try
|
||||
{
|
||||
await Task.Delay(10 + (10 * _client.ShardId));
|
||||
|
||||
var allGuildIds = _client.Guilds.Select(x => x.Id);
|
||||
|
||||
var table = await GetKeptGuildsTable();
|
||||
|
||||
var dontDeleteList = await table
|
||||
.Where(x => allGuildIds.Contains(x.GuildId))
|
||||
.Select(x => x.GuildId)
|
||||
.ToListAsyncLinqToDB();
|
||||
|
||||
var dontDelete = dontDeleteList.ToHashSet();
|
||||
|
||||
guildIds = new();
|
||||
foreach (var guildId in allGuildIds)
|
||||
{
|
||||
if (dontDelete.Contains(guildId))
|
||||
continue;
|
||||
|
||||
// 1 leave per 20 seconds per shard
|
||||
await Task.Delay(RandomNumberGenerator.GetInt32(18_000, 22_000));
|
||||
|
||||
SocketGuild? guild = null;
|
||||
try
|
||||
{
|
||||
guild = _client.GetGuild(guildId);
|
||||
|
||||
if (guild is null)
|
||||
{
|
||||
Log.Warning("Unable to find guild {GuildId}", guildId);
|
||||
continue;
|
||||
}
|
||||
|
||||
await guild.LeaveAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning("Unable to leave guild {GuildName} [{GuildId}]: {ErrorMessage}",
|
||||
guild?.Name,
|
||||
guildId,
|
||||
ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
keepTriggered = false;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<KeepResult?> DeleteMissingGuildDataAsync()
|
||||
{
|
||||
guildIds = new();
|
||||
var totalShards = _creds.GetCreds().TotalShards;
|
||||
await _pubSub.Pub(_keepTriggerKey, true);
|
||||
await _pubSub.Pub(_cleanupTriggerKey, true);
|
||||
var counter = 0;
|
||||
while (guildIds.Keys.Count < totalShards)
|
||||
{
|
||||
|
@ -133,10 +209,7 @@ public sealed class CleanupService : ICleanupService, IReadyExecutor, IEService
|
|||
|
||||
public async Task<bool> KeepGuild(ulong guildId)
|
||||
{
|
||||
await using var db = _db.GetDbContext();
|
||||
await using var ctx = db.CreateLinqToDBContext();
|
||||
|
||||
var table = ctx.CreateTable<KeptGuilds>(tableOptions: TableOptions.CheckExistence);
|
||||
var table = await GetKeptGuildsTable();
|
||||
|
||||
if (await table.AnyAsyncLinqToDB(x => x.GuildId == guildId))
|
||||
return false;
|
||||
|
@ -149,30 +222,37 @@ public sealed class CleanupService : ICleanupService, IReadyExecutor, IEService
|
|||
return true;
|
||||
}
|
||||
|
||||
public async Task<int> GetKeptGuildCount()
|
||||
{
|
||||
var table = await GetKeptGuildsTable();
|
||||
return await table.CountAsync();
|
||||
}
|
||||
|
||||
private async Task<ITable<KeptGuilds>> GetKeptGuildsTable()
|
||||
{
|
||||
await using var db = _db.GetDbContext();
|
||||
await using var ctx = db.CreateLinqToDBContext();
|
||||
var table = ctx.CreateTable<KeptGuilds>(tableOptions: TableOptions.CheckExistence);
|
||||
return table;
|
||||
}
|
||||
|
||||
public async Task LeaveUnkeptServers()
|
||||
=> await _pubSub.Pub(_keepTriggerKey, true);
|
||||
|
||||
private ValueTask OnKeepReport(KeepReport report)
|
||||
{
|
||||
guildIds[report.ShardId] = report.GuildIds;
|
||||
return default;
|
||||
}
|
||||
|
||||
public async Task OnReadyAsync()
|
||||
{
|
||||
await _pubSub.Sub(_keepTriggerKey, OnKeepTrigger);
|
||||
|
||||
_client.JoinedGuild += ClientOnJoinedGuild;
|
||||
|
||||
if (_client.ShardId == 0)
|
||||
await _pubSub.Sub(_keepReportKey, OnKeepReport);
|
||||
}
|
||||
|
||||
private async Task ClientOnJoinedGuild(SocketGuild arg)
|
||||
{
|
||||
await KeepGuild(arg.Id);
|
||||
}
|
||||
|
||||
private ValueTask OnKeepTrigger(bool arg)
|
||||
private ValueTask OnCleanupTrigger(bool arg)
|
||||
{
|
||||
_pubSub.Pub(_keepReportKey,
|
||||
_pubSub.Pub(_cleanupReportKey,
|
||||
new KeepReport()
|
||||
{
|
||||
ShardId = _client.ShardId,
|
||||
|
|
|
@ -4,4 +4,6 @@ public interface ICleanupService
|
|||
{
|
||||
Task<KeepResult?> DeleteMissingGuildDataAsync();
|
||||
Task<bool> KeepGuild(ulong guildId);
|
||||
Task<int> GetKeptGuildCount();
|
||||
Task LeaveUnkeptServers();
|
||||
}
|
|
@ -1424,3 +1424,5 @@ afk:
|
|||
- afk
|
||||
keep:
|
||||
- keep
|
||||
leaveunkeptservers:
|
||||
- leaveunkeptservers
|
|
@ -4556,3 +4556,10 @@ keep:
|
|||
- ''
|
||||
params:
|
||||
- { }
|
||||
leaveunkeptservers:
|
||||
desc: |-
|
||||
Leaves all servers whose owners didn't run .keep
|
||||
ex:
|
||||
- ''
|
||||
params:
|
||||
- { }
|
Loading…
Reference in a new issue