From dff78fdf8f98a0f9581b56357107bb6680da62d8 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 20 Oct 2018 15:14:09 -0400 Subject: cache wiki data on mod compatibility page (#597) --- src/SMAPI.Web/Controllers/ModsController.cs | 58 ++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/src/SMAPI.Web/Controllers/ModsController.cs b/src/SMAPI.Web/Controllers/ModsController.cs index 99d19f76..f258c745 100644 --- a/src/SMAPI.Web/Controllers/ModsController.cs +++ b/src/SMAPI.Web/Controllers/ModsController.cs @@ -1,9 +1,13 @@ +using System; using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Options; using StardewModdingAPI.Toolkit; using StardewModdingAPI.Toolkit.Framework.Clients.Wiki; +using StardewModdingAPI.Web.Framework.ConfigModels; using StardewModdingAPI.Web.ViewModels; namespace StardewModdingAPI.Web.Controllers @@ -11,23 +15,59 @@ namespace StardewModdingAPI.Web.Controllers /// Provides user-friendly info about SMAPI mods. internal class ModsController : Controller { + /********* + ** Properties + *********/ + /// The cache in which to store mod metadata. + private readonly IMemoryCache Cache; + + /// The number of minutes successful update checks should be cached before refetching them. + private readonly int SuccessCacheMinutes; + + /********* ** Public methods *********/ + /// Construct an instance. + /// The cache in which to store mod metadata. + /// The config settings for mod update checks. + public ModsController(IMemoryCache cache, IOptions configProvider) + { + ModUpdateCheckConfig config = configProvider.Value; + + this.Cache = cache; + this.SuccessCacheMinutes = config.SuccessCacheMinutes; + } + /// Display information for all mods. [HttpGet] [Route("mods")] public async Task Index() { - WikiModEntry[] mods = await new ModToolkit().GetWikiCompatibilityListAsync(); - ModListModel viewModel = new ModListModel( - stableVersion: "1.3.28", - betaVersion: "1.3.31-beta", - mods: mods - .Select(mod => new ModModel(mod)) - .OrderBy(p => Regex.Replace(p.Name.ToLower(), "[^a-z0-9]", "")) // ignore case, spaces, and special characters when sorting - ); - return this.View("Index", viewModel); + return this.View("Index", await this.FetchDataAsync()); + } + + + /********* + ** Private methods + *********/ + /// Asynchronously fetch mod metadata from the wiki. + public async Task FetchDataAsync() + { + return await this.Cache.GetOrCreateAsync($"{nameof(ModsController)}_mod_list", async entry => + { + WikiModEntry[] entries = await new ModToolkit().GetWikiCompatibilityListAsync(); + ModListModel model = new ModListModel( + stableVersion: "1.3.28", + betaVersion: "1.3.31-beta", + mods: entries + .Select(mod => new ModModel(mod)) + .OrderBy(p => Regex.Replace(p.Name.ToLower(), "[^a-z0-9]", "")) // ignore case, spaces, and special characters when sorting + ); + + entry.AbsoluteExpiration = DateTimeOffset.UtcNow.AddMinutes(this.SuccessCacheMinutes); + return model; + }); } } } -- cgit