Global custom reactions now use redis pub/sub

This commit is contained in:
Master Kwoth 2017-09-13 03:12:40 +02:00
parent 438f68cde7
commit a2c4695557
5 changed files with 51 additions and 11 deletions

View File

@ -58,8 +58,7 @@ namespace NadekoBot.Modules.CustomReactions
if (channel == null) if (channel == null)
{ {
Array.Resize(ref _service.GlobalReactions, _service.GlobalReactions.Length + 1); await _service.AddGcr(cr).ConfigureAwait(false);
_service.GlobalReactions[_service.GlobalReactions.Length - 1] = cr;
} }
else else
{ {
@ -237,8 +236,7 @@ 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);
//todo 91 i can dramatically improve performance of this, if Ids are ordered. await _service.DelGcr(toDelete.Id);
_service.GlobalReactions = _service.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)

View File

@ -15,6 +15,7 @@ using NadekoBot.Modules.CustomReactions.Extensions;
using NadekoBot.Modules.Permissions.Common; using NadekoBot.Modules.Permissions.Common;
using NadekoBot.Modules.Permissions.Services; using NadekoBot.Modules.Permissions.Services;
using NadekoBot.Services.Impl; using NadekoBot.Services.Impl;
using Newtonsoft.Json;
namespace NadekoBot.Modules.CustomReactions.Services namespace NadekoBot.Modules.CustomReactions.Services
{ {
@ -32,9 +33,11 @@ namespace NadekoBot.Modules.CustomReactions.Services
private readonly CommandHandler _cmd; private readonly CommandHandler _cmd;
private readonly IBotConfigProvider _bc; private readonly IBotConfigProvider _bc;
private readonly NadekoStrings _strings; private readonly NadekoStrings _strings;
private readonly IDataCache _cache;
public CustomReactionsService(PermissionService perms, DbService db, NadekoStrings strings, public CustomReactionsService(PermissionService perms, DbService db, NadekoStrings strings,
DiscordSocketClient client, CommandHandler cmd, IBotConfigProvider bc, IUnitOfWork uow) DiscordSocketClient client, CommandHandler cmd, IBotConfigProvider bc, IUnitOfWork uow,
IDataCache cache)
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
_db = db; _db = db;
@ -43,10 +46,42 @@ namespace NadekoBot.Modules.CustomReactions.Services
_cmd = cmd; _cmd = cmd;
_bc = bc; _bc = bc;
_strings = strings; _strings = strings;
_cache = cache;
var sub = _cache.Redis.GetSubscriber();
sub.Subscribe("gcr.added", (ch, msg) =>
{
Array.Resize(ref GlobalReactions, GlobalReactions.Length + 1);
GlobalReactions[GlobalReactions.Length - 1] = JsonConvert.DeserializeObject<CustomReaction>(msg);
}, StackExchange.Redis.CommandFlags.FireAndForget);
sub.Subscribe("gcr.deleted", (ch, msg) =>
{
var id = int.Parse(msg);
GlobalReactions = GlobalReactions.Where(cr => cr?.Id != id).ToArray();
}, StackExchange.Redis.CommandFlags.FireAndForget);
var items = uow.CustomReactions.GetAll(); var items = uow.CustomReactions.GetAll();
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())); 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 = items.Where(g => g.GuildId == null || g.GuildId == 0).ToArray(); GlobalReactions = items.Where(g => g.GuildId == null || g.GuildId == 0).ToArray();
foreach (var item in items)
{
_log.Info(item.Id);
_log.Info(item.Trigger);
_log.Info(item.GuildId);
}
}
public Task AddGcr(CustomReaction cr)
{
var sub = _cache.Redis.GetSubscriber();
return sub.PublishAsync("gcr.added", JsonConvert.SerializeObject(cr));
}
public Task DelGcr(int id)
{
var sub = _cache.Redis.GetSubscriber();
return sub.PublishAsync("gcr.deleted", id);
} }
public void ClearStats() => ReactionStats.Clear(); public void ClearStats() => ReactionStats.Clear();

View File

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations.Schema; using Newtonsoft.Json;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace NadekoBot.Services.Database.Models namespace NadekoBot.Services.Database.Models
@ -6,7 +7,9 @@ namespace NadekoBot.Services.Database.Models
public class CustomReaction : DbEntity public class CustomReaction : DbEntity
{ {
public ulong? GuildId { get; set; } public ulong? GuildId { get; set; }
[NotMapped] [NotMapped]
[JsonIgnore]
public Regex Regex { get; set; } public Regex Regex { get; set; }
public string Response { get; set; } public string Response { get; set; }
public string Trigger { get; set; } public string Trigger { get; set; }
@ -16,6 +19,7 @@ namespace NadekoBot.Services.Database.Models
public bool AutoDeleteTrigger { get; set; } public bool AutoDeleteTrigger { get; set; }
public bool DmResponse { get; set; } public bool DmResponse { get; set; }
[JsonIgnore]
public bool IsGlobal => !GuildId.HasValue; public bool IsGlobal => !GuildId.HasValue;
public bool ContainsAnywhere { get; set; } public bool ContainsAnywhere { get; set; }

View File

@ -1,4 +1,5 @@
using System; using StackExchange.Redis;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -8,6 +9,7 @@ namespace NadekoBot.Services
{ {
public interface IDataCache public interface IDataCache
{ {
ConnectionMultiplexer Redis { get; }
Task<(bool Success, byte[] Data)> TryGetImageDataAsync(string key); Task<(bool Success, byte[] Data)> TryGetImageDataAsync(string key);
Task SetImageDataAsync(string key, byte[] data); Task SetImageDataAsync(string key, byte[] data);
} }

View File

@ -5,13 +5,14 @@ namespace NadekoBot.Services.Impl
{ {
public class RedisCache : IDataCache public class RedisCache : IDataCache
{ {
private readonly ConnectionMultiplexer _redis; public ConnectionMultiplexer Redis { get; }
private readonly IDatabase _db; private readonly IDatabase _db;
public RedisCache() public RedisCache()
{ {
_redis = ConnectionMultiplexer.Connect("localhost"); Redis = ConnectionMultiplexer.Connect("localhost");
_db = _redis.GetDatabase(); Redis.PreserveAsyncOrder = false;
_db = Redis.GetDatabase();
} }
public async Task<(bool Success, byte[] Data)> TryGetImageDataAsync(string key) public async Task<(bool Success, byte[] Data)> TryGetImageDataAsync(string key)