summaryrefslogtreecommitdiff
path: root/src/SMAPI.Web/Framework/Clients/UpdateManifest
diff options
context:
space:
mode:
Diffstat (limited to 'src/SMAPI.Web/Framework/Clients/UpdateManifest')
-rw-r--r--src/SMAPI.Web/Framework/Clients/UpdateManifest/IUpdateManifestClient.cs3
-rw-r--r--src/SMAPI.Web/Framework/Clients/UpdateManifest/TextAsJsonMediaTypeFormatter.cs18
-rw-r--r--src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestClient.cs37
-rw-r--r--src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestModDownload.cs40
-rw-r--r--src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestModModel.cs32
-rw-r--r--src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestModPage.cs80
-rw-r--r--src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestModel.cs30
-rw-r--r--src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestVersionModel.cs28
8 files changed, 163 insertions, 105 deletions
diff --git a/src/SMAPI.Web/Framework/Clients/UpdateManifest/IUpdateManifestClient.cs b/src/SMAPI.Web/Framework/Clients/UpdateManifest/IUpdateManifestClient.cs
index 36d018c7..dd9f5811 100644
--- a/src/SMAPI.Web/Framework/Clients/UpdateManifest/IUpdateManifestClient.cs
+++ b/src/SMAPI.Web/Framework/Clients/UpdateManifest/IUpdateManifestClient.cs
@@ -3,7 +3,6 @@ using System;
namespace StardewModdingAPI.Web.Framework.Clients.UpdateManifest
{
- /// <summary>An HTTP client for fetching an update manifest from an arbitrary URL.</summary>
+ /// <summary>An API client for fetching update metadata from an arbitrary JSON URL.</summary>
internal interface IUpdateManifestClient : IModSiteClient, IDisposable { }
}
-
diff --git a/src/SMAPI.Web/Framework/Clients/UpdateManifest/TextAsJsonMediaTypeFormatter.cs b/src/SMAPI.Web/Framework/Clients/UpdateManifest/TextAsJsonMediaTypeFormatter.cs
index 48e3c294..02722cb1 100644
--- a/src/SMAPI.Web/Framework/Clients/UpdateManifest/TextAsJsonMediaTypeFormatter.cs
+++ b/src/SMAPI.Web/Framework/Clients/UpdateManifest/TextAsJsonMediaTypeFormatter.cs
@@ -1,14 +1,18 @@
-// Copyright 2022 Jamie Taylor
+// Copyright 2022 Jamie Taylor
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
-namespace StardewModdingAPI.Web.Framework.Clients.UpdateManifest {
- /// <summary>
- /// A <see cref="JsonMediaTypeFormatter"/> that can parse from content of type <c>text/plain</c>.
- /// </summary>
- internal class TextAsJsonMediaTypeFormatter : JsonMediaTypeFormatter {
+namespace StardewModdingAPI.Web.Framework.Clients.UpdateManifest
+{
+ /// <summary>A <see cref="JsonMediaTypeFormatter"/> that can parse from content of type <c>text/plain</c>.</summary>
+ internal class TextAsJsonMediaTypeFormatter : JsonMediaTypeFormatter
+ {
+ /*********
+ ** Public methods
+ *********/
/// <summary>Construct a new <see cref="JsonMediaTypeFormatter"/></summary>
- public TextAsJsonMediaTypeFormatter() {
+ public TextAsJsonMediaTypeFormatter()
+ {
this.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/plain"));
}
}
diff --git a/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestClient.cs b/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestClient.cs
index d7cf4945..88a5c2f6 100644
--- a/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestClient.cs
+++ b/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestClient.cs
@@ -1,19 +1,21 @@
// Copyright 2022 Jamie Taylor
-using System;
+using System.Net;
+using System.Threading.Tasks;
using Pathoschild.Http.Client;
using StardewModdingAPI.Toolkit.Framework.UpdateData;
-using System.Threading.Tasks;
-using System.Net;
-namespace StardewModdingAPI.Web.Framework.Clients.UpdateManifest {
- /// <summary>An HTTP client for fetching an update manifest from an arbitrary URL.</summary>
- internal class UpdateManifestClient : IUpdateManifestClient {
+namespace StardewModdingAPI.Web.Framework.Clients.UpdateManifest
+{
+ /// <summary>An API client for fetching update metadata from an arbitrary JSON URL.</summary>
+ internal class UpdateManifestClient : IUpdateManifestClient
+ {
/*********
** Fields
*********/
/// <summary>The underlying HTTP client.</summary>
private readonly IClient Client;
+
/*********
** Accessors
*********/
@@ -26,30 +28,35 @@ namespace StardewModdingAPI.Web.Framework.Clients.UpdateManifest {
*********/
/// <summary>Construct an instance.</summary>
/// <param name="userAgent">The user agent for the API client.</param>
- public UpdateManifestClient(string userAgent) {
+ public UpdateManifestClient(string userAgent)
+ {
this.Client = new FluentClient()
.SetUserAgent(userAgent);
this.Client.Formatters.Add(new TextAsJsonMediaTypeFormatter());
}
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
- public void Dispose() {
+ public void Dispose()
+ {
this.Client.Dispose();
}
/// <inheritdoc/>
- public async Task<IModPage?> GetModData(string id) {
+ public async Task<IModPage?> GetModData(string id)
+ {
UpdateManifestModel? manifest;
- try {
+ try
+ {
manifest = await this.Client.GetAsync(id).As<UpdateManifestModel?>();
- } catch (ApiException ex) when (ex.Status == HttpStatusCode.NotFound) {
- return new GenericModPage(this.SiteKey, id).SetError(RemoteModStatus.DoesNotExist, $"No update manifest found at {id}");
}
- if (manifest is null) {
- return new GenericModPage(this.SiteKey, id).SetError(RemoteModStatus.DoesNotExist, $"Error parsing manifest at {id}");
+ catch (ApiException ex) when (ex.Status == HttpStatusCode.NotFound)
+ {
+ return new GenericModPage(this.SiteKey, id).SetError(RemoteModStatus.DoesNotExist, $"No update manifest found at {id}");
}
- return new UpdateManifestModPage(id, manifest);
+ return manifest is not null
+ ? new UpdateManifestModPage(id, manifest)
+ : new GenericModPage(this.SiteKey, id).SetError(RemoteModStatus.DoesNotExist, $"The update manifest at {id} has an invalid format");
}
}
}
diff --git a/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestModDownload.cs b/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestModDownload.cs
index 117ae15c..0a6d4736 100644
--- a/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestModDownload.cs
+++ b/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestModDownload.cs
@@ -1,27 +1,35 @@
// Copyright 2022 Jamie Taylor
-using System;
-namespace StardewModdingAPI.Web.Framework.Clients.UpdateManifest {
+namespace StardewModdingAPI.Web.Framework.Clients.UpdateManifest
+{
/// <summary>Metadata about a mod download in an update manifest file.</summary>
- internal class UpdateManifestModDownload : GenericModDownload {
- /// <summary>The subkey for this mod download</summary>
- private readonly string subkey;
+ internal class UpdateManifestModDownload : GenericModDownload
+ {
+ /*********
+ ** Fields
+ *********/
+ /// <summary>The update subkey for this mod download.</summary>
+ private readonly string Subkey;
+
+
+ /*********
+ ** Public methods
+ *********/
/// <summary>Construct an instance.</summary>
- /// <param name="subkey">The subkey for this download.</param>
+ /// <param name="fieldName">The field name for this mod download in the manifest.</param>
/// <param name="name">The mod name for this download.</param>
/// <param name="version">The download's version.</param>
/// <param name="url">The download's URL.</param>
- public UpdateManifestModDownload(string subkey, string name, string? version, string? url) : base(name, null, version, url) {
- this.subkey = subkey;
+ public UpdateManifestModDownload(string fieldName, string name, string? version, string? url)
+ : base(name, null, version, url)
+ {
+ this.Subkey = fieldName;
}
- /// <summary>
- /// Returns <see langword="true"/> iff the given subkey is the same as the subkey for this download.
- /// </summary>
- /// <param name="subkey">The subkey to match</param>
- /// <returns><see langword="true"/> if <paramref name="subkey"/> is the same as the subkey for this download, <see langword="false"/> otherwise.</returns>
- public override bool MatchesSubkey(string subkey) {
- return this.subkey == subkey;
+ /// <summary>Get whether the subkey matches this download.</summary>
+ /// <param name="subkey">The update subkey to check.</param>
+ public override bool MatchesSubkey(string subkey)
+ {
+ return subkey == this.Subkey;
}
}
}
-
diff --git a/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestModModel.cs b/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestModModel.cs
index 4ec9c03d..92642321 100644
--- a/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestModModel.cs
+++ b/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestModModel.cs
@@ -1,26 +1,34 @@
// Copyright 2022 Jamie Taylor
-using System;
-namespace StardewModdingAPI.Web.Framework.Clients.UpdateManifest {
- /// <summary>Data model for a mod in an update manifest.</summary>
- internal class UpdateManifestModModel {
+namespace StardewModdingAPI.Web.Framework.Clients.UpdateManifest
+{
+ /// <summary>The data model for a mod in an update manifest file.</summary>
+ internal class UpdateManifestModModel
+ {
+ /*********
+ ** Accessors
+ *********/
/// <summary>The mod's name.</summary>
- public string Name { get; }
+ public string? Name { get; }
- /// <summary>The mod's URL.</summary>
+ /// <summary>The mod page URL from which to download updates.</summary>
public string? Url { get; }
- /// <summary>The versions for this mod.</summary>
- public UpdateManifestVersionModel[] Versions { get; }
+ /// <summary>The available versions for this mod.</summary>
+ public UpdateManifestVersionModel[]? Versions { get; }
+
+ /*********
+ ** Public methods
+ *********/
/// <summary>Construct an instance.</summary>
/// <param name="name">The mod's name.</param>
- /// <param name="url">The mod's URL.</param>
- /// <param name="versions">The versions for this mod.</param>
- public UpdateManifestModModel(string name, string? url, UpdateManifestVersionModel[] versions) {
+ /// <param name="url">The mod page URL from which to download updates.</param>
+ /// <param name="versions">The available versions for this mod.</param>
+ public UpdateManifestModModel(string? name, string? url, UpdateManifestVersionModel[]? versions)
+ {
this.Name = name;
this.Url = url;
this.Versions = versions;
}
}
}
-
diff --git a/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestModPage.cs b/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestModPage.cs
index 109175b5..bbc7b5da 100644
--- a/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestModPage.cs
+++ b/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestModPage.cs
@@ -1,58 +1,74 @@
-// Copyright 2022 Jamie Taylor
-using System;
+// Copyright 2022 Jamie Taylor
using System.Collections.Generic;
using System.Linq;
using StardewModdingAPI.Toolkit.Framework.UpdateData;
-namespace StardewModdingAPI.Web.Framework.Clients.UpdateManifest {
+namespace StardewModdingAPI.Web.Framework.Clients.UpdateManifest
+{
/// <summary>Metadata about an update manifest "page".</summary>
- internal class UpdateManifestModPage : GenericModPage {
- /// <summary>The update manifest model.</summary>
- private UpdateManifestModel manifest;
-
- /// <summary>Constuct an instance.</summary>
- /// <param name="id">The "id" (i.e., URL) of this update manifest.</param>
- /// <param name="manifest">The manifest object model.</param>
- public UpdateManifestModPage(string id, UpdateManifestModel manifest) : base(ModSiteKey.UpdateManifest, id) {
+ internal class UpdateManifestModPage : GenericModPage
+ {
+ /*********
+ ** Fields
+ *********/
+ /// <summary>The mods from the update manifest.</summary>
+ private readonly IDictionary<string, UpdateManifestModModel> Mods;
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Construct an instance.</summary>
+ /// <param name="url">The URL of the update manifest file.</param>
+ /// <param name="manifest">The parsed update manifest.</param>
+ public UpdateManifestModPage(string url, UpdateManifestModel manifest)
+ : base(ModSiteKey.UpdateManifest, url)
+ {
this.IsSubkeyStrict = true;
- this.manifest = manifest;
- this.SetInfo(name: id, url: id, version: null, downloads: TranslateDownloads(manifest).ToArray());
+ this.Mods = manifest.Mods ?? new Dictionary<string, UpdateManifestModModel>();
+ this.SetInfo(name: url, url: url, version: null, downloads: this.ParseDownloads(manifest.Mods).ToArray());
}
/// <summary>Return the mod name for the given subkey, if it exists in this update manifest.</summary>
/// <param name="subkey">The subkey.</param>
/// <returns>The mod name for the given subkey, or <see langword="null"/> if this manifest does not contain the given subkey.</returns>
- public override string? GetName(string? subkey) {
- if (subkey is null)
- return null;
- this.manifest.Subkeys.TryGetValue(subkey, out UpdateManifestModModel? modModel);
- return modModel?.Name;
+ public override string? GetName(string? subkey)
+ {
+ return subkey is not null && this.Mods.TryGetValue(subkey, out UpdateManifestModModel? modModel)
+ ? modModel.Name
+ : null;
}
/// <summary>Return the mod URL for the given subkey, if it exists in this update manifest.</summary>
/// <param name="subkey">The subkey.</param>
/// <returns>The mod URL for the given subkey, or <see langword="null"/> if this manifest does not contain the given subkey.</returns>
- public override string? GetUrl(string? subkey) {
- if (subkey is null)
- return null;
- this.manifest.Subkeys.TryGetValue(subkey, out UpdateManifestModModel? modModel);
- return modModel?.Url;
+ public override string? GetUrl(string? subkey)
+ {
+ return subkey is not null && this.Mods.TryGetValue(subkey, out UpdateManifestModModel? modModel)
+ ? modModel.Url
+ : null;
}
/*********
** Private methods
*********/
- /// <summary>Translate the downloads from the manifest's object model into <see cref="IModDownload"/> objects.</summary>
- /// <param name="manifest">The manifest object model.</param>
- /// <returns>An <see cref="IModDownload"/> for each <see cref="UpdateManifestVersionModel"/> in the manifest.</returns>
- private static IEnumerable<IModDownload> TranslateDownloads(UpdateManifestModel manifest) {
- foreach (var entry in manifest.Subkeys) {
- foreach (var version in entry.Value.Versions) {
- yield return new UpdateManifestModDownload(entry.Key, entry.Value.Name, version.Version, version.DownloadFileUrl ?? version.DownloadPageUrl);
- }
+ /// <summary>Convert the raw download info from an update manifest to <see cref="IModDownload"/>.</summary>
+ /// <param name="mods">The mods from the update manifest.</param>
+ private IEnumerable<IModDownload> ParseDownloads(IDictionary<string, UpdateManifestModModel>? mods)
+ {
+ if (mods is null)
+ yield break;
+
+ foreach ((string modKey, UpdateManifestModModel mod) in mods)
+ {
+ if (mod.Versions is null)
+ continue;
+
+ foreach (UpdateManifestVersionModel version in mod.Versions)
+ yield return new UpdateManifestModDownload(modKey, mod.Name ?? modKey, version.Version, version.DownloadFileUrl ?? version.DownloadPageUrl);
}
}
}
-} \ No newline at end of file
+}
diff --git a/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestModel.cs b/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestModel.cs
index 03f89726..ad618022 100644
--- a/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestModel.cs
+++ b/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestModel.cs
@@ -1,23 +1,31 @@
// Copyright 2022 Jamie Taylor
-using System;
using System.Collections.Generic;
-namespace StardewModdingAPI.Web.Framework.Clients.UpdateManifest {
- /// <summary>Data model for an update manifest.</summary>
- internal class UpdateManifestModel {
+namespace StardewModdingAPI.Web.Framework.Clients.UpdateManifest
+{
+ /// <summary>The data model for an update manifest file.</summary>
+ internal class UpdateManifestModel
+ {
+ /*********
+ ** Accessors
+ *********/
/// <summary>The manifest format version.</summary>
- public string ManifestVersion { get; }
+ public string? ManifestVersion { get; }
- /// <summary>The subkeys in this update manifest.</summary>
- public IDictionary<string, UpdateManifestModModel> Subkeys { get; }
+ /// <summary>The mod info in this update manifest.</summary>
+ public IDictionary<string, UpdateManifestModModel>? Mods { get; }
+
+ /*********
+ ** Public methods
+ *********/
/// <summary>Construct an instance.</summary>
/// <param name="manifestVersion">The manifest format version.</param>
- /// <param name="subkeys">The subkeys in this update manifest.</param>
- public UpdateManifestModel(string manifestVersion, IDictionary<string, UpdateManifestModModel> subkeys) {
+ /// <param name="mods">The mod info in this update manifest.</param>
+ public UpdateManifestModel(string manifestVersion, IDictionary<string, UpdateManifestModModel> mods)
+ {
this.ManifestVersion = manifestVersion;
- this.Subkeys = subkeys;
+ this.Mods = mods;
}
}
}
-
diff --git a/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestVersionModel.cs b/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestVersionModel.cs
index 55b6db61..90e054d8 100644
--- a/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestVersionModel.cs
+++ b/src/SMAPI.Web/Framework/Clients/UpdateManifest/UpdateManifestVersionModel.cs
@@ -1,10 +1,14 @@
// Copyright 2022 Jamie Taylor
-using System;
-namespace StardewModdingAPI.Web.Framework.Clients.UpdateManifest {
+namespace StardewModdingAPI.Web.Framework.Clients.UpdateManifest
+{
/// <summary>Data model for a Version in an update manifest.</summary>
- internal class UpdateManifestVersionModel {
- /// <summary>The semantic version string.</summary>
- public string Version { get; }
+ internal class UpdateManifestVersionModel
+ {
+ /*********
+ ** Accessors
+ *********/
+ /// <summary>The mod's semantic version.</summary>
+ public string? Version { get; }
/// <summary>The URL for this version's download page (if any).</summary>
public string? DownloadPageUrl { get; }
@@ -12,15 +16,19 @@ namespace StardewModdingAPI.Web.Framework.Clients.UpdateManifest {
/// <summary>The URL for this version's direct file download (if any).</summary>
public string? DownloadFileUrl { get; }
+
+ /*********
+ ** Public methods
+ *********/
/// <summary>Construct an instance.</summary>
- /// <param name="version">The semantic version string.</param>
- /// <param name="downloadPageUrl">This version's download page URL (if any).</param>
- /// <param name="downloadFileUrl">This version's direct file download URL (if any).</param>
- public UpdateManifestVersionModel(string version, string? downloadPageUrl, string? downloadFileUrl) {
+ /// <param name="version">The mod's semantic version.</param>
+ /// <param name="downloadPageUrl">This version's download page URL, if any.</param>
+ /// <param name="downloadFileUrl">This version's direct file download URL, if any.</param>
+ public UpdateManifestVersionModel(string version, string? downloadPageUrl, string? downloadFileUrl)
+ {
this.Version = version;
this.DownloadPageUrl = downloadPageUrl;
this.DownloadFileUrl = downloadFileUrl;
}
}
}
-