Custom reaction bufixes and perf improvements

This commit is contained in:
Kwoth 2017-01-29 04:30:21 +01:00
parent 17338396a4
commit d5c4d3f3d2
2 changed files with 72 additions and 37 deletions

View File

@ -10,14 +10,16 @@ using NadekoBot.Extensions;
using NLog; using NLog;
using System.Diagnostics; using System.Diagnostics;
using Discord.WebSocket; using Discord.WebSocket;
using System;
namespace NadekoBot.Modules.CustomReactions namespace NadekoBot.Modules.CustomReactions
{ {
[NadekoModule("CustomReactions", ".")] [NadekoModule("CustomReactions", ".")]
public class CustomReactions : DiscordModule public class CustomReactions : DiscordModule
{ {
public static ConcurrentHashSet<CustomReaction> GlobalReactions { get; } = new ConcurrentHashSet<CustomReaction>(); private static CustomReaction[] _globalReactions = new CustomReaction[] { };
public static ConcurrentDictionary<ulong, ConcurrentHashSet<CustomReaction>> GuildReactions { get; } = new ConcurrentDictionary<ulong, ConcurrentHashSet<CustomReaction>>(); public static CustomReaction[] GlobalReactions => _globalReactions;
public static ConcurrentDictionary<ulong, CustomReaction[]> GuildReactions { get; } = new ConcurrentDictionary<ulong, CustomReaction[]>();
public static ConcurrentDictionary<string, uint> ReactionStats { get; } = new ConcurrentDictionary<string, uint>(); public static ConcurrentDictionary<string, uint> ReactionStats { get; } = new ConcurrentDictionary<string, uint>();
@ -30,8 +32,8 @@ namespace NadekoBot.Modules.CustomReactions
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
var items = uow.CustomReactions.GetAll(); var items = uow.CustomReactions.GetAll();
GuildReactions = new ConcurrentDictionary<ulong, ConcurrentHashSet<CustomReaction>>(items.Where(g => g.GuildId != null && g.GuildId != 0).GroupBy(k => k.GuildId.Value).ToDictionary(g => g.Key, g => new ConcurrentHashSet<CustomReaction>(g))); GuildReactions = new ConcurrentDictionary<ulong, CustomReaction[]>(items.Where(g => g.GuildId != null && g.GuildId != 0).GroupBy(k => k.GuildId.Value).ToDictionary(g => g.Key, g => g.ToArray()));
GlobalReactions = new ConcurrentHashSet<CustomReaction>(items.Where(g => g.GuildId == null || g.GuildId == 0)); _globalReactions = items.Where(g => g.GuildId == null || g.GuildId == 0).ToArray();
} }
sw.Stop(); sw.Stop();
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
@ -46,32 +48,46 @@ namespace NadekoBot.Modules.CustomReactions
return false; return false;
var content = umsg.Content.Trim().ToLowerInvariant(); var content = umsg.Content.Trim().ToLowerInvariant();
ConcurrentHashSet<CustomReaction> reactions; CustomReaction[] reactions;
GuildReactions.TryGetValue(channel.Guild.Id, out reactions); GuildReactions.TryGetValue(channel.Guild.Id, out reactions);
if (reactions != null && reactions.Any()) if (reactions != null && reactions.Any())
{ {
var reaction = reactions.Where(cr => var rs = reactions.Where(cr =>
{ {
if (cr == null)
return false;
var hasTarget = cr.Response.ToLowerInvariant().Contains("%target%"); var hasTarget = cr.Response.ToLowerInvariant().Contains("%target%");
var trigger = cr.TriggerWithContext(umsg).Trim().ToLowerInvariant(); var trigger = cr.TriggerWithContext(umsg).Trim().ToLowerInvariant();
return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger); return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger);
}).Shuffle().FirstOrDefault(); }).ToArray();
if (reaction != null)
{
if (reaction.Response != "-")
try { await channel.SendMessageAsync(reaction.ResponseWithContext(umsg)).ConfigureAwait(false); } catch { }
ReactionStats.AddOrUpdate(reaction.Trigger, 1, (k, old) => ++old); if (rs.Length != 0)
return true; {
var reaction = rs[new NadekoRandom().Next(0, rs.Length)];
if (reaction != null)
{
if (reaction.Response != "-")
try { await channel.SendMessageAsync(reaction.ResponseWithContext(umsg)).ConfigureAwait(false); } catch { }
ReactionStats.AddOrUpdate(reaction.Trigger, 1, (k, old) => ++old);
return true;
}
} }
} }
var greaction = GlobalReactions.Where(cr =>
var grs = GlobalReactions.Where(cr =>
{ {
if (cr == null)
return false;
var hasTarget = cr.Response.ToLowerInvariant().Contains("%target%"); var hasTarget = cr.Response.ToLowerInvariant().Contains("%target%");
var trigger = cr.TriggerWithContext(umsg).Trim().ToLowerInvariant(); var trigger = cr.TriggerWithContext(umsg).Trim().ToLowerInvariant();
return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger); return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger);
}).Shuffle().FirstOrDefault(); }).ToArray();
if (grs.Length == 0)
return false;
var greaction = grs[new NadekoRandom().Next(0, grs.Length)];
if (greaction != null) if (greaction != null)
{ {
@ -114,12 +130,19 @@ namespace NadekoBot.Modules.CustomReactions
if (channel == null) if (channel == null)
{ {
GlobalReactions.Add(cr); Array.Resize(ref _globalReactions, _globalReactions.Length + 1);
_globalReactions[_globalReactions.Length - 1] = cr;
} }
else else
{ {
var reactions = GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet<CustomReaction>()); var reactions = GuildReactions.AddOrUpdate(Context.Guild.Id,
reactions.Add(cr); Array.Empty<CustomReaction>(),
(k, old) =>
{
Array.Resize(ref old, old.Length + 1);
old[old.Length - 1] = cr;
return old;
});
} }
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
@ -136,17 +159,17 @@ namespace NadekoBot.Modules.CustomReactions
{ {
if (page < 1 || page > 1000) if (page < 1 || page > 1000)
return; return;
ConcurrentHashSet<CustomReaction> customReactions; CustomReaction[] customReactions;
if (Context.Guild == null) if (Context.Guild == null)
customReactions = GlobalReactions; customReactions = GlobalReactions.Where(cr => cr != null).ToArray();
else else
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet<CustomReaction>()); customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, Array.Empty<CustomReaction>()).Where(cr => cr != null).ToArray();
if (customReactions == null || !customReactions.Any()) if (customReactions == null || !customReactions.Any())
await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false); await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false);
else else
{ {
var lastPage = customReactions.Count / 20; var lastPage = customReactions.Length / 20;
await Context.Channel.SendPaginatedConfirmAsync(page, curPage => await Context.Channel.SendPaginatedConfirmAsync(page, curPage =>
new EmbedBuilder().WithOkColor() new EmbedBuilder().WithOkColor()
.WithTitle("Custom reactions") .WithTitle("Custom reactions")
@ -167,11 +190,11 @@ namespace NadekoBot.Modules.CustomReactions
[Priority(1)] [Priority(1)]
public async Task ListCustReact(All x) public async Task ListCustReact(All x)
{ {
ConcurrentHashSet<CustomReaction> customReactions; CustomReaction[] customReactions;
if (Context.Guild == null) if (Context.Guild == null)
customReactions = GlobalReactions; customReactions = GlobalReactions.Where(cr => cr != null).ToArray();
else else
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet<CustomReaction>()); customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new CustomReaction[]{ }).Where(cr => cr != null).ToArray();
if (customReactions == null || !customReactions.Any()) if (customReactions == null || !customReactions.Any())
await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false); await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false);
@ -195,11 +218,11 @@ namespace NadekoBot.Modules.CustomReactions
{ {
if (page < 1 || page > 10000) if (page < 1 || page > 10000)
return; return;
ConcurrentHashSet<CustomReaction> customReactions; CustomReaction[] customReactions;
if (Context.Guild == null) if (Context.Guild == null)
customReactions = GlobalReactions; customReactions = GlobalReactions.Where(cr => cr != null).ToArray();
else else
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet<CustomReaction>()); customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new CustomReaction[]{ }).Where(cr => cr != null).ToArray();
if (customReactions == null || !customReactions.Any()) if (customReactions == null || !customReactions.Any())
await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false); await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false);
@ -225,13 +248,13 @@ namespace NadekoBot.Modules.CustomReactions
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
public async Task ShowCustReact(int id) public async Task ShowCustReact(int id)
{ {
ConcurrentHashSet<CustomReaction> customReactions; CustomReaction[] customReactions;
if (Context.Guild == null) if (Context.Guild == null)
customReactions = GlobalReactions; customReactions = GlobalReactions;
else else
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet<CustomReaction>()); customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new CustomReaction[]{ });
var found = customReactions.FirstOrDefault(cr => cr.Id == id); var found = customReactions.FirstOrDefault(cr => cr?.Id == id);
if (found == null) if (found == null)
await Context.Channel.SendErrorAsync("No custom reaction found with that id.").ConfigureAwait(false); await Context.Channel.SendErrorAsync("No custom reaction found with that id.").ConfigureAwait(false);
@ -265,13 +288,17 @@ namespace NadekoBot.Modules.CustomReactions
if ((toDelete.GuildId == null || toDelete.GuildId == 0) && Context.Guild == null) if ((toDelete.GuildId == null || toDelete.GuildId == 0) && Context.Guild == null)
{ {
uow.CustomReactions.Remove(toDelete); uow.CustomReactions.Remove(toDelete);
GlobalReactions.RemoveWhere(cr => cr.Id == toDelete.Id); //todo i can dramatically improve performance of this, if Ids are ordered.
_globalReactions = GlobalReactions.Where(cr => cr?.Id != toDelete.Id).ToArray();
success = true; success = true;
} }
else if ((toDelete.GuildId != null && toDelete.GuildId != 0) && Context.Guild.Id == toDelete.GuildId) else if ((toDelete.GuildId != null && toDelete.GuildId != 0) && Context.Guild.Id == toDelete.GuildId)
{ {
uow.CustomReactions.Remove(toDelete); uow.CustomReactions.Remove(toDelete);
GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet<CustomReaction>()).RemoveWhere(cr => cr.Id == toDelete.Id); GuildReactions.AddOrUpdate(Context.Guild.Id, new CustomReaction[] { }, (key, old) =>
{
return old.Where(cr => cr?.Id != toDelete.Id).ToArray();
});
success = true; success = true;
} }
if (success) if (success)
@ -312,8 +339,10 @@ namespace NadekoBot.Modules.CustomReactions
{ {
if (page < 1) if (page < 1)
return; return;
var ordered = ReactionStats.OrderByDescending(x => x.Value).ToList(); var ordered = ReactionStats.OrderByDescending(x => x.Value).ToArray();
var lastPage = ordered.Count / 9; if (!ordered.Any())
return;
var lastPage = ordered.Length / 9;
await Context.Channel.SendPaginatedConfirmAsync(page, await Context.Channel.SendPaginatedConfirmAsync(page,
(curPage) => ordered.Skip((curPage - 1) * 9) (curPage) => ordered.Skip((curPage - 1) * 9)
.Take(9) .Take(9)

View File

@ -1,9 +1,11 @@
using Discord; using Discord;
using Discord.WebSocket;
using NadekoBot.Extensions; using NadekoBot.Extensions;
using NadekoBot.Services; using NadekoBot.Services;
using NadekoBot.Services.Database.Models; using NadekoBot.Services.Database.Models;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@ -25,9 +27,13 @@ namespace NadekoBot.Modules.CustomReactions
if(ch == null) if(ch == null)
return ""; return "";
var usrs = (ch.Guild.GetUsersAsync().GetAwaiter().GetResult()); var g = ch.Guild as SocketGuild;
if(g == null)
return "";
return usrs.Skip(new NadekoRandom().Next(0,usrs.Count-1)).Shuffle().FirstOrDefault()?.Mention ?? ""; var users = g.Users.ToArray();
return users[new NadekoRandom().Next(0, users.Length-1)].Mention;
} } } }
//{"%rng%", (ctx) => { return new NadekoRandom().Next(0,10).ToString(); } } //{"%rng%", (ctx) => { return new NadekoRandom().Next(0,10).ToString(); } }
}; };