Restructured the project structure back to the way it was, there's no reasonable way to split the modules

This commit is contained in:
Kwoth
2024-04-26 22:26:24 +00:00
parent 6c9c8bf63e
commit e0819f760c
768 changed files with 192 additions and 1047 deletions

View File

@@ -0,0 +1,77 @@
#nullable disable
using NadekoBot.Modules.Administration.Services;
namespace NadekoBot.Modules.Administration;
public partial class Administration
{
[Group]
public partial class VcRoleCommands : NadekoModule<VcRoleService>
{
[Cmd]
[UserPerm(GuildPerm.ManageRoles)]
[BotPerm(GuildPerm.ManageRoles)]
[RequireContext(ContextType.Guild)]
public async Task VcRoleRm(ulong vcId)
{
if (_service.RemoveVcRole(ctx.Guild.Id, vcId))
await ReplyConfirmLocalizedAsync(strs.vcrole_removed(Format.Bold(vcId.ToString())));
else
await ReplyErrorLocalizedAsync(strs.vcrole_not_found);
}
[Cmd]
[UserPerm(GuildPerm.ManageRoles)]
[BotPerm(GuildPerm.ManageRoles)]
[RequireContext(ContextType.Guild)]
public async Task VcRole([Leftover] IRole role = null)
{
var user = (IGuildUser)ctx.User;
var vc = user.VoiceChannel;
if (vc is null || vc.GuildId != user.GuildId)
{
await ReplyErrorLocalizedAsync(strs.must_be_in_voice);
return;
}
if (role is null)
{
if (_service.RemoveVcRole(ctx.Guild.Id, vc.Id))
await ReplyConfirmLocalizedAsync(strs.vcrole_removed(Format.Bold(vc.Name)));
}
else
{
_service.AddVcRole(ctx.Guild.Id, role, vc.Id);
await ReplyConfirmLocalizedAsync(strs.vcrole_added(Format.Bold(vc.Name), Format.Bold(role.Name)));
}
}
[Cmd]
[RequireContext(ContextType.Guild)]
public async Task VcRoleList()
{
var guild = (SocketGuild)ctx.Guild;
string text;
if (_service.VcRoles.TryGetValue(ctx.Guild.Id, out var roles))
{
if (!roles.Any())
text = GetText(strs.no_vcroles);
else
{
text = string.Join("\n",
roles.Select(x
=> $"{Format.Bold(guild.GetVoiceChannel(x.Key)?.Name ?? x.Key.ToString())} => {x.Value}"));
}
}
else
text = GetText(strs.no_vcroles);
await ctx.Channel.EmbedAsync(_eb.Create()
.WithOkColor()
.WithTitle(GetText(strs.vc_role_list))
.WithDescription(text));
}
}
}

View File

