mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 01:38:27 -04: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:
@@ -39,5 +39,27 @@ public partial class Administration
|
|||||||
|
|
||||||
await Response().Text("This guild's bot data will be saved.").SendAsync();
|
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.Data;
|
||||||
using LinqToDB.EntityFrameworkCore;
|
using LinqToDB.EntityFrameworkCore;
|
||||||
using LinqToDB.Mapping;
|
using LinqToDB.Mapping;
|
||||||
|
using LinqToDB.Tools;
|
||||||
using NadekoBot.Common.ModuleBehaviors;
|
using NadekoBot.Common.ModuleBehaviors;
|
||||||
using NadekoBot.Db.Models;
|
using NadekoBot.Db.Models;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Administration.DangerousCommands;
|
namespace NadekoBot.Modules.Administration.DangerousCommands;
|
||||||
|
|
||||||
public sealed class CleanupService : ICleanupService, IReadyExecutor, INService
|
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 readonly IPubSub _pubSub;
|
||||||
private TypedKey<KeepReport> _keepReportKey = new("cleanup:report");
|
|
||||||
private TypedKey<bool> _keepTriggerKey = new("cleanup:trigger");
|
|
||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private ConcurrentDictionary<int, ulong[]> guildIds = new();
|
private ConcurrentDictionary<int, ulong[]> guildIds = new();
|
||||||
private readonly IBotCredsProvider _creds;
|
private readonly IBotCredsProvider _creds;
|
||||||
@@ -29,11 +34,82 @@ public sealed class CleanupService : ICleanupService, IReadyExecutor, INService
|
|||||||
_db = db;
|
_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()
|
public async Task<KeepResult?> DeleteMissingGuildDataAsync()
|
||||||
{
|
{
|
||||||
guildIds = new();
|
guildIds = new();
|
||||||
var totalShards = _creds.GetCreds().TotalShards;
|
var totalShards = _creds.GetCreds().TotalShards;
|
||||||
await _pubSub.Pub(_keepTriggerKey, true);
|
await _pubSub.Pub(_cleanupTriggerKey, true);
|
||||||
var counter = 0;
|
var counter = 0;
|
||||||
while (guildIds.Keys.Count < totalShards)
|
while (guildIds.Keys.Count < totalShards)
|
||||||
{
|
{
|
||||||
@@ -133,10 +209,7 @@ public sealed class CleanupService : ICleanupService, IReadyExecutor, INService
|
|||||||
|
|
||||||
public async Task<bool> KeepGuild(ulong guildId)
|
public async Task<bool> KeepGuild(ulong guildId)
|
||||||
{
|
{
|
||||||
await using var db = _db.GetDbContext();
|
var table = await GetKeptGuildsTable();
|
||||||
await using var ctx = db.CreateLinqToDBContext();
|
|
||||||
|
|
||||||
var table = ctx.CreateTable<KeptGuilds>(tableOptions: TableOptions.CheckExistence);
|
|
||||||
|
|
||||||
if (await table.AnyAsyncLinqToDB(x => x.GuildId == guildId))
|
if (await table.AnyAsyncLinqToDB(x => x.GuildId == guildId))
|
||||||
return false;
|
return false;
|
||||||
@@ -149,30 +222,37 @@ public sealed class CleanupService : ICleanupService, IReadyExecutor, INService
|
|||||||
return true;
|
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)
|
private ValueTask OnKeepReport(KeepReport report)
|
||||||
{
|
{
|
||||||
guildIds[report.ShardId] = report.GuildIds;
|
guildIds[report.ShardId] = report.GuildIds;
|
||||||
return default;
|
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)
|
private async Task ClientOnJoinedGuild(SocketGuild arg)
|
||||||
{
|
{
|
||||||
await KeepGuild(arg.Id);
|
await KeepGuild(arg.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ValueTask OnKeepTrigger(bool arg)
|
private ValueTask OnCleanupTrigger(bool arg)
|
||||||
{
|
{
|
||||||
_pubSub.Pub(_keepReportKey,
|
_pubSub.Pub(_cleanupReportKey,
|
||||||
new KeepReport()
|
new KeepReport()
|
||||||
{
|
{
|
||||||
ShardId = _client.ShardId,
|
ShardId = _client.ShardId,
|
||||||
|
@@ -4,4 +4,6 @@ public interface ICleanupService
|
|||||||
{
|
{
|
||||||
Task<KeepResult?> DeleteMissingGuildDataAsync();
|
Task<KeepResult?> DeleteMissingGuildDataAsync();
|
||||||
Task<bool> KeepGuild(ulong guildId);
|
Task<bool> KeepGuild(ulong guildId);
|
||||||
|
Task<int> GetKeptGuildCount();
|
||||||
|
Task LeaveUnkeptServers();
|
||||||
}
|
}
|
@@ -1424,3 +1424,5 @@ afk:
|
|||||||
- afk
|
- afk
|
||||||
keep:
|
keep:
|
||||||
- keep
|
- keep
|
||||||
|
leaveunkeptservers:
|
||||||
|
- leaveunkeptservers
|
@@ -4556,3 +4556,10 @@ keep:
|
|||||||
- ''
|
- ''
|
||||||
params:
|
params:
|
||||||
- { }
|
- { }
|
||||||
|
leaveunkeptservers:
|
||||||
|
desc: |-
|
||||||
|
Leaves all servers whose owners didn't run .keep
|
||||||
|
ex:
|
||||||
|
- ''
|
||||||
|
params:
|
||||||
|
- { }
|
Reference in New Issue
Block a user