diff options
author | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2020-05-23 21:55:11 -0400 |
---|---|---|
committer | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2020-05-23 21:55:11 -0400 |
commit | 786077340f2cea37d82455fc413535ae82a912ee (patch) | |
tree | 588d6755b1001bd7eb218dcf9b332feb933e180b /src/SMAPI.Web/Framework/ModRepositories | |
parent | d7add894419543667e60569bfeb439e8e797a4d1 (diff) | |
download | SMAPI-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')
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 - } -} |