summaryrefslogtreecommitdiff
path: root/src/SMAPI.Web/Framework/ModRepositories
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2020-05-23 21:55:11 -0400
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2020-05-23 21:55:11 -0400
commit786077340f2cea37d82455fc413535ae82a912ee (patch)
tree588d6755b1001bd7eb218dcf9b332feb933e180b /src/SMAPI.Web/Framework/ModRepositories
parentd7add894419543667e60569bfeb439e8e797a4d1 (diff)
downloadSMAPI-786077340f2cea37d82455fc413535ae82a912ee.tar.gz
SMAPI-786077340f2cea37d82455fc413535ae82a912ee.tar.bz2
SMAPI-786077340f2cea37d82455fc413535ae82a912ee.zip
refactor update check API
This simplifies the logic for individual clients, centralises common logic, and prepares for upcoming features.
Diffstat (limited to 'src/SMAPI.Web/Framework/ModRepositories')
-rw-r--r--src/SMAPI.Web/Framework/ModRepositories/BaseRepository.cs51
-rw-r--r--src/SMAPI.Web/Framework/ModRepositories/ChucklefishRepository.cs57
-rw-r--r--src/SMAPI.Web/Framework/ModRepositories/CurseForgeRepository.cs63
-rw-r--r--src/SMAPI.Web/Framework/ModRepositories/GitHubRepository.cs82
-rw-r--r--src/SMAPI.Web/Framework/ModRepositories/IModRepository.cs24
-rw-r--r--src/SMAPI.Web/Framework/ModRepositories/ModDropRepository.cs57
-rw-r--r--src/SMAPI.Web/Framework/ModRepositories/ModInfoModel.cs96
-rw-r--r--src/SMAPI.Web/Framework/ModRepositories/NexusRepository.cs65
-rw-r--r--src/SMAPI.Web/Framework/ModRepositories/RemoteModStatus.cs18
9 files changed, 0 insertions, 513 deletions
diff --git a/src/SMAPI.Web/Framework/ModRepositories/BaseRepository.cs b/src/SMAPI.Web/Framework/ModRepositories/BaseRepository.cs
deleted file mode 100644
index f9f9f47d..00000000
--- a/src/SMAPI.Web/Framework/ModRepositories/BaseRepository.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-using StardewModdingAPI.Toolkit.Framework.UpdateData;
-
-namespace StardewModdingAPI.Web.Framework.ModRepositories
-{
- internal abstract class RepositoryBase : IModRepository
- {
- /*********
- ** Accessors
- *********/
- /// <summary>The unique key for this vendor.</summary>
- public ModRepositoryKey VendorKey { get; }
-
-
- /*********
- ** Public methods
- *********/
- /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
- public abstract void Dispose();
-
- /// <summary>Get metadata about a mod in the repository.</summary>
- /// <param name="id">The mod ID in this repository.</param>
- public abstract Task<ModInfoModel> GetModInfoAsync(string id);
-
-
- /*********
- ** Protected methods
- *********/
- /// <summary>Construct an instance.</summary>
- /// <param name="vendorKey">The unique key for this vendor.</param>
- protected RepositoryBase(ModRepositoryKey vendorKey)
- {
- this.VendorKey = vendorKey;
- }
-
- /// <summary>Normalize a version string.</summary>
- /// <param name="version">The version to normalize.</param>
- protected string NormalizeVersion(string version)
- {
- if (string.IsNullOrWhiteSpace(version))
- return null;
-
- version = version.Trim();
- if (Regex.IsMatch(version, @"^v\d", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase)) // common version prefix
- version = version.Substring(1);
-
- return version;
- }
- }
-}
diff --git a/src/SMAPI.Web/Framework/ModRepositories/ChucklefishRepository.cs b/src/SMAPI.Web/Framework/ModRepositories/ChucklefishRepository.cs
deleted file mode 100644
index 0945735a..00000000
--- a/src/SMAPI.Web/Framework/ModRepositories/ChucklefishRepository.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-using System;
-using System.Threading.Tasks;
-using StardewModdingAPI.Toolkit.Framework.UpdateData;
-using StardewModdingAPI.Web.Framework.Clients.Chucklefish;
-
-namespace StardewModdingAPI.Web.Framework.ModRepositories
-{
- /// <summary>An HTTP client for fetching mod metadata from the Chucklefish mod site.</summary>
- internal class ChucklefishRepository : RepositoryBase
- {
- /*********
- ** Fields
- *********/
- /// <summary>The underlying HTTP client.</summary>
- private readonly IChucklefishClient Client;
-
-
- /*********
- ** Public methods
- *********/
- /// <summary>Construct an instance.</summary>
- /// <param name="client">The underlying HTTP client.</param>
- public ChucklefishRepository(IChucklefishClient client)
- : base(ModRepositoryKey.Chucklefish)
- {
- this.Client = client;
- }
-
- /// <summary>Get metadata about a mod in the repository.</summary>
- /// <param name="id">The mod ID in this repository.</param>
- public override async Task<ModInfoModel> GetModInfoAsync(string id)
- {
- // validate ID format
- if (!uint.TryParse(id, out uint realID))
- return new ModInfoModel().SetError(RemoteModStatus.DoesNotExist, $"The value '{id}' isn't a valid Chucklefish mod ID, must be an integer ID.");
-
- // fetch info
- try
- {
- var mod = await this.Client.GetModAsync(realID);
- return mod != null
- ? new ModInfoModel(name: mod.Name, version: this.NormalizeVersion(mod.Version), url: mod.Url)
- : new ModInfoModel().SetError(RemoteModStatus.DoesNotExist, "Found no Chucklefish mod with this ID.");
- }
- catch (Exception ex)
- {
- return new ModInfoModel().SetError(RemoteModStatus.TemporaryError, ex.ToString());
- }
- }
-
- /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
- public override void Dispose()
- {
- this.Client.Dispose();
- }
- }
-}
diff --git a/src/SMAPI.Web/Framework/ModRepositories/CurseForgeRepository.cs b/src/SMAPI.Web/Framework/ModRepositories/CurseForgeRepository.cs
deleted file mode 100644
index 93ddc1eb..00000000
--- a/src/SMAPI.Web/Framework/ModRepositories/CurseForgeRepository.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-using System;
-using System.Threading.Tasks;
-using StardewModdingAPI.Toolkit.Framework.UpdateData;
-using StardewModdingAPI.Web.Framework.Clients.CurseForge;
-
-namespace StardewModdingAPI.Web.Framework.ModRepositories
-{
- /// <summary>An HTTP client for fetching mod metadata from CurseForge.</summary>
- internal class CurseForgeRepository : RepositoryBase
- {
- /*********
- ** Fields
- *********/
- /// <summary>The underlying CurseForge API client.</summary>
- private readonly ICurseForgeClient Client;
-
-
- /*********
- ** Public methods
- *********/
- /// <summary>Construct an instance.</summary>
- /// <param name="client">The underlying CurseForge API client.</param>
- public CurseForgeRepository(ICurseForgeClient client)
- : base(ModRepositoryKey.CurseForge)
- {
- this.Client = client;
- }
-
- /// <summary>Get metadata about a mod in the repository.</summary>
- /// <param name="id">The mod ID in this repository.</param>
- public override async Task<ModInfoModel> GetModInfoAsync(string id)
- {
- // validate ID format
- if (!uint.TryParse(id, out uint curseID))
- return new ModInfoModel().SetError(RemoteModStatus.DoesNotExist, $"The value '{id}' isn't a valid CurseForge mod ID, must be an integer ID.");
-
- // fetch info
- try
- {
- CurseForgeMod mod = await this.Client.GetModAsync(curseID);
- if (mod == null)
- return new ModInfoModel().SetError(RemoteModStatus.DoesNotExist, "Found no CurseForge mod with this ID.");
- if (mod.Error != null)
- {
- RemoteModStatus remoteStatus = RemoteModStatus.InvalidData;
- return new ModInfoModel().SetError(remoteStatus, mod.Error);
- }
-
- return new ModInfoModel(name: mod.Name, version: this.NormalizeVersion(mod.LatestVersion), url: mod.Url);
- }
- catch (Exception ex)
- {
- return new ModInfoModel().SetError(RemoteModStatus.TemporaryError, ex.ToString());
- }
- }
-
- /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
- public override void Dispose()
- {
- this.Client.Dispose();
- }
- }
-}
diff --git a/src/SMAPI.Web/Framework/ModRepositories/GitHubRepository.cs b/src/SMAPI.Web/Framework/ModRepositories/GitHubRepository.cs
deleted file mode 100644
index c62cb73f..00000000
--- a/src/SMAPI.Web/Framework/ModRepositories/GitHubRepository.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-using System;
-using System.Threading.Tasks;
-using StardewModdingAPI.Toolkit.Framework.UpdateData;
-using StardewModdingAPI.Web.Framework.Clients.GitHub;
-
-namespace StardewModdingAPI.Web.Framework.ModRepositories
-{
- /// <summary>An HTTP client for fetching mod metadata from GitHub project releases.</summary>
- internal class GitHubRepository : RepositoryBase
- {
- /*********
- ** Fields
- *********/
- /// <summary>The underlying GitHub API client.</summary>
- private readonly IGitHubClient Client;
-
-
- /*********
- ** Public methods
- *********/
- /// <summary>Construct an instance.</summary>
- /// <param name="client">The underlying GitHub API client.</param>
- public GitHubRepository(IGitHubClient client)
- : base(ModRepositoryKey.GitHub)
- {
- this.Client = client;
- }
-
- /// <summary>Get metadata about a mod in the repository.</summary>
- /// <param name="id">The mod ID in this repository.</param>
- public override async Task<ModInfoModel> GetModInfoAsync(string id)
- {
- ModInfoModel result = new ModInfoModel().SetBasicInfo(id, $"https://github.com/{id}/releases");
-
- // validate ID format
- if (!id.Contains("/") || id.IndexOf("/", StringComparison.InvariantCultureIgnoreCase) != id.LastIndexOf("/", StringComparison.InvariantCultureIgnoreCase))
- return result.SetError(RemoteModStatus.DoesNotExist, $"The value '{id}' isn't a valid GitHub mod ID, must be a username and project name like 'Pathoschild/LookupAnything'.");
-
- // fetch info
- try
- {
- // fetch repo info
- GitRepo repository = await this.Client.GetRepositoryAsync(id);
- if (repository == null)
- return result.SetError(RemoteModStatus.DoesNotExist, "Found no GitHub repository for this ID.");
- result
- .SetBasicInfo(repository.FullName, $"{repository.WebUrl}/releases")
- .SetLicense(url: repository.License?.Url, name: repository.License?.SpdxId ?? repository.License?.Name);
-
- // get latest release (whether preview or stable)
- GitRelease latest = await this.Client.GetLatestReleaseAsync(id, includePrerelease: true);
- if (latest == null)
- return result.SetError(RemoteModStatus.DoesNotExist, "Found no GitHub release for this ID.");
-
- // split stable/prerelease if applicable
- GitRelease preview = null;
- if (latest.IsPrerelease)
- {
- GitRelease release = await this.Client.GetLatestReleaseAsync(id, includePrerelease: false);
- if (release != null)
- {
- preview = latest;
- latest = release;
- }
- }
-
- // return data
- return result.SetVersions(version: this.NormalizeVersion(latest.Tag), previewVersion: this.NormalizeVersion(preview?.Tag));
- }
- catch (Exception ex)
- {
- return result.SetError(RemoteModStatus.TemporaryError, ex.ToString());
- }
- }
-
- /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
- public override void Dispose()
- {
- this.Client.Dispose();
- }
- }
-}
diff --git a/src/SMAPI.Web/Framework/ModRepositories/IModRepository.cs b/src/SMAPI.Web/Framework/ModRepositories/IModRepository.cs
deleted file mode 100644
index 68f754ae..00000000
--- a/src/SMAPI.Web/Framework/ModRepositories/IModRepository.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-using System.Threading.Tasks;
-using StardewModdingAPI.Toolkit.Framework.UpdateData;
-
-namespace StardewModdingAPI.Web.Framework.ModRepositories
-{
- /// <summary>A repository which provides mod metadata.</summary>
- internal interface IModRepository : IDisposable
- {
- /*********
- ** Accessors
- *********/
- /// <summary>The unique key for this vendor.</summary>
- ModRepositoryKey VendorKey { get; }
-
-
- /*********
- ** Public methods
- *********/
- /// <summary>Get metadata about a mod in the repository.</summary>
- /// <param name="id">The mod ID in this repository.</param>
- Task<ModInfoModel> GetModInfoAsync(string id);
- }
-}
diff --git a/src/SMAPI.Web/Framework/ModRepositories/ModDropRepository.cs b/src/SMAPI.Web/Framework/ModRepositories/ModDropRepository.cs
deleted file mode 100644
index 62142668..00000000
--- a/src/SMAPI.Web/Framework/ModRepositories/ModDropRepository.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-using System;
-using System.Threading.Tasks;
-using StardewModdingAPI.Toolkit.Framework.UpdateData;
-using StardewModdingAPI.Web.Framework.Clients.ModDrop;
-
-namespace StardewModdingAPI.Web.Framework.ModRepositories
-{
- /// <summary>An HTTP client for fetching mod metadata from the ModDrop API.</summary>
- internal class ModDropRepository : RepositoryBase
- {
- /*********
- ** Fields
- *********/
- /// <summary>The underlying ModDrop API client.</summary>
- private readonly IModDropClient Client;
-
-
- /*********
- ** Public methods
- *********/
- /// <summary>Construct an instance.</summary>
- /// <param name="client">The underlying Nexus Mods API client.</param>
- public ModDropRepository(IModDropClient client)
- : base(ModRepositoryKey.ModDrop)
- {
- this.Client = client;
- }
-
- /// <summary>Get metadata about a mod in the repository.</summary>
- /// <param name="id">The mod ID in this repository.</param>
- public override async Task<ModInfoModel> GetModInfoAsync(string id)
- {
- // validate ID format
- if (!long.TryParse(id, out long modDropID))
- return new ModInfoModel().SetError(RemoteModStatus.DoesNotExist, $"The value '{id}' isn't a valid ModDrop mod ID, must be an integer ID.");
-
- // fetch info
- try
- {
- ModDropMod mod = await this.Client.GetModAsync(modDropID);
- return mod != null
- ? new ModInfoModel(name: mod.Name, version: mod.LatestDefaultVersion?.ToString(), previewVersion: mod.LatestOptionalVersion?.ToString(), url: mod.Url)
- : new ModInfoModel().SetError(RemoteModStatus.DoesNotExist, "Found no ModDrop mod with this ID.");
- }
- catch (Exception ex)
- {
- return new ModInfoModel().SetError(RemoteModStatus.TemporaryError, ex.ToString());
- }
- }
-
- /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
- public override void Dispose()
- {
- this.Client.Dispose();
- }
- }
-}
diff --git a/src/SMAPI.Web/Framework/ModRepositories/ModInfoModel.cs b/src/SMAPI.Web/Framework/ModRepositories/ModInfoModel.cs
deleted file mode 100644
index 46b98860..00000000
--- a/src/SMAPI.Web/Framework/ModRepositories/ModInfoModel.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-namespace StardewModdingAPI.Web.Framework.ModRepositories
-{
- /// <summary>Generic metadata about a mod.</summary>
- internal class ModInfoModel
- {
- /*********
- ** Accessors
- *********/
- /// <summary>The mod name.</summary>
- public string Name { get; set; }
-
- /// <summary>The mod's latest version.</summary>
- public string Version { get; set; }
-
- /// <summary>The mod's latest optional or prerelease version, if newer than <see cref="Version"/>.</summary>
- public string PreviewVersion { get; set; }
-
- /// <summary>The mod's web URL.</summary>
- public string Url { get; set; }
-
- /// <summary>The license URL, if available.</summary>
- public string LicenseUrl { get; set; }
-
- /// <summary>The license name, if available.</summary>
- public string LicenseName { get; set; }
-
- /// <summary>The mod availability status on the remote site.</summary>
- public RemoteModStatus Status { get; set; } = RemoteModStatus.Ok;
-
- /// <summary>The error message indicating why the mod is invalid (if applicable).</summary>
- public string Error { get; set; }
-
-
- /*********
- ** Public methods
- *********/
- /// <summary>Construct an empty instance.</summary>
- public ModInfoModel() { }
-
- /// <summary>Construct an instance.</summary>
- /// <param name="name">The mod name.</param>
- /// <param name="version">The semantic version for the mod's latest release.</param>
- /// <param name="previewVersion">The semantic version for the mod's latest preview release, if available and different from <see cref="Version"/>.</param>
- /// <param name="url">The mod's web URL.</param>
- public ModInfoModel(string name, string version, string url, string previewVersion = null)
- {
- this
- .SetBasicInfo(name, url)
- .SetVersions(version, previewVersion);
- }
-
- /// <summary>Set the basic mod info.</summary>
- /// <param name="name">The mod name.</param>
- /// <param name="url">The mod's web URL.</param>
- public ModInfoModel SetBasicInfo(string name, string url)
- {
- this.Name = name;
- this.Url = url;
-
- return this;
- }
-
- /// <summary>Set the mod version info.</summary>
- /// <param name="version">The semantic version for the mod's latest release.</param>
- /// <param name="previewVersion">The semantic version for the mod's latest preview release, if available and different from <see cref="Version"/>.</param>
- public ModInfoModel SetVersions(string version, string previewVersion = null)
- {
- this.Version = version;
- this.PreviewVersion = previewVersion;
-
- return this;
- }
-
- /// <summary>Set the license info, if available.</summary>
- /// <param name="url">The license URL.</param>
- /// <param name="name">The license name.</param>
- public ModInfoModel SetLicense(string url, string name)
- {
- this.LicenseUrl = url;
- this.LicenseName = name;
-
- return this;
- }
-
- /// <summary>Set a mod error.</summary>
- /// <param name="status">The mod availability status on the remote site.</param>
- /// <param name="error">The error message indicating why the mod is invalid (if applicable).</param>
- public ModInfoModel SetError(RemoteModStatus status, string error)
- {
- this.Status = status;
- this.Error = error;
-
- return this;
- }
- }
-}
diff --git a/src/SMAPI.Web/Framework/ModRepositories/NexusRepository.cs b/src/SMAPI.Web/Framework/ModRepositories/NexusRepository.cs
deleted file mode 100644
index 9551258c..00000000
--- a/src/SMAPI.Web/Framework/ModRepositories/NexusRepository.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-using System;
-using System.Threading.Tasks;
-using StardewModdingAPI.Toolkit.Framework.UpdateData;
-using StardewModdingAPI.Web.Framework.Clients.Nexus;
-
-namespace StardewModdingAPI.Web.Framework.ModRepositories
-{
- /// <summary>An HTTP client for fetching mod metadata from Nexus Mods.</summary>
- internal class NexusRepository : RepositoryBase
- {
- /*********
- ** Fields
- *********/
- /// <summary>The underlying Nexus Mods API client.</summary>
- private readonly INexusClient Client;
-
-
- /*********
- ** Public methods
- *********/
- /// <summary>Construct an instance.</summary>
- /// <param name="client">The underlying Nexus Mods API client.</param>
- public NexusRepository(INexusClient client)
- : base(ModRepositoryKey.Nexus)
- {
- this.Client = client;
- }
-
- /// <summary>Get metadata about a mod in the repository.</summary>
- /// <param name="id">The mod ID in this repository.</param>
- public override async Task<ModInfoModel> GetModInfoAsync(string id)
- {
- // validate ID format
- if (!uint.TryParse(id, out uint nexusID))
- return new ModInfoModel().SetError(RemoteModStatus.DoesNotExist, $"The value '{id}' isn't a valid Nexus mod ID, must be an integer ID.");
-
- // fetch info
- try
- {
- NexusMod mod = await this.Client.GetModAsync(nexusID);
- if (mod == null)
- return new ModInfoModel().SetError(RemoteModStatus.DoesNotExist, "Found no Nexus mod with this ID.");
- if (mod.Error != null)
- {
- RemoteModStatus remoteStatus = mod.Status == NexusModStatus.Hidden || mod.Status == NexusModStatus.NotPublished
- ? RemoteModStatus.DoesNotExist
- : RemoteModStatus.TemporaryError;
- return new ModInfoModel().SetError(remoteStatus, mod.Error);
- }
-
- return new ModInfoModel(name: mod.Name, version: this.NormalizeVersion(mod.Version), previewVersion: mod.LatestFileVersion?.ToString(), url: mod.Url);
- }
- catch (Exception ex)
- {
- return new ModInfoModel().SetError(RemoteModStatus.TemporaryError, ex.ToString());
- }
- }
-
- /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
- public override void Dispose()
- {
- this.Client.Dispose();
- }
- }
-}
diff --git a/src/SMAPI.Web/Framework/ModRepositories/RemoteModStatus.cs b/src/SMAPI.Web/Framework/ModRepositories/RemoteModStatus.cs
deleted file mode 100644
index 02876556..00000000
--- a/src/SMAPI.Web/Framework/ModRepositories/RemoteModStatus.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-namespace StardewModdingAPI.Web.Framework.ModRepositories
-{
- /// <summary>The mod availability status on a remote site.</summary>
- internal enum RemoteModStatus
- {
- /// <summary>The mod is valid.</summary>
- Ok,
-
- /// <summary>The mod data was fetched, but the data is not valid (e.g. version isn't semantic).</summary>
- InvalidData,
-
- /// <summary>The mod does not exist.</summary>
- DoesNotExist,
-
- /// <summary>The mod was temporarily unavailable (e.g. the site could not be reached or an unknown error occurred).</summary>
- TemporaryError
- }
-}