From dab1ef6acc243726247cee57877c3b3100106522 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 20 Jun 2022 18:01:48 -0400 Subject: add flag to disable deprecated code --- src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/SMAPI.Toolkit') diff --git a/src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs b/src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs index 32c2ed6d..338192af 100644 --- a/src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs +++ b/src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs @@ -18,9 +18,11 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData /// The mod patches the game in a way that may impact stability. PatchesGame = 4, +#if SMAPI_FOR_WINDOWS /// The mod uses the dynamic keyword which won't work on Linux/macOS. [Obsolete("This value is no longer used by SMAPI and will be removed in the upcoming SMAPI 4.0.0.")] UsesDynamic = 8, +#endif /// The mod references specialized 'unvalidated update tick' events which may impact stability. UsesUnvalidatedUpdateTick = 16, @@ -37,6 +39,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData /// Uses .NET APIs for shell or process access. AccessesShell = 256, +#if SMAPI_DEPRECATED /// References the legacy System.Configuration.ConfigurationManager assembly and doesn't include a copy in the mod folder, so it'll break in SMAPI 4.0.0. DetectedLegacyConfigurationDll = 512, @@ -45,5 +48,6 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData /// References the legacy System.Security.Permissions assembly and doesn't include a copy in the mod folder, so it'll break in SMAPI 4.0.0. DetectedLegacyPermissionsDll = 2048 +#endif } } -- cgit From 1021c3291088d8e47dc23c608aaa7ff1f81c9fd7 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 22 Jun 2022 20:15:25 -0400 Subject: update fluent HTTP client --- src/SMAPI.Toolkit/SMAPI.Toolkit.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/SMAPI.Toolkit') diff --git a/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj b/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj index e021993f..7b79105f 100644 --- a/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj +++ b/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj @@ -11,7 +11,7 @@ - + -- cgit From 6d11c41facb2e1397a25110517cc281f87be2caf Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 28 Jun 2022 18:17:27 -0400 Subject: migrate update checks to FluentHttpClient WebClient isn't needed for compatibility with macOS after the .NET 5 update in Stardew Valley 1.5.5, and causes noticeable lag for some players even when running on a background thread. --- .../Framework/Clients/WebApi/WebApiClient.cs | 56 ++++++++-------------- src/SMAPI.Toolkit/Serialization/JsonHelper.cs | 26 ++++++---- 2 files changed, 37 insertions(+), 45 deletions(-) (limited to 'src/SMAPI.Toolkit') diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs index d4282617..ef1904d4 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs @@ -1,27 +1,24 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Net; -using Newtonsoft.Json; +using System.Threading.Tasks; +using Pathoschild.Http.Client; using StardewModdingAPI.Toolkit.Serialization; using StardewModdingAPI.Toolkit.Utilities; namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi { /// Provides methods for interacting with the SMAPI web API. - public class WebApiClient + public class WebApiClient : IDisposable { /********* ** Fields *********/ - /// The base URL for the web API. - private readonly Uri BaseUrl; - /// The API version number. private readonly ISemanticVersion Version; - /// The JSON serializer settings to use. - private readonly JsonSerializerSettings JsonSettings = new JsonHelper().JsonSettings; + /// The underlying HTTP client. + private readonly IClient Client; /********* @@ -32,8 +29,11 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi /// The web API version. public WebApiClient(string baseUrl, ISemanticVersion version) { - this.BaseUrl = new Uri(baseUrl); this.Version = version; + this.Client = new FluentClient(baseUrl) + .SetUserAgent($"SMAPI/{version}"); + + this.Client.Formatters.JsonFormatter.SerializerSettings = JsonHelper.CreateDefaultSettings(); } /// Get metadata about a set of mods from the web API. @@ -42,36 +42,22 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi /// The Stardew Valley version installed by the player. /// The OS on which the player plays. /// Whether to include extended metadata for each mod. - public IDictionary GetModInfo(ModSearchEntryModel[] mods, ISemanticVersion apiVersion, ISemanticVersion gameVersion, Platform platform, bool includeExtendedMetadata = false) + public async Task> GetModInfoAsync(ModSearchEntryModel[] mods, ISemanticVersion apiVersion, ISemanticVersion gameVersion, Platform platform, bool includeExtendedMetadata = false) { - return this.Post( - $"v{this.Version}/mods", - new ModSearchModel(mods, apiVersion, gameVersion, platform, includeExtendedMetadata) - ).ToDictionary(p => p.ID); + ModEntryModel[] result = await this.Client + .PostAsync( + $"v{this.Version}/mods", + new ModSearchModel(mods, apiVersion, gameVersion, platform, includeExtendedMetadata) + ) + .As(); + + return result.ToDictionary(p => p.ID); } - - /********* - ** Private methods - *********/ - /// Fetch the response from the backend API. - /// The body content type. - /// The expected response type. - /// The request URL, optionally excluding the base URL. - /// The body content to post. - private TResult Post(string url, TBody content) + /// + public void Dispose() { - // note: avoid HttpClient for macOS compatibility - using WebClient client = new(); - - Uri fullUrl = new(this.BaseUrl, url); - string data = JsonConvert.SerializeObject(content); - - client.Headers["Content-Type"] = "application/json"; - client.Headers["User-Agent"] = $"SMAPI/{this.Version}"; - string response = client.UploadString(fullUrl, data); - return JsonConvert.DeserializeObject(response, this.JsonSettings) - ?? throw new InvalidOperationException($"Could not parse the response from POST {url}."); + this.Client.Dispose(); } } } diff --git a/src/SMAPI.Toolkit/Serialization/JsonHelper.cs b/src/SMAPI.Toolkit/Serialization/JsonHelper.cs index 1a003c51..a5d7e2e8 100644 --- a/src/SMAPI.Toolkit/Serialization/JsonHelper.cs +++ b/src/SMAPI.Toolkit/Serialization/JsonHelper.cs @@ -15,21 +15,27 @@ namespace StardewModdingAPI.Toolkit.Serialization ** Accessors *********/ /// The JSON settings to use when serializing and deserializing files. - public JsonSerializerSettings JsonSettings { get; } = new() - { - Formatting = Formatting.Indented, - ObjectCreationHandling = ObjectCreationHandling.Replace, // avoid issue where default ICollection values are duplicated each time the config is loaded - Converters = new List - { - new SemanticVersionConverter(), - new StringEnumConverter() - } - }; + public JsonSerializerSettings JsonSettings { get; } = JsonHelper.CreateDefaultSettings(); /********* ** Public methods *********/ + /// Create an instance of the default JSON serializer settings. + public static JsonSerializerSettings CreateDefaultSettings() + { + return new() + { + Formatting = Formatting.Indented, + ObjectCreationHandling = ObjectCreationHandling.Replace, // avoid issue where default ICollection values are duplicated each time the config is loaded + Converters = new List + { + new SemanticVersionConverter(), + new StringEnumConverter() + } + }; + } + /// Read a JSON file. /// The model type. /// The absolute file path. -- cgit From 6b411d1dee49a636a8a8c9a88d9cfc0720c7c1dd Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 28 Jun 2022 20:48:28 -0400 Subject: fix deprecation check --- src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/SMAPI.Toolkit') diff --git a/src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs b/src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs index 338192af..4c76f417 100644 --- a/src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs +++ b/src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs @@ -18,7 +18,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData /// The mod patches the game in a way that may impact stability. PatchesGame = 4, -#if SMAPI_FOR_WINDOWS +#if SMAPI_DEPRECATED /// The mod uses the dynamic keyword which won't work on Linux/macOS. [Obsolete("This value is no longer used by SMAPI and will be removed in the upcoming SMAPI 4.0.0.")] UsesDynamic = 8, -- cgit From 4d9fd63d9e890a10029508c7d7e31dcc0b579db7 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 6 Jul 2022 19:24:49 -0400 Subject: update code annotations --- src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs | 10 +++++----- src/SMAPI.Toolkit/Framework/LowLevelEnvironmentUtility.cs | 7 +++++-- 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'src/SMAPI.Toolkit') diff --git a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs index 7f06d170..3bdd145a 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs @@ -283,8 +283,8 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki } /// The response model for the MediaWiki parse API. - [SuppressMessage("ReSharper", "ClassNeverInstantiated.Local")] - [SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")] + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Local", Justification = "Used via JSON deserialization.")] + [SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local", Justification = "Used via JSON deserialization.")] private class ResponseModel { /********* @@ -306,9 +306,9 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki } /// The inner response model for the MediaWiki parse API. - [SuppressMessage("ReSharper", "ClassNeverInstantiated.Local")] - [SuppressMessage("ReSharper", "CollectionNeverUpdated.Local")] - [SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")] + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Local", Justification = "Used via JSON deserialization.")] + [SuppressMessage("ReSharper", "CollectionNeverUpdated.Local", Justification = "Used via JSON deserialization.")] + [SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local", Justification = "Used via JSON deserialization.")] private class ResponseParseModel { /********* diff --git a/src/SMAPI.Toolkit/Framework/LowLevelEnvironmentUtility.cs b/src/SMAPI.Toolkit/Framework/LowLevelEnvironmentUtility.cs index 6978567e..118b71b2 100644 --- a/src/SMAPI.Toolkit/Framework/LowLevelEnvironmentUtility.cs +++ b/src/SMAPI.Toolkit/Framework/LowLevelEnvironmentUtility.cs @@ -21,6 +21,7 @@ namespace StardewModdingAPI.Toolkit.Framework /// Get the OS name from the system uname command. /// The buffer to fill with the resulting string. [DllImport("libc")] + [SuppressMessage("ReSharper", "IdentifierTypo", Justification = "This is the actual external command name.")] static extern int uname(IntPtr buffer); @@ -51,7 +52,6 @@ namespace StardewModdingAPI.Toolkit.Framework /// Get the human-readable OS name and version. /// The current platform. - [SuppressMessage("ReSharper", "EmptyGeneralCatchClause", Justification = "Error suppressed deliberately to fallback to default behaviour.")] public static string GetFriendlyPlatformName(string platform) { #if SMAPI_FOR_WINDOWS @@ -65,7 +65,10 @@ namespace StardewModdingAPI.Toolkit.Framework return result ?? "Windows"; } - catch { } + catch + { + // fallback to default behavior + } #endif string name = Environment.OSVersion.ToString(); -- cgit From 9c9552531f8f085cded6ed5158503e75b00be1ff Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 6 Jul 2022 19:25:15 -0400 Subject: fix build warnings --- src/SMAPI.Toolkit/Framework/LowLevelEnvironmentUtility.cs | 2 +- src/SMAPI.Toolkit/ModToolkit.cs | 2 +- .../Serialization/Converters/SemanticVersionConverter.cs | 7 ++++++- .../Serialization/Converters/SimpleReadOnlyConverter.cs | 7 ++++++- 4 files changed, 14 insertions(+), 4 deletions(-) (limited to 'src/SMAPI.Toolkit') diff --git a/src/SMAPI.Toolkit/Framework/LowLevelEnvironmentUtility.cs b/src/SMAPI.Toolkit/Framework/LowLevelEnvironmentUtility.cs index 118b71b2..f464f4bb 100644 --- a/src/SMAPI.Toolkit/Framework/LowLevelEnvironmentUtility.cs +++ b/src/SMAPI.Toolkit/Framework/LowLevelEnvironmentUtility.cs @@ -22,7 +22,7 @@ namespace StardewModdingAPI.Toolkit.Framework /// The buffer to fill with the resulting string. [DllImport("libc")] [SuppressMessage("ReSharper", "IdentifierTypo", Justification = "This is the actual external command name.")] - static extern int uname(IntPtr buffer); + private static extern int uname(IntPtr buffer); /********* diff --git a/src/SMAPI.Toolkit/ModToolkit.cs b/src/SMAPI.Toolkit/ModToolkit.cs index 0df75a31..55b9bdd8 100644 --- a/src/SMAPI.Toolkit/ModToolkit.cs +++ b/src/SMAPI.Toolkit/ModToolkit.cs @@ -65,7 +65,7 @@ namespace StardewModdingAPI.Toolkit /// The file path for the SMAPI metadata file. public ModDatabase GetModDatabase(string metadataPath) { - MetadataModel metadata = JsonConvert.DeserializeObject(File.ReadAllText(metadataPath)); + MetadataModel metadata = JsonConvert.DeserializeObject(File.ReadAllText(metadataPath)) ?? new MetadataModel(); ModDataRecord[] records = metadata.ModData.Select(pair => new ModDataRecord(pair.Key, pair.Value)).ToArray(); return new ModDatabase(records, this.GetUpdateUrl); } diff --git a/src/SMAPI.Toolkit/Serialization/Converters/SemanticVersionConverter.cs b/src/SMAPI.Toolkit/Serialization/Converters/SemanticVersionConverter.cs index c32c3185..913d54e0 100644 --- a/src/SMAPI.Toolkit/Serialization/Converters/SemanticVersionConverter.cs +++ b/src/SMAPI.Toolkit/Serialization/Converters/SemanticVersionConverter.cs @@ -48,7 +48,12 @@ namespace StardewModdingAPI.Toolkit.Serialization.Converters return this.ReadObject(JObject.Load(reader)); case JsonToken.String: - return this.ReadString(JToken.Load(reader).Value(), path); + { + string? value = JToken.Load(reader).Value(); + return value is not null + ? this.ReadString(value, path) + : null; + } default: throw new SParseException($"Can't parse {nameof(ISemanticVersion)} from {reader.TokenType} node (path: {reader.Path})."); diff --git a/src/SMAPI.Toolkit/Serialization/Converters/SimpleReadOnlyConverter.cs b/src/SMAPI.Toolkit/Serialization/Converters/SimpleReadOnlyConverter.cs index 1c59f5e7..cdf2ed77 100644 --- a/src/SMAPI.Toolkit/Serialization/Converters/SimpleReadOnlyConverter.cs +++ b/src/SMAPI.Toolkit/Serialization/Converters/SimpleReadOnlyConverter.cs @@ -42,7 +42,12 @@ namespace StardewModdingAPI.Toolkit.Serialization.Converters return this.ReadObject(JObject.Load(reader), path); case JsonToken.String: - return this.ReadString(JToken.Load(reader).Value(), path); + { + string? value = JToken.Load(reader).Value(); + return value is not null + ? this.ReadString(value, path) + : null; + } default: throw new SParseException($"Can't parse {typeof(T).Name} from {reader.TokenType} node (path: {reader.Path})."); -- cgit