From e79b3db8182906f2cdbb61aacaf3e82d408918ec Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 6 Nov 2017 10:01:38 +0100 Subject: [PATCH] trivia questions and pokemon data will be stored in redis, instead of per-shard --- .../Common/Pokemon/PokemonNameId.cs | 8 ++ .../Pokemon}/SearchPokemon.cs | 23 +--- .../Common/Pokemon/SearchPokemonAbility.cs | 10 ++ .../Modules/Games/Common/Trivia/TriviaGame.cs | 9 +- .../Games/Common/Trivia/TriviaQuestionPool.cs | 41 ++---- .../Modules/Games/TriviaCommands.cs | 7 +- .../Modules/Searches/PokemonSearchCommands.cs | 14 +- .../Searches/Services/SearchesService.cs | 18 --- NadekoBot.Core/Services/IDataCache.cs | 1 + NadekoBot.Core/Services/ILocalDataCache.cs | 14 ++ NadekoBot.Core/Services/Impl/RedisCache.cs | 3 +- .../Services/Impl/RedisLocalDataCache.cs | 122 ++++++++++++++++++ NadekoBot.Core/Services/Impl/StatsService.cs | 2 +- 13 files changed, 195 insertions(+), 77 deletions(-) create mode 100644 NadekoBot.Core/Common/Pokemon/PokemonNameId.cs rename NadekoBot.Core/{Modules/Searches/Common => Common/Pokemon}/SearchPokemon.cs (66%) create mode 100644 NadekoBot.Core/Common/Pokemon/SearchPokemonAbility.cs create mode 100644 NadekoBot.Core/Services/ILocalDataCache.cs create mode 100644 NadekoBot.Core/Services/Impl/RedisLocalDataCache.cs diff --git a/NadekoBot.Core/Common/Pokemon/PokemonNameId.cs b/NadekoBot.Core/Common/Pokemon/PokemonNameId.cs new file mode 100644 index 00000000..628b56d6 --- /dev/null +++ b/NadekoBot.Core/Common/Pokemon/PokemonNameId.cs @@ -0,0 +1,8 @@ +namespace NadekoBot.Core.Common.Pokemon +{ + public class PokemonNameId + { + public int Id { get; set; } + public string Name { get; set; } + } +} diff --git a/NadekoBot.Core/Modules/Searches/Common/SearchPokemon.cs b/NadekoBot.Core/Common/Pokemon/SearchPokemon.cs similarity index 66% rename from NadekoBot.Core/Modules/Searches/Common/SearchPokemon.cs rename to NadekoBot.Core/Common/Pokemon/SearchPokemon.cs index 29de4e00..fa541f8c 100644 --- a/NadekoBot.Core/Modules/Searches/Common/SearchPokemon.cs +++ b/NadekoBot.Core/Common/Pokemon/SearchPokemon.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace NadekoBot.Modules.Searches.Common +namespace NadekoBot.Core.Common.Pokemon { public class SearchPokemon { @@ -9,6 +9,7 @@ namespace NadekoBot.Modules.Searches.Common public float M { get; set; } public float F { get; set; } } + public class BaseStatsClass { public int HP { get; set; } @@ -21,6 +22,7 @@ namespace NadekoBot.Modules.Searches.Common public override string ToString() => $@"**HP:** {HP,-4} **ATK:** {ATK,-4} **DEF:** {DEF,-4} **SPA:** {SPA,-4} **SPD:** {SPD,-4} **SPE:** {SPE,-4}"; } + public int Id { get; set; } public string Species { get; set; } public string[] Types { get; set; } @@ -32,24 +34,5 @@ namespace NadekoBot.Modules.Searches.Common public string Color { get; set; } public string[] Evos { get; set; } public string[] EggGroups { get; set; } - -// public override string ToString() => $@"`Name:` {Species} -//`Types:` {string.Join(", ", Types)} -//`Stats:` {BaseStats} -//`Height:` {HeightM,4}m `Weight:` {WeightKg}kg -//`Abilities:` {string.Join(", ", Abilities.Values)}"; - - } - - public class SearchPokemonAbility - { - public string Desc { get; set; } - public string ShortDesc { get; set; } - public string Name { get; set; } - public float Rating { get; set; } - -// public override string ToString() => $@"`Name:` : {Name} -//`Rating:` {Rating} -//`Description:` {Desc}"; } } diff --git a/NadekoBot.Core/Common/Pokemon/SearchPokemonAbility.cs b/NadekoBot.Core/Common/Pokemon/SearchPokemonAbility.cs new file mode 100644 index 00000000..0173749d --- /dev/null +++ b/NadekoBot.Core/Common/Pokemon/SearchPokemonAbility.cs @@ -0,0 +1,10 @@ +namespace NadekoBot.Core.Common.Pokemon +{ + public class SearchPokemonAbility + { + public string Desc { get; set; } + public string ShortDesc { get; set; } + public string Name { get; set; } + public float Rating { get; set; } + } +} diff --git a/NadekoBot.Core/Modules/Games/Common/Trivia/TriviaGame.cs b/NadekoBot.Core/Modules/Games/Common/Trivia/TriviaGame.cs index e3e98b03..30d0a7fd 100644 --- a/NadekoBot.Core/Modules/Games/Common/Trivia/TriviaGame.cs +++ b/NadekoBot.Core/Modules/Games/Common/Trivia/TriviaGame.cs @@ -19,6 +19,7 @@ namespace NadekoBot.Modules.Games.Common.Trivia { private readonly SemaphoreSlim _guessLock = new SemaphoreSlim(1, 1); private readonly Logger _log; + private readonly IDataCache _cache; private readonly NadekoStrings _strings; private readonly DiscordSocketClient _client; private readonly IBotConfigProvider _bc; @@ -43,11 +44,15 @@ namespace NadekoBot.Modules.Games.Common.Trivia public int WinRequirement { get; } + private readonly TriviaQuestionPool _questionPool; + public TriviaGame(NadekoStrings strings, DiscordSocketClient client, IBotConfigProvider bc, - CurrencyService cs, IGuild guild, ITextChannel channel, + IDataCache cache, CurrencyService cs, IGuild guild, ITextChannel channel, bool showHints, int winReq, bool isPokemon) { _log = LogManager.GetCurrentClassLogger(); + _cache = cache; + _questionPool = new TriviaQuestionPool(_cache); _strings = strings; _client = client; _bc = bc; @@ -74,7 +79,7 @@ namespace NadekoBot.Modules.Games.Common.Trivia _triviaCancelSource = new CancellationTokenSource(); // load question - CurrentQuestion = TriviaQuestionPool.Instance.GetRandomQuestion(OldQuestions, IsPokemon); + CurrentQuestion = _questionPool.GetRandomQuestion(OldQuestions, IsPokemon); if (string.IsNullOrWhiteSpace(CurrentQuestion?.Answer) || string.IsNullOrWhiteSpace(CurrentQuestion.Question)) { await Channel.SendErrorAsync(GetText("trivia_game"), GetText("failed_loading_question")).ConfigureAwait(false); diff --git a/NadekoBot.Core/Modules/Games/Common/Trivia/TriviaQuestionPool.cs b/NadekoBot.Core/Modules/Games/Common/Trivia/TriviaQuestionPool.cs index 2307c209..96aad572 100644 --- a/NadekoBot.Core/Modules/Games/Common/Trivia/TriviaQuestionPool.cs +++ b/NadekoBot.Core/Modules/Games/Common/Trivia/TriviaQuestionPool.cs @@ -1,62 +1,43 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; -using System.IO; -using System.Linq; using NadekoBot.Common; using NadekoBot.Extensions; -using Newtonsoft.Json; +using NadekoBot.Core.Services; namespace NadekoBot.Modules.Games.Common.Trivia { public class TriviaQuestionPool { - public class PokemonNameId - { - public int Id { get; set; } - public string Name { get; set; } - } - - private static TriviaQuestionPool _instance; - public static TriviaQuestionPool Instance { get; } = _instance ?? (_instance = new TriviaQuestionPool()); - - private const string questionsFile = "data/trivia_questions.json"; - private const string pokemonMapPath = "data/pokemon/name-id_map4.json"; + private readonly IDataCache _cache; private readonly int maxPokemonId; - private Random rng { get; } = new NadekoRandom(); - - private TriviaQuestion[] pool { get; } - private ImmutableDictionary map { get; } + private readonly NadekoRandom _rng = new NadekoRandom(); - static TriviaQuestionPool() { } + private TriviaQuestion[] Pool => _cache.LocalData.TriviaQuestions; + private IReadOnlyDictionary Map => _cache.LocalData.PokemonMap; - private TriviaQuestionPool() + public TriviaQuestionPool(IDataCache cache) { - pool = JsonConvert.DeserializeObject(File.ReadAllText(questionsFile)); - map = JsonConvert.DeserializeObject(File.ReadAllText(pokemonMapPath)) - .ToDictionary(x => x.Id, x => x.Name) - .ToImmutableDictionary(); - + _cache = cache; maxPokemonId = 721; //xd } public TriviaQuestion GetRandomQuestion(HashSet exclude, bool isPokemon) { - if (pool.Length == 0) + if (Pool.Length == 0) return null; if (isPokemon) { - var num = rng.Next(1, maxPokemonId + 1); + var num = _rng.Next(1, maxPokemonId + 1); return new TriviaQuestion("Who's That Pokémon?", - map[num].ToTitleCase(), + Map[num].ToTitleCase(), "Pokemon", $@"http://nadekobot.me/images/pokemon/shadows/{num}.png", $@"http://nadekobot.me/images/pokemon/real/{num}.png"); } TriviaQuestion randomQuestion; - while (exclude.Contains(randomQuestion = pool[rng.Next(0, pool.Length)])) ; + while (exclude.Contains(randomQuestion = Pool[_rng.Next(0, Pool.Length)])) ; return randomQuestion; } diff --git a/NadekoBot.Core/Modules/Games/TriviaCommands.cs b/NadekoBot.Core/Modules/Games/TriviaCommands.cs index d47058d1..1feceb37 100644 --- a/NadekoBot.Core/Modules/Games/TriviaCommands.cs +++ b/NadekoBot.Core/Modules/Games/TriviaCommands.cs @@ -15,12 +15,15 @@ namespace NadekoBot.Modules.Games [Group] public class TriviaCommands : NadekoSubmodule { + private readonly IDataCache _cache; private readonly CurrencyService _cs; private readonly DiscordSocketClient _client; private readonly IBotConfigProvider _bc; - public TriviaCommands(DiscordSocketClient client, IBotConfigProvider bc, CurrencyService cs) + public TriviaCommands(DiscordSocketClient client, IDataCache cache, + IBotConfigProvider bc, CurrencyService cs) { + _cache = cache; _cs = cs; _client = client; _bc = bc; @@ -45,7 +48,7 @@ namespace NadekoBot.Modules.Games var showHints = !additionalArgs.Contains("nohint"); var isPokemon = additionalArgs.Contains("pokemon"); - var trivia = new TriviaGame(_strings, _client, _bc, _cs, channel.Guild, channel, showHints, winReq, isPokemon); + var trivia = new TriviaGame(_strings, _client, _bc, _cache, _cs, channel.Guild, channel, showHints, winReq, isPokemon); if (_service.RunningTrivias.TryAdd(channel.Guild.Id, trivia)) { try diff --git a/NadekoBot.Core/Modules/Searches/PokemonSearchCommands.cs b/NadekoBot.Core/Modules/Searches/PokemonSearchCommands.cs index 2ea5c498..b78eb5e1 100644 --- a/NadekoBot.Core/Modules/Searches/PokemonSearchCommands.cs +++ b/NadekoBot.Core/Modules/Searches/PokemonSearchCommands.cs @@ -6,7 +6,8 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using NadekoBot.Common.Attributes; -using NadekoBot.Modules.Searches.Common; +using NadekoBot.Core.Common.Pokemon; +using NadekoBot.Core.Services; namespace NadekoBot.Modules.Searches { @@ -15,8 +16,15 @@ namespace NadekoBot.Modules.Searches [Group] public class PokemonSearchCommands : NadekoSubmodule { - public Dictionary Pokemons => _service.Pokemons; - public Dictionary PokemonAbilities => _service.PokemonAbilities; + private readonly IDataCache _cache; + + public IReadOnlyDictionary Pokemons => _cache.LocalData.Pokemons; + public IReadOnlyDictionary PokemonAbilities => _cache.LocalData.PokemonAbilities; + + public PokemonSearchCommands(IDataCache cache) + { + _cache = cache; + } [NadekoCommand, Usage, Description, Aliases] public async Task Pokemon([Remainder] string pokemon = null) diff --git a/NadekoBot.Core/Modules/Searches/Services/SearchesService.cs b/NadekoBot.Core/Modules/Searches/Services/SearchesService.cs index 74e501d7..c8ff016f 100644 --- a/NadekoBot.Core/Modules/Searches/Services/SearchesService.cs +++ b/NadekoBot.Core/Modules/Searches/Services/SearchesService.cs @@ -17,7 +17,6 @@ using System.Net.Http; using Newtonsoft.Json.Linq; using AngleSharp; using System.Threading; -using NadekoBot.Modules.Searches.Exceptions; using ImageSharp; using Image = ImageSharp.Image; using SixLabors.Primitives; @@ -41,12 +40,6 @@ namespace NadekoBot.Modules.Searches.Services public ConcurrentDictionary TranslatedChannels { get; } = new ConcurrentDictionary(); public ConcurrentDictionary UserLanguages { get; } = new ConcurrentDictionary(); - - public readonly string PokemonAbilitiesFile = "data/pokemon/pokemon_abilities7.json"; - - public readonly string PokemonListFile = "data/pokemon/pokemon_list7.json"; - public Dictionary Pokemons { get; } = new Dictionary(); - public Dictionary PokemonAbilities { get; } = new Dictionary(); public List WowJokes { get; } = new List(); public List MagicItems { get; } = new List(); @@ -113,17 +106,6 @@ namespace NadekoBot.Modules.Searches.Services return Task.CompletedTask; }; - //pokemon commands - if (File.Exists(PokemonListFile)) - { - Pokemons = JsonConvert.DeserializeObject>(File.ReadAllText(PokemonListFile)); - } - else - _log.Warn(PokemonListFile + " is missing. Pokemon abilities not loaded."); - if (File.Exists(PokemonAbilitiesFile)) - PokemonAbilities = JsonConvert.DeserializeObject>(File.ReadAllText(PokemonAbilitiesFile)); - else - _log.Warn(PokemonAbilitiesFile + " is missing. Pokemon abilities not loaded."); //joke commands if (File.Exists("data/wowjokes.json")) diff --git a/NadekoBot.Core/Services/IDataCache.cs b/NadekoBot.Core/Services/IDataCache.cs index d1256529..f5913219 100644 --- a/NadekoBot.Core/Services/IDataCache.cs +++ b/NadekoBot.Core/Services/IDataCache.cs @@ -8,6 +8,7 @@ namespace NadekoBot.Core.Services { ConnectionMultiplexer Redis { get; } IImageCache LocalImages { get; } + ILocalDataCache LocalData { get; } Task<(bool Success, byte[] Data)> TryGetImageDataAsync(string key); Task<(bool Success, string Data)> TryGetAnimeDataAsync(string key); diff --git a/NadekoBot.Core/Services/ILocalDataCache.cs b/NadekoBot.Core/Services/ILocalDataCache.cs new file mode 100644 index 00000000..da5e5e93 --- /dev/null +++ b/NadekoBot.Core/Services/ILocalDataCache.cs @@ -0,0 +1,14 @@ +using NadekoBot.Core.Common.Pokemon; +using NadekoBot.Modules.Games.Common.Trivia; +using System.Collections.Generic; + +namespace NadekoBot.Core.Services +{ + public interface ILocalDataCache + { + IReadOnlyDictionary Pokemons { get; } + IReadOnlyDictionary PokemonAbilities { get; } + TriviaQuestion[] TriviaQuestions { get; } + IReadOnlyDictionary PokemonMap { get; } + } +} diff --git a/NadekoBot.Core/Services/Impl/RedisCache.cs b/NadekoBot.Core/Services/Impl/RedisCache.cs index 69334cd1..6b6a749e 100644 --- a/NadekoBot.Core/Services/Impl/RedisCache.cs +++ b/NadekoBot.Core/Services/Impl/RedisCache.cs @@ -1,7 +1,6 @@ using NadekoBot.Extensions; using StackExchange.Redis; using System; -using System.Linq; using System.Threading.Tasks; namespace NadekoBot.Core.Services.Impl @@ -11,6 +10,7 @@ namespace NadekoBot.Core.Services.Impl public ConnectionMultiplexer Redis { get; } public IImageCache LocalImages { get; } + public ILocalDataCache LocalData { get; } private readonly IDatabase _db; private readonly string _redisKey; @@ -20,6 +20,7 @@ namespace NadekoBot.Core.Services.Impl Redis = ConnectionMultiplexer.Connect("127.0.0.1"); Redis.PreserveAsyncOrder = false; LocalImages = new RedisImagesCache(Redis, creds); + LocalData = new RedisLocalDataCache(Redis, creds); _db = Redis.GetDatabase(); _redisKey = creds.RedisKey(); } diff --git a/NadekoBot.Core/Services/Impl/RedisLocalDataCache.cs b/NadekoBot.Core/Services/Impl/RedisLocalDataCache.cs new file mode 100644 index 00000000..e5eeb3f8 --- /dev/null +++ b/NadekoBot.Core/Services/Impl/RedisLocalDataCache.cs @@ -0,0 +1,122 @@ +using NadekoBot.Core.Common.Pokemon; +using NadekoBot.Extensions; +using NadekoBot.Modules.Games.Common.Trivia; +using Newtonsoft.Json; +using NLog; +using StackExchange.Redis; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace NadekoBot.Core.Services.Impl +{ + public class RedisLocalDataCache : ILocalDataCache + { + private readonly ConnectionMultiplexer _con; + private readonly IBotCredentials _creds; + private readonly Logger _log; + + private IDatabase _db => _con.GetDatabase(); + + private const string pokemonAbilitiesFile = "data/pokemon/pokemon_abilities7.json"; + private const string pokemonListFile = "data/pokemon/pokemon_list7.json"; + private const string pokemonMapPath = "data/pokemon/name-id_map4.json"; + private const string questionsFile = "data/trivia_questions.json"; + + public IReadOnlyDictionary Pokemons + { + get + { + return Get>("pokemon_list"); + } + private set + { + Set("pokemon_list", value); + } + } + + public IReadOnlyDictionary PokemonAbilities + { + get + { + return Get>("pokemon_abilities"); + } + private set + { + Set("pokemon_abilities", value); + } + } + + public TriviaQuestion[] TriviaQuestions + { + get + { + return Get("trivia_questions"); + } + private set + { + Set("trivia_questions", value); + } + } + + public IReadOnlyDictionary PokemonMap + { + get + { + return Get>("pokemon_map"); + } + private set + { + Set("pokemon_map", value); + } + } + + public RedisLocalDataCache(ConnectionMultiplexer con, IBotCredentials creds) + { + _con = con; + _creds = creds; + _log = LogManager.GetCurrentClassLogger(); + + if (!File.Exists(pokemonListFile)) + { + _log.Warn(pokemonListFile + " is missing. Pokemon abilities not loaded."); + } + else + { + Pokemons = JsonConvert.DeserializeObject>(File.ReadAllText(pokemonListFile)); + } + + if (!File.Exists(pokemonAbilitiesFile)) + { + _log.Warn(pokemonAbilitiesFile + " is missing. Pokemon abilities not loaded."); + } + else + { + PokemonAbilities = JsonConvert.DeserializeObject>(File.ReadAllText(pokemonAbilitiesFile)); + } + + try + { + TriviaQuestions = JsonConvert.DeserializeObject(File.ReadAllText(questionsFile)); + PokemonMap = JsonConvert.DeserializeObject(File.ReadAllText(pokemonMapPath)) + .ToDictionary(x => x.Id, x => x.Name); + } + catch (Exception ex) + { + _log.Error(ex); + throw; + } + } + + private T Get(string key) where T : class + { + return JsonConvert.DeserializeObject(_db.StringGet($"{_creds.RedisKey()}_localdata_{key}")); + } + + private void Set(string key, object obj) + { + _db.StringSet($"{_creds.RedisKey()}_localdata_{key}", JsonConvert.SerializeObject(obj)); + } + } +} diff --git a/NadekoBot.Core/Services/Impl/StatsService.cs b/NadekoBot.Core/Services/Impl/StatsService.cs index 54dd85a9..a79dddf2 100644 --- a/NadekoBot.Core/Services/Impl/StatsService.cs +++ b/NadekoBot.Core/Services/Impl/StatsService.cs @@ -21,7 +21,7 @@ namespace NadekoBot.Core.Services.Impl private readonly IBotCredentials _creds; private readonly DateTime _started; - public const string BotVersion = "2.3.5"; + public const string BotVersion = "2.3.6"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net";