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 { /// 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() { 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 => { WikiModList data = await new ModToolkit().GetWikiCompatibilityListAsync(); ModListModel model = new ModListModel( stableVersion: data.StableVersion, betaVersion: data.BetaVersion, mods: data .Mods .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; }); } } }