using System.Threading.Tasks; using Pathoschild.Http.Client; using StardewModdingAPI.Toolkit; using StardewModdingAPI.Web.Framework.Clients.ModDrop.ResponseModels; namespace StardewModdingAPI.Web.Framework.Clients.ModDrop { /// An HTTP client for fetching mod metadata from the ModDrop API. internal class ModDropClient : IModDropClient { /********* ** Fields *********/ /// The underlying HTTP client. private readonly IClient Client; /// The URL for a ModDrop mod page for the user, where {0} is the mod ID. private readonly string ModUrlFormat; /********* ** Public methods *********/ /// Construct an instance. /// The user agent for the API client. /// The base URL for the ModDrop API. /// The URL for a ModDrop mod page for the user, where {0} is the mod ID. public ModDropClient(string userAgent, string apiUrl, string modUrlFormat) { this.Client = new FluentClient(apiUrl).SetUserAgent(userAgent); this.ModUrlFormat = modUrlFormat; } /// Get metadata about a mod. /// The ModDrop mod ID. /// Returns the mod info if found, else null. public async Task GetModAsync(long id) { // get raw data ModListModel response = await this.Client .PostAsync("") .WithBody(new { ModIDs = new[] { id }, Files = true, Mods = true }) .As(); ModModel mod = response.Mods[id]; if (mod.Mod?.Title == null || mod.Mod.ErrorCode.HasValue) return null; // get latest versions ISemanticVersion latest = null; ISemanticVersion optional = null; foreach (FileDataModel file in mod.Files) { if (file.IsOld || file.IsDeleted || file.IsHidden) continue; if (!SemanticVersion.TryParse(file.Version, out ISemanticVersion version)) continue; if (file.IsDefault) { if (latest == null || version.IsNewerThan(latest)) latest = version; } else if (optional == null || version.IsNewerThan(optional)) optional = version; } if (latest == null) { latest = optional; optional = null; } if (optional != null && latest.IsNewerThan(optional)) optional = null; // generate result return new ModDropMod { Name = mod.Mod?.Title, LatestDefaultVersion = latest, LatestOptionalVersion = optional, Url = string.Format(this.ModUrlFormat, id) }; } /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. public void Dispose() { this.Client?.Dispose(); } } }