From dff78fdf8f98a0f9581b56357107bb6680da62d8 Mon Sep 17 00:00:00 2001
From: Jesse Plamondon-Willard <github@jplamondonw.com>
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(-)

(limited to 'src')

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
     /// <summary>Provides user-friendly info about SMAPI mods.</summary>
     internal class ModsController : Controller
     {
+        /*********
+        ** Properties
+        *********/
+        /// <summary>The cache in which to store mod metadata.</summary>
+        private readonly IMemoryCache Cache;
+
+        /// <summary>The number of minutes successful update checks should be cached before refetching them.</summary>
+        private readonly int SuccessCacheMinutes;
+
+
         /*********
         ** Public methods
         *********/
+        /// <summary>Construct an instance.</summary>
+        /// <param name="cache">The cache in which to store mod metadata.</param>
+        /// <param name="configProvider">The config settings for mod update checks.</param>
+        public ModsController(IMemoryCache cache, IOptions<ModUpdateCheckConfig> configProvider)
+        {
+            ModUpdateCheckConfig config = configProvider.Value;
+
+            this.Cache = cache;
+            this.SuccessCacheMinutes = config.SuccessCacheMinutes;
+        }
+
         /// <summary>Display information for all mods.</summary>
         [HttpGet]
         [Route("mods")]
         public async Task<ViewResult> 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
+        *********/
+        /// <summary>Asynchronously fetch mod metadata from the wiki.</summary>
+        public async Task<ModListModel> 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