Remove all dependencies on redis

This commit is contained in:
runebaas 2020-05-30 17:02:17 +02:00
parent 2e501008df
commit 33b17b373f
No known key found for this signature in database
GPG key ID: 2677AF508D0300D6
11 changed files with 129 additions and 77 deletions

View file

@ -170,23 +170,16 @@ namespace Geekbot.net.Commands.Admin
[RequireUserPermission(GuildPermission.ManageRoles)] [RequireUserPermission(GuildPermission.ManageRoles)]
[Summary("Give a role by clicking on an emoji")] [Summary("Give a role by clicking on an emoji")]
[Command("listen", RunMode = RunMode.Async)] [Command("listen", RunMode = RunMode.Async)]
public async Task AddListener([Summary("message-ID")] string messageId, [Summary("Emoji")] string emoji, [Summary("@role")] IRole role) public async Task AddListener([Summary("message-ID")] string messageIdStr, [Summary("Emoji")] string emoji, [Summary("@role")] IRole role)
{ {
try try
{ {
var message = (IUserMessage) await Context.Channel.GetMessageAsync(ulong.Parse(messageId)); var messageId = ulong.Parse(messageIdStr);
IEmote emote; var message = (IUserMessage) await Context.Channel.GetMessageAsync(messageId);
if (!emoji.StartsWith('<')) var emote = _reactionListener.ConvertStringToEmote(emoji);
{
var emo = new Emoji(emoji);
emote = emo;
}
else
{
emote = Emote.Parse(emoji);
}
await message.AddReactionAsync(emote); await message.AddReactionAsync(emote);
await _reactionListener.AddRoleToListener(messageId, emote, role); await _reactionListener.AddRoleToListener(messageId, Context.Guild.Id, emoji, role);
await Context.Message.DeleteAsync(); await Context.Message.DeleteAsync();
} }
catch (HttpException e) catch (HttpException e)

View file

@ -4,26 +4,25 @@ using System.Threading.Tasks;
using Discord.Commands; using Discord.Commands;
using Geekbot.net.Database; using Geekbot.net.Database;
using Geekbot.net.Database.Models; using Geekbot.net.Database.Models;
using Geekbot.net.Lib.AlmostRedis;
using Geekbot.net.Lib.ErrorHandling; using Geekbot.net.Lib.ErrorHandling;
using Geekbot.net.Lib.Extensions; using Geekbot.net.Lib.Extensions;
using Geekbot.net.Lib.KvInMemoryStore;
using Geekbot.net.Lib.Localization; using Geekbot.net.Lib.Localization;
using Geekbot.net.Lib.RandomNumberGenerator; using Geekbot.net.Lib.RandomNumberGenerator;
using StackExchange.Redis;
namespace Geekbot.net.Commands.Games namespace Geekbot.net.Commands.Games
{ {
public class Roll : ModuleBase public class Roll : ModuleBase
{ {
private readonly IErrorHandler _errorHandler; private readonly IErrorHandler _errorHandler;
private readonly IAlmostRedis _redis; private readonly IKvInMemoryStore _kvInMemoryStore;
private readonly ITranslationHandler _translation; private readonly ITranslationHandler _translation;
private readonly DatabaseContext _database; private readonly DatabaseContext _database;
private readonly IRandomNumberGenerator _randomNumberGenerator; private readonly IRandomNumberGenerator _randomNumberGenerator;
public Roll(IAlmostRedis redis, IErrorHandler errorHandler, ITranslationHandler translation, DatabaseContext database, IRandomNumberGenerator randomNumberGenerator) public Roll(IKvInMemoryStore kvInMemoryStore,IErrorHandler errorHandler, ITranslationHandler translation, DatabaseContext database, IRandomNumberGenerator randomNumberGenerator)
{ {
_redis = redis; _kvInMemoryStore = kvInMemoryStore;
_translation = translation; _translation = translation;
_database = database; _database = database;
_randomNumberGenerator = randomNumberGenerator; _randomNumberGenerator = randomNumberGenerator;
@ -37,28 +36,28 @@ namespace Geekbot.net.Commands.Games
try try
{ {
var number = _randomNumberGenerator.Next(1, 100); var number = _randomNumberGenerator.Next(1, 100);
var guess = 1000; int.TryParse(stuff, out var guess);
int.TryParse(stuff, out guess);
var transContext = await _translation.GetGuildContext(Context); var transContext = await _translation.GetGuildContext(Context);
if (guess <= 100 && guess > 0) if (guess <= 100 && guess > 0)
{ {
var prevRoll = _redis.Db.HashGet($"{Context.Guild.Id}:RollsPrevious2", Context.Message.Author.Id).ToString()?.Split('|'); var kvKey = $"{Context.Guild.Id}:{Context.User.Id}:RollsPrevious";
if (prevRoll?.Length == 2)
var prevRoll = _kvInMemoryStore.Get<int>(kvKey);
if (prevRoll > 0)
{ {
if (prevRoll[0] == guess.ToString() && DateTime.Parse(prevRoll[1]) > DateTime.Now.AddDays(-1)) if (prevRoll == guess)
{ {
await ReplyAsync(transContext.GetString("NoPrevGuess", Context.Message.Author.Mention)); await ReplyAsync(transContext.GetString("NoPrevGuess", Context.Message.Author.Mention));
return; return;
} }
} }
_redis.Db.HashSet($"{Context.Guild.Id}:RollsPrevious2", new[] {new HashEntry(Context.Message.Author.Id, $"{guess}|{DateTime.Now}")}); _kvInMemoryStore.Set(kvKey, guess);
await ReplyAsync(transContext.GetString("Rolled", Context.Message.Author.Mention, number, guess)); await ReplyAsync(transContext.GetString("Rolled", Context.Message.Author.Mention, number, guess));
if (guess == number) if (guess == number)
{ {
await ReplyAsync(transContext.GetString("Gratz", Context.Message.Author)); await ReplyAsync(transContext.GetString("Gratz", Context.Message.Author));
_redis.Db.HashIncrement($"{Context.Guild.Id}:Rolls", Context.User.Id.ToString());
var user = await GetUser(Context.User.Id); var user = await GetUser(Context.User.Id);
user.Rolls += 1; user.Rolls += 1;
_database.Rolls.Update(user); _database.Rolls.Update(user);

View file

@ -4,7 +4,6 @@ using System.Threading.Tasks;
using Discord; using Discord;
using Discord.Commands; using Discord.Commands;
using Geekbot.net.Database; using Geekbot.net.Database;
using Geekbot.net.Lib.AlmostRedis;
using Geekbot.net.Lib.CommandPreconditions; using Geekbot.net.Lib.CommandPreconditions;
using Geekbot.net.Lib.ErrorHandling; using Geekbot.net.Lib.ErrorHandling;
using Geekbot.net.Lib.Extensions; using Geekbot.net.Lib.Extensions;
@ -16,12 +15,10 @@ namespace Geekbot.net.Commands.User
{ {
private readonly IErrorHandler _errorHandler; private readonly IErrorHandler _errorHandler;
private readonly ILevelCalc _levelCalc; private readonly ILevelCalc _levelCalc;
private readonly IAlmostRedis _redis;
private readonly DatabaseContext _database; private readonly DatabaseContext _database;
public Stats(IAlmostRedis redis, DatabaseContext database, IErrorHandler errorHandler, ILevelCalc levelCalc) public Stats(DatabaseContext database, IErrorHandler errorHandler, ILevelCalc levelCalc)
{ {
_redis = redis;
_database = database; _database = database;
_errorHandler = errorHandler; _errorHandler = errorHandler;
_levelCalc = levelCalc; _levelCalc = levelCalc;

View file

@ -18,5 +18,6 @@ namespace Geekbot.net.Database
public DbSet<RoleSelfServiceModel> RoleSelfService { get; set; } public DbSet<RoleSelfServiceModel> RoleSelfService { get; set; }
public DbSet<PollModel> Polls { get; set; } public DbSet<PollModel> Polls { get; set; }
public DbSet<CookiesModel> Cookies { get; set; } public DbSet<CookiesModel> Cookies { get; set; }
public DbSet<ReactionListenerModel> ReactionListeners { get; set; }
} }
} }

View file

@ -0,0 +1,22 @@
using System.ComponentModel.DataAnnotations;
namespace Geekbot.net.Database.Models
{
public class ReactionListenerModel
{
[Key]
public int Id { get; set; }
[Required]
public long GuildId { get; set; }
[Required]
public long MessageId { get; set; }
[Required]
public long RoleId { get; set; }
[Required]
public string Reaction { get; set; }
}
}

View file

@ -9,12 +9,12 @@ using Discord.Rest;
using Discord.WebSocket; using Discord.WebSocket;
using Geekbot.net.Database; using Geekbot.net.Database;
using Geekbot.net.Database.Models; using Geekbot.net.Database.Models;
using Geekbot.net.Lib.AlmostRedis;
using Geekbot.net.Lib.Extensions; using Geekbot.net.Lib.Extensions;
using Geekbot.net.Lib.Logger; using Geekbot.net.Lib.Logger;
using Geekbot.net.Lib.ReactionListener; using Geekbot.net.Lib.ReactionListener;
using Geekbot.net.Lib.UserRepository; using Geekbot.net.Lib.UserRepository;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace Geekbot.net namespace Geekbot.net
{ {
public class Handlers public class Handlers

View file

@ -0,0 +1,9 @@
namespace Geekbot.net.Lib.KvInMemoryStore
{
public interface IKvInMemoryStore
{
public T Get<T>(string key);
public void Set<T>(string key, T value);
public void Remove(string key);
}
}

View file

@ -0,0 +1,32 @@
using System.Collections.Generic;
namespace Geekbot.net.Lib.KvInMemoryStore
{
public class KvInInMemoryStore : IKvInMemoryStore
{
private readonly Dictionary<string, object> _storage = new Dictionary<string, object>();
public T Get<T>(string key)
{
try
{
return (T) _storage[key];
}
catch
{
return default;
}
}
public void Set<T>(string key, T value)
{
_storage.Remove(key);
_storage.Add(key, value);
}
public void Remove(string key)
{
_storage.Remove(key);
}
}
}

View file

@ -7,8 +7,9 @@ namespace Geekbot.net.Lib.ReactionListener
public interface IReactionListener public interface IReactionListener
{ {
bool IsListener(ulong id); bool IsListener(ulong id);
Task AddRoleToListener(string messageId, IEmote emoji, IRole role); Task AddRoleToListener(ulong messageId, ulong guildId, string emoji, IRole role);
void RemoveRole(ISocketMessageChannel channel, SocketReaction reaction); void RemoveRole(ISocketMessageChannel channel, SocketReaction reaction);
void GiveRole(ISocketMessageChannel message, SocketReaction reaction); void GiveRole(ISocketMessageChannel message, SocketReaction reaction);
IEmote ConvertStringToEmote(string emoji);
} }
} }

View file

@ -1,80 +1,66 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Discord; using Discord;
using Discord.WebSocket; using Discord.WebSocket;
using StackExchange.Redis; using Geekbot.net.Database;
using Geekbot.net.Database.Models;
using Geekbot.net.Lib.Extensions;
namespace Geekbot.net.Lib.ReactionListener namespace Geekbot.net.Lib.ReactionListener
{ {
public class ReactionListener : IReactionListener public class ReactionListener : IReactionListener
{ {
private readonly IDatabase _redis; private readonly DatabaseContext _database;
private Dictionary<string, Dictionary<IEmote, ulong>> _listener; private Dictionary<ulong, Dictionary<IEmote, ulong>> _listener;
public ReactionListener(IDatabase redis) public ReactionListener(DatabaseContext database)
{ {
_redis = redis; _database = database;
LoadListeners(); LoadListeners();
} }
private void LoadListeners() private void LoadListeners()
{ {
var ids = _redis.SetMembers("MessageIds"); _listener = new Dictionary<ulong, Dictionary<IEmote, ulong>>();
_listener = new Dictionary<string, Dictionary<IEmote, ulong>>(); foreach (var row in _database.ReactionListeners)
foreach (var id in ids)
{ {
var reactions = _redis.HashGetAll($"Messages:{id}"); var messageId = row.MessageId.AsUlong();
var messageId = id; if (!_listener.ContainsKey(messageId))
var emojiDict = new Dictionary<IEmote, ulong>();
foreach (var r in reactions)
{ {
IEmote emote; _listener.Add(messageId, new Dictionary<IEmote, ulong>());
if (!r.Name.ToString().StartsWith('<'))
{
var emo = new Emoji(r.Name);
emote = emo;
} }
else
{ _listener[messageId].Add(ConvertStringToEmote(row.Reaction), row.RoleId.AsUlong());
emote = Emote.Parse(r.Name);
}
emojiDict.Add(emote, ulong.Parse(r.Value));
}
_listener.Add(messageId, emojiDict);
} }
} }
public bool IsListener(ulong id) public bool IsListener(ulong id)
{ {
return _listener.ContainsKey(id.ToString()); return _listener.ContainsKey(id);
} }
public Task AddRoleToListener(string messageId, IEmote emoji, IRole role) public async Task AddRoleToListener(ulong messageId, ulong guildId, string emoji, IRole role)
{ {
if (_redis.SetMembers("MessageIds").All(e => e.ToString() != messageId)) var emote = ConvertStringToEmote(emoji);
{
_redis.SetAdd("MessageIds", messageId);
}
_redis.HashSet($"Messages:{messageId}", new[] {new HashEntry(emoji.ToString(), role.Id.ToString())});
_redis.SetAdd("MessageIds", messageId);
if (_listener.ContainsKey(messageId))
{
_listener[messageId].Add(emoji, role.Id);
return Task.CompletedTask;
}
var dict = new Dictionary<IEmote, ulong> await _database.ReactionListeners.AddAsync(new ReactionListenerModel()
{ {
{emoji, role.Id} GuildId = guildId.AsLong(),
}; MessageId = messageId.AsLong(),
_listener.Add(messageId, dict); RoleId = role.Id.AsLong(),
return Task.CompletedTask; Reaction = emoji
});
if (!_listener.ContainsKey(messageId))
{
_listener.Add(messageId, new Dictionary<IEmote, ulong>());
}
_listener[messageId].Add(emote, role.Id);
} }
public async void RemoveRole(ISocketMessageChannel channel, SocketReaction reaction) public async void RemoveRole(ISocketMessageChannel channel, SocketReaction reaction)
{ {
var roleId = _listener[reaction.MessageId.ToString()][reaction.Emote]; var roleId = _listener[reaction.MessageId][reaction.Emote];
var guild = (SocketGuildChannel) channel; var guild = (SocketGuildChannel) channel;
var role = guild.Guild.GetRole(roleId); var role = guild.Guild.GetRole(roleId);
await ((IGuildUser) reaction.User.Value).RemoveRoleAsync(role); await ((IGuildUser) reaction.User.Value).RemoveRoleAsync(role);
@ -82,10 +68,19 @@ namespace Geekbot.net.Lib.ReactionListener
public async void GiveRole(ISocketMessageChannel channel, SocketReaction reaction) public async void GiveRole(ISocketMessageChannel channel, SocketReaction reaction)
{ {
var roleId = _listener[reaction.MessageId.ToString()][reaction.Emote]; var roleId = _listener[reaction.MessageId][reaction.Emote];
var guild = (SocketGuildChannel) channel; var guild = (SocketGuildChannel) channel;
var role = guild.Guild.GetRole(roleId); var role = guild.Guild.GetRole(roleId);
await ((IGuildUser) reaction.User.Value).AddRoleAsync(role); await ((IGuildUser) reaction.User.Value).AddRoleAsync(role);
} }
public IEmote ConvertStringToEmote(string emoji)
{
if (!emoji.StartsWith('<'))
{
return new Emoji(emoji);
}
return Emote.Parse(emoji);
}
} }
} }

View file

@ -14,6 +14,7 @@ using Geekbot.net.Lib.Converters;
using Geekbot.net.Lib.ErrorHandling; using Geekbot.net.Lib.ErrorHandling;
using Geekbot.net.Lib.GlobalSettings; using Geekbot.net.Lib.GlobalSettings;
using Geekbot.net.Lib.Highscores; using Geekbot.net.Lib.Highscores;
using Geekbot.net.Lib.KvInMemoryStore;
using Geekbot.net.Lib.Levels; using Geekbot.net.Lib.Levels;
using Geekbot.net.Lib.Localization; using Geekbot.net.Lib.Localization;
using Geekbot.net.Lib.Logger; using Geekbot.net.Lib.Logger;
@ -125,6 +126,7 @@ namespace Geekbot.net
var mtgManaConverter = new MtgManaConverter(); var mtgManaConverter = new MtgManaConverter();
var wikipediaClient = new WikipediaClient(); var wikipediaClient = new WikipediaClient();
var randomNumberGenerator = new RandomNumberGenerator(); var randomNumberGenerator = new RandomNumberGenerator();
var kvMemoryStore = new KvInInMemoryStore();
_services.AddSingleton(_redis); _services.AddSingleton(_redis);
_services.AddSingleton(_userRepository); _services.AddSingleton(_userRepository);
@ -137,6 +139,7 @@ namespace Geekbot.net
_services.AddSingleton<IMtgManaConverter>(mtgManaConverter); _services.AddSingleton<IMtgManaConverter>(mtgManaConverter);
_services.AddSingleton<IWikipediaClient>(wikipediaClient); _services.AddSingleton<IWikipediaClient>(wikipediaClient);
_services.AddSingleton<IRandomNumberGenerator>(randomNumberGenerator); _services.AddSingleton<IRandomNumberGenerator>(randomNumberGenerator);
_services.AddSingleton<IKvInMemoryStore>(kvMemoryStore);
_services.AddSingleton(_globalSettings); _services.AddSingleton(_globalSettings);
_services.AddTransient<IHighscoreManager>(e => new HighscoreManager(_databaseInitializer.Initialize(), _userRepository)); _services.AddTransient<IHighscoreManager>(e => new HighscoreManager(_databaseInitializer.Initialize(), _userRepository));
_services.AddTransient(e => _databaseInitializer.Initialize()); _services.AddTransient(e => _databaseInitializer.Initialize());
@ -164,7 +167,7 @@ namespace Geekbot.net
_logger.Information(LogSource.Geekbot, "Registering Stuff"); _logger.Information(LogSource.Geekbot, "Registering Stuff");
var translationHandler = new TranslationHandler(_databaseInitializer.Initialize(), _logger); var translationHandler = new TranslationHandler(_databaseInitializer.Initialize(), _logger);
var errorHandler = new ErrorHandler(_logger, translationHandler, _runParameters.ExposeErrors); var errorHandler = new ErrorHandler(_logger, translationHandler, _runParameters.ExposeErrors);
var reactionListener = new ReactionListener(_redis.Db); var reactionListener = new ReactionListener(_databaseInitializer.Initialize());
_services.AddSingleton<IErrorHandler>(errorHandler); _services.AddSingleton<IErrorHandler>(errorHandler);
_services.AddSingleton<ITranslationHandler>(translationHandler); _services.AddSingleton<ITranslationHandler>(translationHandler);
_services.AddSingleton(_client); _services.AddSingleton(_client);