summaryrefslogtreecommitdiff
path: root/src/SMAPI.Web/Framework/Clients/CurseForge/CurseForgeClient.cs
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2019-11-24 13:49:30 -0500
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2019-11-24 13:49:30 -0500
commita3f21685049cabf2d824c8060dc0b1de47e9449e (patch)
treead9add30e9da2a50e0ea0245f1546b7378f0d282 /src/SMAPI.Web/Framework/Clients/CurseForge/CurseForgeClient.cs
parent6521df7b131924835eb797251c1e956fae0d6e13 (diff)
parent277bf082675b98b95bf6184fe3c7a45b969c7ac2 (diff)
downloadSMAPI-a3f21685049cabf2d824c8060dc0b1de47e9449e.tar.gz
SMAPI-a3f21685049cabf2d824c8060dc0b1de47e9449e.tar.bz2
SMAPI-a3f21685049cabf2d824c8060dc0b1de47e9449e.zip
Merge branch 'develop' into stable
Diffstat (limited to 'src/SMAPI.Web/Framework/Clients/CurseForge/CurseForgeClient.cs')
-rw-r--r--src/SMAPI.Web/Framework/Clients/CurseForge/CurseForgeClient.cs113
1 files changed, 113 insertions, 0 deletions
diff --git a/src/SMAPI.Web/Framework/Clients/CurseForge/CurseForgeClient.cs b/src/SMAPI.Web/Framework/Clients/CurseForge/CurseForgeClient.cs
new file mode 100644
index 00000000..140b854e
--- /dev/null
+++ b/src/SMAPI.Web/Framework/Clients/CurseForge/CurseForgeClient.cs
@@ -0,0 +1,113 @@
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using Pathoschild.Http.Client;
+using StardewModdingAPI.Toolkit;
+using StardewModdingAPI.Web.Framework.Clients.CurseForge.ResponseModels;
+
+namespace StardewModdingAPI.Web.Framework.Clients.CurseForge
+{
+ /// <summary>An HTTP client for fetching mod metadata from the CurseForge API.</summary>
+ internal class CurseForgeClient : ICurseForgeClient
+ {
+ /*********
+ ** Fields
+ *********/
+ /// <summary>The underlying HTTP client.</summary>
+ private readonly IClient Client;
+
+ /// <summary>A regex pattern which matches a version number in a CurseForge mod file name.</summary>
+ private readonly Regex VersionInNamePattern = new Regex(@"^(?:.+? | *)v?(\d+\.\d+(?:\.\d+)?(?:-.+?)?) *(?:\.(?:zip|rar|7z))?$", RegexOptions.Compiled);
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Construct an instance.</summary>
+ /// <param name="userAgent">The user agent for the API client.</param>
+ /// <param name="apiUrl">The base URL for the CurseForge API.</param>
+ public CurseForgeClient(string userAgent, string apiUrl)
+ {
+ this.Client = new FluentClient(apiUrl).SetUserAgent(userAgent);
+ }
+
+ /// <summary>Get metadata about a mod.</summary>
+ /// <param name="id">The CurseForge mod ID.</param>
+ /// <returns>Returns the mod info if found, else <c>null</c>.</returns>
+ public async Task<CurseForgeMod> GetModAsync(long id)
+ {
+ // get raw data
+ ModModel mod = await this.Client
+ .GetAsync($"addon/{id}")
+ .As<ModModel>();
+ if (mod == null)
+ return null;
+
+ // get latest versions
+ string invalidVersion = null;
+ ISemanticVersion latest = null;
+ foreach (ModFileModel file in mod.LatestFiles)
+ {
+ // extract version
+ ISemanticVersion version;
+ {
+ string raw = this.GetRawVersion(file);
+ if (raw == null)
+ continue;
+
+ if (!SemanticVersion.TryParse(raw, out version))
+ {
+ if (invalidVersion == null)
+ invalidVersion = raw;
+ continue;
+ }
+ }
+
+ // track latest version
+ if (latest == null || version.IsNewerThan(latest))
+ latest = version;
+ }
+
+ // get error
+ string error = null;
+ if (latest == null && invalidVersion == null)
+ {
+ error = mod.LatestFiles.Any()
+ ? $"CurseForge mod {id} has no downloads which specify the version in a recognised format."
+ : $"CurseForge mod {id} has no downloads.";
+ }
+
+ // generate result
+ return new CurseForgeMod
+ {
+ Name = mod.Name,
+ LatestVersion = latest?.ToString() ?? invalidVersion,
+ Url = mod.WebsiteUrl,
+ Error = error
+ };
+ }
+
+ /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
+ public void Dispose()
+ {
+ this.Client?.Dispose();
+ }
+
+
+ /*********
+ ** Private methods
+ *********/
+ /// <summary>Get a raw version string for a mod file, if available.</summary>
+ /// <param name="file">The file whose version to get.</param>
+ private string GetRawVersion(ModFileModel file)
+ {
+ Match match = this.VersionInNamePattern.Match(file.DisplayName);
+ if (!match.Success)
+ match = this.VersionInNamePattern.Match(file.FileName);
+
+ return match.Success
+ ? match.Groups[1].Value
+ : null;
+ }
+ }
+}