mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2024-10-02 12:09:07 +00:00
add: 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
67b186a1a5
commit
9424d4d5f9
5 changed files with 134 additions and 21 deletions
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace NadekoBot.Modules.Administration;
|
||||
|
||||
public partial class Administration
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public partial class CleanupCommands : CleanupModuleBase
|
||||
|
@ -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 NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Db.Models;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.DangerousCommands;
|
||||
|
||||
public sealed class CleanupService : ICleanupService, IReadyExecutor, INService
|
||||
{
|
||||
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, INService
|
|||
_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,11 +209,8 @@ public sealed class CleanupService : ICleanupService, IReadyExecutor, INService
|
|||
|
||||
public async Task<bool> KeepGuild(ulong guildId)
|
||||
{
|
||||
await using var db = _db.GetDbContext();
|
||||
await using var ctx = db.CreateLinqToDBContext();
|
||||
var table = await GetKeptGuildsTable();
|
||||
|
||||
var table = ctx.CreateTable<KeptGuilds>(tableOptions: TableOptions.CheckExistence);
|
||||
|
||||
if (await table.AnyAsyncLinqToDB(x => x.GuildId == guildId))
|
||||
return false;
|
||||
|
||||
|
@ -149,30 +222,37 @@ public sealed class CleanupService : ICleanupService, IReadyExecutor, INService
|
|||
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();
|
||||
}
|
|
@ -1423,4 +1423,6 @@ coins:
|
|||
afk:
|
||||
- afk
|
||||
keep:
|
||||
- keep
|
||||
- keep
|
||||
leaveunkeptservers:
|
||||
- leaveunkeptservers
|
|
@ -4554,5 +4554,12 @@ keep:
|
|||
The current serve, won't be deleted from Nadeko's database during the purge.
|
||||
ex:
|
||||
- ''
|
||||
params:
|
||||
- { }
|
||||
leaveunkeptservers:
|
||||
desc: |-
|
||||
Leaves all servers whose owners didn't run .keep
|
||||
ex:
|
||||
- ''
|
||||
params:
|
||||
- { }
|
Loading…
Reference in a new issue