From 71b46d73d25fddb2bced4dd1f1083931c0b7edef Mon Sep 17 00:00:00 2001 From: barelyprofessional <150058423+barelyprofessional@users.noreply.github.com> Date: Sat, 17 Aug 2024 23:45:29 +0800 Subject: [PATCH] Added in memory caching --- KfChatDotNetBot/Commands/CacheCommands.cs | 27 ++ KfChatDotNetBot/KfChatDotNetBot.csproj | 1 + .../20240817151151_SettingsCache.Designer.cs | 266 ++++++++++++++++++ .../20240817151151_SettingsCache.cs | 29 ++ .../ApplicationDbContextModelSnapshot.cs | 3 + .../Models/BuiltInSettingsModel.cs | 2 +- .../Models/DbModels/SettingDbModel.cs | 2 + KfChatDotNetBot/Settings/BuiltIn.cs | 106 ++++--- KfChatDotNetBot/Settings/Helpers.cs | 57 ++-- KfChatDotNetBot/Settings/SettingValue.cs | 5 +- 10 files changed, 428 insertions(+), 70 deletions(-) create mode 100644 KfChatDotNetBot/Commands/CacheCommands.cs create mode 100644 KfChatDotNetBot/Migrations/20240817151151_SettingsCache.Designer.cs create mode 100644 KfChatDotNetBot/Migrations/20240817151151_SettingsCache.cs diff --git a/KfChatDotNetBot/Commands/CacheCommands.cs b/KfChatDotNetBot/Commands/CacheCommands.cs new file mode 100644 index 0000000..562f46d --- /dev/null +++ b/KfChatDotNetBot/Commands/CacheCommands.cs @@ -0,0 +1,27 @@ +using System.Runtime.Caching; +using System.Text.RegularExpressions; +using KfChatDotNetBot.Models.DbModels; +using KfChatDotNetWsClient.Models.Events; + +namespace KfChatDotNetBot.Commands; + +public class CacheClearCommand : ICommand +{ + public List Patterns => [ + new Regex("^cache clear") + ]; + + public string HelpText => "Clear the cache"; + public bool HideFromHelp => true; + public UserRight RequiredRight => UserRight.Admin; + + public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + { + var cacheKeys = MemoryCache.Default.Select(kvp => kvp.Key).ToList(); + foreach (var cacheKey in cacheKeys) + { + MemoryCache.Default.Remove(cacheKey); + } + botInstance.SendChatMessage("Cache wiped", true); + } +} \ No newline at end of file diff --git a/KfChatDotNetBot/KfChatDotNetBot.csproj b/KfChatDotNetBot/KfChatDotNetBot.csproj index 38a433a..d1fb6b9 100644 --- a/KfChatDotNetBot/KfChatDotNetBot.csproj +++ b/KfChatDotNetBot/KfChatDotNetBot.csproj @@ -18,6 +18,7 @@ + diff --git a/KfChatDotNetBot/Migrations/20240817151151_SettingsCache.Designer.cs b/KfChatDotNetBot/Migrations/20240817151151_SettingsCache.Designer.cs new file mode 100644 index 0000000..924ab92 --- /dev/null +++ b/KfChatDotNetBot/Migrations/20240817151151_SettingsCache.Designer.cs @@ -0,0 +1,266 @@ +// +using System; +using KfChatDotNetBot; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace KfChatDotNetBot.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20240817151151_SettingsCache")] + partial class SettingsCache + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.7"); + + modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.ChipsggBetDbModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Amount") + .HasColumnType("REAL"); + + b.Property("BetId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Currency") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CurrencyPrice") + .HasColumnType("REAL"); + + b.Property("GameTitle") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Multiplier") + .HasColumnType("REAL"); + + b.Property("Updated") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Username") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Win") + .HasColumnType("INTEGER"); + + b.Property("Winnings") + .HasColumnType("REAL"); + + b.HasKey("Id"); + + b.ToTable("ChipsggBets"); + }); + + modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.HowlggBetsDbModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Bet") + .HasColumnType("INTEGER"); + + b.Property("BetId") + .HasColumnType("INTEGER"); + + b.Property("Date") + .HasColumnType("TEXT"); + + b.Property("Game") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("GameId") + .HasColumnType("INTEGER"); + + b.Property("Profit") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("HowlggBets"); + }); + + modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.JuicerDbModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Amount") + .HasColumnType("REAL"); + + b.Property("JuicedAt") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Juicers"); + }); + + modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.RainbetBetsDbModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BetId") + .HasColumnType("INTEGER"); + + b.Property("BetSeenAt") + .HasColumnType("TEXT"); + + b.Property("GameName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Multiplier") + .HasColumnType("REAL"); + + b.Property("Payout") + .HasColumnType("REAL"); + + b.Property("PublicId") + .HasColumnType("TEXT"); + + b.Property("RainbetUserId") + .HasColumnType("INTEGER"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("REAL"); + + b.HasKey("Id"); + + b.ToTable("RainbetBets"); + }); + + modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.SettingDbModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CacheDuration") + .HasColumnType("REAL"); + + b.Property("Default") + .HasColumnType("TEXT"); + + b.Property("Description") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("IsSecret") + .HasColumnType("INTEGER"); + + b.Property("Key") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Regex") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Settings"); + }); + + modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.TwitchViewCountDbModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ServerTime") + .HasColumnType("REAL"); + + b.Property("Time") + .HasColumnType("TEXT"); + + b.Property("Topic") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Viewers") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("TwitchViewCounts"); + }); + + modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.UserDbModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Ignored") + .HasColumnType("INTEGER"); + + b.Property("KfId") + .HasColumnType("INTEGER"); + + b.Property("KfUsername") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserRight") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.JuicerDbModel", b => + { + b.HasOne("KfChatDotNetBot.Models.DbModels.UserDbModel", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/KfChatDotNetBot/Migrations/20240817151151_SettingsCache.cs b/KfChatDotNetBot/Migrations/20240817151151_SettingsCache.cs new file mode 100644 index 0000000..0051487 --- /dev/null +++ b/KfChatDotNetBot/Migrations/20240817151151_SettingsCache.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace KfChatDotNetBot.Migrations +{ + /// + public partial class SettingsCache : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "CacheDuration", + table: "Settings", + type: "REAL", + nullable: false, + defaultValue: 0.0); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "CacheDuration", + table: "Settings"); + } + } +} diff --git a/KfChatDotNetBot/Migrations/ApplicationDbContextModelSnapshot.cs b/KfChatDotNetBot/Migrations/ApplicationDbContextModelSnapshot.cs index 76cfd3f..e10eccf 100644 --- a/KfChatDotNetBot/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/KfChatDotNetBot/Migrations/ApplicationDbContextModelSnapshot.cs @@ -169,6 +169,9 @@ namespace KfChatDotNetBot.Migrations .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); + b.Property("CacheDuration") + .HasColumnType("REAL"); + b.Property("Default") .HasColumnType("TEXT"); diff --git a/KfChatDotNetBot/Models/BuiltInSettingsModel.cs b/KfChatDotNetBot/Models/BuiltInSettingsModel.cs index 3b4239c..6490ca4 100644 --- a/KfChatDotNetBot/Models/BuiltInSettingsModel.cs +++ b/KfChatDotNetBot/Models/BuiltInSettingsModel.cs @@ -9,5 +9,5 @@ public class BuiltInSettingsModel public required string Description { get; set; } public string? Default { get; set; } public required bool IsSecret { get; set; } - + public required TimeSpan CacheDuration { get; set; } = TimeSpan.Zero; } \ No newline at end of file diff --git a/KfChatDotNetBot/Models/DbModels/SettingDbModel.cs b/KfChatDotNetBot/Models/DbModels/SettingDbModel.cs index dc50327..7de520f 100644 --- a/KfChatDotNetBot/Models/DbModels/SettingDbModel.cs +++ b/KfChatDotNetBot/Models/DbModels/SettingDbModel.cs @@ -16,4 +16,6 @@ public class SettingDbModel public string? Default { get; set; } = null; // Prevents the value from being revealed to Sneedchat when queried by an admin public bool IsSecret { get; set; } = false; + // Number of seconds to cache in memory, 0 to not cache + public double CacheDuration { get; set; } = 0; } \ No newline at end of file diff --git a/KfChatDotNetBot/Settings/BuiltIn.cs b/KfChatDotNetBot/Settings/BuiltIn.cs index 0f6eeae..8e34f48 100644 --- a/KfChatDotNetBot/Settings/BuiltIn.cs +++ b/KfChatDotNetBot/Settings/BuiltIn.cs @@ -26,7 +26,8 @@ public static class BuiltIn Regex = builtIn.Regex, Description = builtIn.Description, Default = builtIn.Default, - IsSecret = builtIn.IsSecret + IsSecret = builtIn.IsSecret, + CacheDuration = builtIn.CacheDuration.TotalSeconds }); continue; } @@ -36,6 +37,7 @@ public static class BuiltIn setting.Description = builtIn.Description; setting.Default = builtIn.Default; setting.IsSecret = builtIn.IsSecret; + setting.CacheDuration = builtIn.CacheDuration.TotalSeconds; } logger.Info("Saving changes to the DB"); await db.SaveChangesAsync(); @@ -101,7 +103,8 @@ public static class BuiltIn Description = "Pusher WebSocket endpoint URL", Default = "wss://ws-us2.pusher.com/app/32cbd69e4b950bf97679?protocol=7&client=js&version=7.6.0&flash=false", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -110,7 +113,8 @@ public static class BuiltIn Description = "Kiwi Farms chat WebSocket endpoint", Default = "wss://kiwifarms.st:9443/chat.ws", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -119,7 +123,8 @@ public static class BuiltIn Description = "List of Pusher channels to subscribe to", Default = null, - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -128,7 +133,8 @@ public static class BuiltIn Description = "Kiwi Farms Keno Kasino room ID", Default = "15", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -137,7 +143,8 @@ public static class BuiltIn Description = "Proxy to use for all outgoing requests. Null to disable", Default = null, - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -146,7 +153,8 @@ public static class BuiltIn Description = "Kiwi Farms chat reconnect timeout", Default = "30", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -155,7 +163,8 @@ public static class BuiltIn Description = "Pusher reconnect timeout", Default = "30", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -164,7 +173,8 @@ public static class BuiltIn Description = "Whether to enable detection for the presence of GambaSesh", Default = "true", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromMinutes(5) }, new BuiltInSettingsModel { @@ -173,7 +183,8 @@ public static class BuiltIn Description = "GambaSesh's uer ID for the purposes of detection", Default = "168162", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -182,7 +193,8 @@ public static class BuiltIn Description = "Kick Icon to use for relaying chat messages", Default = "https://i.postimg.cc/Qtw4nCPG/kick16.png", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -191,7 +203,8 @@ public static class BuiltIn Description = "Domain to use when retrieving a session token", Default = "kiwifarms.st", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -200,7 +213,8 @@ public static class BuiltIn Description = "Username to use when authenticating with Kiwi Farms", Default = null, - IsSecret = true + IsSecret = true, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -209,7 +223,8 @@ public static class BuiltIn Description = "Password to use when authenticating with Kiwi Farms", Default = null, - IsSecret = true + IsSecret = true, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -218,7 +233,8 @@ public static class BuiltIn Description = "Path to download the Chromium install used for the token grabber", Default = "chromium_install", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -227,7 +243,8 @@ public static class BuiltIn Description = "BossmanJack's Twitch channel ID", Default = "114122847", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -236,7 +253,8 @@ public static class BuiltIn Description = "BossmanJack's Twitch channel username", Default = "thebossmanjack", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -245,7 +263,8 @@ public static class BuiltIn Description = "Enable to prevent messages from actually being sent to chat.", Default = "false", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -254,7 +273,8 @@ public static class BuiltIn Description = "Token to use when authenticating with Discord. Set to null to disable.", Default = null, - IsSecret = true + IsSecret = true, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -263,7 +283,8 @@ public static class BuiltIn Description = "BossmanJack's Discord user ID", Default = "554123642246529046", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -271,7 +292,8 @@ public static class BuiltIn Regex = ".+", Description = "URL for the 16px Twitch icon", Default = "https://i.postimg.cc/QMFVV2Xk/twitch16.png", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -279,7 +301,8 @@ public static class BuiltIn Regex = ".+", Description = "URL for the 16px Discord icon", Default = "https://i.postimg.cc/cLmQrp89/discord16.png", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -287,7 +310,8 @@ public static class BuiltIn Regex = ".+", Description = "Bossman's Shuffle Username", Default = "TheBossmanJack", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -295,7 +319,8 @@ public static class BuiltIn Regex = @"\d+", Description = "Cooldown (in seconds) until you can get juiced again", Default = "3600", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromMinutes(5) }, new BuiltInSettingsModel { @@ -303,7 +328,8 @@ public static class BuiltIn Regex = @"\d+", Description = "Amount of $KKK to juice", Default = "50", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromMinutes(5) }, new BuiltInSettingsModel { @@ -311,7 +337,8 @@ public static class BuiltIn Regex = ".+", Description = "Last successfully retrieved forum token (will be refreshed automatically if expired)", Default = null, - IsSecret = true + IsSecret = true, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -319,7 +346,8 @@ public static class BuiltIn Regex = "true|false", Description = "Whether to enable Kick functionality (Pusher websocket mainly)", Default = "true", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -327,7 +355,8 @@ public static class BuiltIn Regex = @"\d+", Description = "How much to divide the Howlgg bets/profit by to get the real value", Default = "1650", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel() { @@ -335,7 +364,8 @@ public static class BuiltIn Regex = ".+", Description = "Green color used for showing positive values in chat", Default = "#3dd179", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel() { @@ -343,7 +373,8 @@ public static class BuiltIn Regex = ".+", Description = "Red color used for showing negative values in chat", Default = "#f1323e", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel() { @@ -351,7 +382,8 @@ public static class BuiltIn Regex = ".+", Description = "Bossman's username on Jackpot", Default = "TheBossmanJack", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -359,7 +391,8 @@ public static class BuiltIn Regex = ".+", Description = "Bossman's rainbet public ID", Default = "Ir04170wLulcjtePCL7P6lmeOlepRaNp", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -367,7 +400,8 @@ public static class BuiltIn Regex = ".+", Description = "URL for your FlareSolverr service API", Default = "http://localhost:8191/", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -375,7 +409,8 @@ public static class BuiltIn Regex = ".+", Description = "Proxy in use specifically for FlareSolverr", Default = null, - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) }, new BuiltInSettingsModel { @@ -383,7 +418,8 @@ public static class BuiltIn Regex = ".+", Description = "Bossman's Chips.gg username", Default = "TheBossmanJack", - IsSecret = false + IsSecret = false, + CacheDuration = TimeSpan.FromHours(1) } ]; diff --git a/KfChatDotNetBot/Settings/Helpers.cs b/KfChatDotNetBot/Settings/Helpers.cs index 2f008aa..88c4f45 100644 --- a/KfChatDotNetBot/Settings/Helpers.cs +++ b/KfChatDotNetBot/Settings/Helpers.cs @@ -1,14 +1,23 @@ using KfChatDotNetBot.Models.DbModels; using Microsoft.EntityFrameworkCore; +using System.Runtime.Caching; using NLog; namespace KfChatDotNetBot.Settings; public static class Helpers { - public static async Task GetValue(string key, bool caseInsensitive = false) + public static async Task GetValue(string key, bool caseInsensitive = false, bool bypassCache = false) { var logger = LogManager.GetCurrentClassLogger(); + var cache = MemoryCache.Default; + if (!bypassCache && cache.Contains(key)) + { + var cachedSetting = cache.Get(key) as SettingDbModel; + var value = cachedSetting.Value; + if (cachedSetting.Value == "null") value = null; + return new SettingValue(value, cachedSetting, true); + } await using var db = new ApplicationDbContext(); logger.Trace($"Retrieving value for {key}"); @@ -30,51 +39,27 @@ public static class Helpers throw new KeyNotFoundException($"{key} does not exist"); } + cache.Set(key, setting, new CacheItemPolicy {AbsoluteExpiration = DateTimeOffset.UtcNow.AddSeconds(setting.CacheDuration)}); + if (setting.Value == "null") { logger.Debug($"{key}'s value is null so returning SettingValue(null)"); - return new SettingValue(null, null); + return new SettingValue(null, setting, false); } - logger.Debug($"Returning '{setting.Value}' as {typeof(SettingValue)}"); - return new SettingValue(setting.Value, setting); + logger.Debug($"Cache Miss! Returning '{setting.Value}' as {typeof(SettingValue)}"); + return new SettingValue(setting.Value, setting, false); } - public static async Task> GetMultipleValues(string[] keys, bool caseInsensitive = false) + public static async Task> GetMultipleValues(string[] keys, bool caseInsensitive = false, bool bypassCache = false) { var logger = LogManager.GetCurrentClassLogger(); - await using var db = new ApplicationDbContext(); logger.Trace($"Getting values for keys {string.Join(", ", keys)}"); Dictionary values = new Dictionary(); foreach (var key in keys) { - SettingDbModel? setting; - if (caseInsensitive) - { - // String comparison doesn't work on EF core if I recall correctly -#pragma warning disable CA1862 - setting = await db.Settings.FirstOrDefaultAsync(s => s.Key.ToLower() == key.ToLower()); -#pragma warning restore CA1862 - } - else - { - setting = await db.Settings.FirstOrDefaultAsync(s => s.Key == key); - } - - if (setting == null) - { - logger.Debug($"{key} does not exist, throwing KeyNotFoundException()"); - throw new KeyNotFoundException(); - } - - if (setting.Value == "null") - { - logger.Debug($"{key}'s value is null so returning SettingValue(null)"); - values.Add(key, new SettingValue(null, null)); - continue; - } - values.Add(key, new SettingValue(setting.Value, setting)); + values.Add(key, await GetValue(key, caseInsensitive, bypassCache)); } return values; @@ -108,6 +93,8 @@ public static class Helpers setting.Value = stringValue; await db.SaveChangesAsync(); + var cache = MemoryCache.Default; + if (cache.Contains(key)) cache.Remove(key); } public static async Task SetValueAsList(string key, List values, char separator = ',') @@ -127,6 +114,8 @@ public static class Helpers setting.Value = joinedValue; await db.SaveChangesAsync(); + var cache = MemoryCache.Default; + if (cache.Contains(key)) cache.Remove(key); } public static async Task SetValueAsKeyValuePairs(string key, Dictionary data, char delimiter = ',', @@ -151,6 +140,8 @@ public static class Helpers setting.Value = value; await db.SaveChangesAsync(); + var cache = MemoryCache.Default; + if (cache.Contains(key)) cache.Remove(key); } public static async Task SetValueAsBoolean(string key, bool value) @@ -169,5 +160,7 @@ public static class Helpers setting.Value = value ? "true" : "false"; await db.SaveChangesAsync(); + var cache = MemoryCache.Default; + if (cache.Contains(key)) cache.Remove(key); } } \ No newline at end of file diff --git a/KfChatDotNetBot/Settings/SettingValue.cs b/KfChatDotNetBot/Settings/SettingValue.cs index 8292411..badfd72 100644 --- a/KfChatDotNetBot/Settings/SettingValue.cs +++ b/KfChatDotNetBot/Settings/SettingValue.cs @@ -2,8 +2,9 @@ using KfChatDotNetBot.Models.DbModels; namespace KfChatDotNetBot.Settings; -public class SettingValue(string? value, SettingDbModel? dbEntry) +public class SettingValue(string? value, SettingDbModel dbEntry, bool cached) { public string? Value { get; set; } = value; - public SettingDbModel? DbEntry { get; set; } = dbEntry; + public SettingDbModel DbEntry { get; set; } = dbEntry; + public bool Cached { get; set; } = cached; } \ No newline at end of file