@@ -0,0 +1,209 @@
#nullable disable
using Microsoft.EntityFrameworkCore;
using NadekoBot.Db;
using Nadeko.Bot.Db.Models;
namespace NadekoBot.Modules.Administration.Services;
public class VcRoleService : INService
{
public ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, IRole>> VcRoles { get; }
public ConcurrentDictionary<ulong, System.Collections.Concurrent.ConcurrentQueue<(bool, IGuildUser, IRole)>> ToAssign { get; }
private readonly DbService _db;
private readonly DiscordSocketClient _client;
public VcRoleService(DiscordSocketClient client, IBot bot, DbService db)
{
_db = db;
_client = client;
_client.UserVoiceStateUpdated += ClientOnUserVoiceStateUpdated;
VcRoles = new();
ToAssign = new();
using (var uow = db.GetDbContext())
{
var guildIds = client.Guilds.Select(x => x.Id).ToList();
uow.Set<GuildConfig>()
.AsQueryable()
.Include(x => x.VcRoleInfos)
.Where(x => guildIds.Contains(x.GuildId))
.AsEnumerable()
.Select(InitializeVcRole)
.WhenAll();
}
Task.Run(async () =>
{
while (true)
{
Task Selector(System.Collections.Concurrent.ConcurrentQueue<(bool, IGuildUser, IRole)> queue)
{
return Task.Run(async () =>
{
while (queue.TryDequeue(out var item))
{
var (add, user, role) = item;
try
{
if (add)
{
if (!user.RoleIds.Contains(role.Id))
await user.AddRoleAsync(role);
}
else
{
if (user.RoleIds.Contains(role.Id))
await user.RemoveRoleAsync(role);
}
}
catch
{
}
await Task.Delay(250);
}
});
}
await ToAssign.Values.Select(Selector).Append(Task.Delay(1000)).WhenAll();
}
});
_client.LeftGuild += _client_LeftGuild;
bot.JoinedGuild += Bot_JoinedGuild;
}
private Task Bot_JoinedGuild(GuildConfig arg)
{
// includeall no longer loads vcrole
// need to load new guildconfig with vc role included
using (var uow = _db.GetDbContext())
{
var configWithVcRole = uow.GuildConfigsForId(arg.GuildId, set => set.Include(x => x.VcRoleInfos));
_ = InitializeVcRole(configWithVcRole);
}
return Task.CompletedTask;
}
private Task _client_LeftGuild(SocketGuild arg)
{
VcRoles.TryRemove(arg.Id, out _);
ToAssign.TryRemove(arg.Id, out _);
return Task.CompletedTask;
}
private async Task InitializeVcRole(GuildConfig gconf)
{
var g = _client.GetGuild(gconf.GuildId);
if (g is null)
return;
var infos = new ConcurrentDictionary<ulong, IRole>();
var missingRoles = new List<VcRoleInfo>();
VcRoles.AddOrUpdate(gconf.GuildId, infos, delegate { return infos; });
foreach (var ri in gconf.VcRoleInfos)
{
var role = g.GetRole(ri.RoleId);
if (role is null)
{
missingRoles.Add(ri);
continue;
}
infos.TryAdd(ri.VoiceChannelId, role);
}
if (missingRoles.Any())
{
await using var uow = _db.GetDbContext();
uow.RemoveRange(missingRoles);
await uow.SaveChangesAsync();
Log.Warning("Removed {MissingRoleCount} missing roles from {ServiceName}",
missingRoles.Count,
nameof(VcRoleService));
}
}
public void AddVcRole(ulong guildId, IRole role, ulong vcId)
{
if (role is null)
throw new ArgumentNullException(nameof(role));
var guildVcRoles = VcRoles.GetOrAdd(guildId, new ConcurrentDictionary<ulong, IRole>());
guildVcRoles.AddOrUpdate(vcId, role, (_, _) => role);
using var uow = _db.GetDbContext();
var conf = uow.GuildConfigsForId(guildId, set => set.Include(x => x.VcRoleInfos));
var toDelete = conf.VcRoleInfos.FirstOrDefault(x => x.VoiceChannelId == vcId); // remove old one
if (toDelete is not null)
uow.Remove(toDelete);
conf.VcRoleInfos.Add(new()
{
VoiceChannelId = vcId,
RoleId = role.Id
}); // add new one
uow.SaveChanges();
}
public bool RemoveVcRole(ulong guildId, ulong vcId)
{
if (!VcRoles.TryGetValue(guildId, out var guildVcRoles))
return false;
if (!guildVcRoles.TryRemove(vcId, out _))
return false;
using var uow = _db.GetDbContext();
var conf = uow.GuildConfigsForId(guildId, set => set.Include(x => x.VcRoleInfos));
var toRemove = conf.VcRoleInfos.Where(x => x.VoiceChannelId == vcId).ToList();
uow.RemoveRange(toRemove);
uow.SaveChanges();
return true;
}
private Task ClientOnUserVoiceStateUpdated(SocketUser usr, SocketVoiceState oldState, SocketVoiceState newState)
{
if (usr is not SocketGuildUser gusr)
return Task.CompletedTask;
var oldVc = oldState.VoiceChannel;
var newVc = newState.VoiceChannel;
_ = Task.Run(() =>
{
try
{
if (oldVc != newVc)
{
ulong guildId;
guildId = newVc?.Guild.Id ?? oldVc.Guild.Id;
if (VcRoles.TryGetValue(guildId, out var guildVcRoles))
{
//remove old
if (oldVc is not null && guildVcRoles.TryGetValue(oldVc.Id, out var role))
Assign(false, gusr, role);
//add new
if (newVc is not null && guildVcRoles.TryGetValue(newVc.Id, out role))
Assign(true, gusr, role);
}
}
}
catch (Exception ex)
{
Log.Warning(ex, "Error in VcRoleService VoiceStateUpdate");
}
});
return Task.CompletedTask;
}
private void Assign(bool v, SocketGuildUser gusr, IRole role)
{
var queue = ToAssign.GetOrAdd(gusr.Guild.Id, new System.Collections.Concurrent.ConcurrentQueue<(bool, IGuildUser, IRole)>());
queue.Enqueue((v, gusr, role));
}
}