using EllieBot.Common.Pokemon; using EllieBot.Modules.Games.Common.Trivia; using System.Text.Json; using System.Text.Json.Serialization; namespace EllieBot.Services; public sealed class LocalDataCache : ILocalDataCache, IEService { private const string POKEMON_ABILITIES_FILE = "data/pokemon/pokemon_abilities.json"; private const string POKEMON_LIST_FILE = "data/pokemon/pokemon_list.json"; private const string POKEMON_MAP_PATH = "data/pokemon/name-id_map.json"; private const string QUESTIONS_FILE = "data/trivia_questions.json"; private readonly IBotCache _cache; private readonly JsonSerializerOptions _opts = new JsonSerializerOptions() { AllowTrailingCommas = true, NumberHandling = JsonNumberHandling.AllowReadingFromString, PropertyNameCaseInsensitive = true }; public LocalDataCache(IBotCache cache) => _cache = cache; private async Task GetOrCreateCachedDataAsync( TypedKey key, string fileName) => await _cache.GetOrAddAsync(key, async () => { if (!File.Exists(fileName)) { Log.Warning($"{fileName} is missing. Relevant data can't be loaded"); return default; } try { await using var stream = File.OpenRead(fileName); return await JsonSerializer.DeserializeAsync(stream, _opts); } catch (Exception ex) { Log.Error(ex, "Error reading {FileName} file: {ErrorMessage}", fileName, ex.Message); return default; } }); private static TypedKey> _pokemonListKey = new("pokemon:list"); public async Task?> GetPokemonsAsync() => await GetOrCreateCachedDataAsync(_pokemonListKey, POKEMON_LIST_FILE); private static TypedKey> _pokemonAbilitiesKey = new("pokemon:abilities"); public async Task?> GetPokemonAbilitiesAsync() => await GetOrCreateCachedDataAsync(_pokemonAbilitiesKey, POKEMON_ABILITIES_FILE); private static TypedKey> _pokeMapKey = new("pokemon:ab_map2"); // 2 because ab_map was storing arrays public async Task?> GetPokemonMapAsync() => await _cache.GetOrAddAsync(_pokeMapKey, async () => { var fileName = POKEMON_MAP_PATH; if (!File.Exists(fileName)) { Log.Warning($"{fileName} is missing. Relevant data can't be loaded"); return default; } try { await using var stream = File.OpenRead(fileName); var arr = await JsonSerializer.DeserializeAsync(stream, _opts); return (IReadOnlyDictionary?)arr?.ToDictionary(x => x.Id, x => x.Name); } catch (Exception ex) { Log.Error(ex, "Error reading {FileName} file: {ErrorMessage}", fileName, ex.Message); return default; } }); private static TypedKey _triviaKey = new("trivia:questions"); public async Task GetTriviaQuestionsAsync() => await GetOrCreateCachedDataAsync(_triviaKey, QUESTIONS_FILE); }