Skip to content

Commit

Permalink
update all json processing to use STJ instead of Newtonsoft
Browse files Browse the repository at this point in the history
  • Loading branch information
floribe2000 committed Oct 2, 2023
1 parent 29f4eb5 commit 28e54b2
Show file tree
Hide file tree
Showing 26 changed files with 158 additions and 167 deletions.
29 changes: 15 additions & 14 deletions WoWsShipBuilder.Common/Features/Builds/Build.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System.Globalization;
using System.IO.Compression;
using System.Security.Cryptography;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using WoWsShipBuilder.DataStructures;
using WoWsShipBuilder.Infrastructure.ApplicationData;
using WoWsShipBuilder.Infrastructure.GameData;
using WoWsShipBuilder.Infrastructure.Utility;

Expand All @@ -20,15 +22,15 @@ public class Build
[JsonConstructor]
private Build(string buildName, string shipIndex, Nation nation, List<string> modules, List<string> upgrades, List<string> consumables, string captain, List<int> skills, List<string> signals, int buildVersion = CurrentBuildVersion)
{
BuildName = buildName;
ShipIndex = shipIndex;
BuildName = buildName ?? throw new ArgumentNullException(nameof(buildName));
ShipIndex = shipIndex ?? throw new ArgumentNullException(nameof(shipIndex));
Nation = nation;
Modules = modules;
Upgrades = upgrades;
Captain = captain;
Skills = skills;
Signals = signals;
Consumables = consumables;
Modules = modules ?? throw new ArgumentNullException(nameof(modules));
Upgrades = upgrades ?? throw new ArgumentNullException(nameof(upgrades));
Captain = captain ?? throw new ArgumentNullException(nameof(captain));
Skills = skills ?? throw new ArgumentNullException(nameof(skills));
Signals = signals ?? throw new ArgumentNullException(nameof(signals));
Consumables = consumables ?? throw new ArgumentNullException(nameof(consumables));
BuildVersion = buildVersion;

Hash = CreateHash(this);
Expand All @@ -39,7 +41,6 @@ public Build(string buildName, string shipIndex, Nation nation, List<string> mod
{
}

[JsonProperty(Required = Required.Always)]
public string BuildName { get; }

public string ShipIndex { get; }
Expand Down Expand Up @@ -93,11 +94,11 @@ public static Build CreateBuildFromString(string buildString, ILogger? logger =
using var gzip = new DeflateStream(inputStream, CompressionMode.Decompress);
using var reader = new StreamReader(gzip, System.Text.Encoding.UTF8);
string buildJson = reader.ReadToEnd();
build = JsonConvert.DeserializeObject<Build>(buildJson) ?? throw new InvalidOperationException("Failed to deserialize build object from string");
build = JsonSerializer.Deserialize<Build>(buildJson, AppConstants.JsonSerializerOptions) ?? throw new InvalidOperationException("Failed to deserialize build object from string");
}
else if (buildString.StartsWith('{') && buildString.EndsWith('}'))
{
build = JsonConvert.DeserializeObject<Build>(buildString)!;
build = JsonSerializer.Deserialize<Build>(buildString, AppConstants.JsonSerializerOptions)!;
}
else
{
Expand Down Expand Up @@ -167,7 +168,7 @@ private static Build UpgradeBuild(Build oldBuild, ILogger logger)

private static string CreateHash(Build build)
{
string buildString = JsonConvert.SerializeObject(build);
string buildString = JsonSerializer.Serialize(build, AppConstants.JsonSerializerOptions);
byte[] textData = System.Text.Encoding.UTF8.GetBytes(buildString);
byte[] hash = SHA256.HashData(textData);
return BitConverter.ToString(hash).Replace("-", string.Empty);
Expand All @@ -192,7 +193,7 @@ public override bool Equals(object? obj)

public string CreateStringFromBuild()
{
string buildString = JsonConvert.SerializeObject(this);
string buildString = JsonSerializer.Serialize(this, AppConstants.JsonSerializerOptions);
using var output = new MemoryStream();
using (var gzip = new DeflateStream(output, CompressionLevel.Optimal))
{
Expand Down
2 changes: 1 addition & 1 deletion WoWsShipBuilder.Common/Features/Settings/AppSettings.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Newtonsoft.Json;
using System.Text.Json.Serialization;
using WoWsShipBuilder.Infrastructure.ApplicationData;
using WoWsShipBuilder.Infrastructure.DataTransfer;
using ServerType = WoWsShipBuilder.Infrastructure.GameData.ServerType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
@using DynamicData
@using Microsoft.AspNetCore.WebUtilities
@using Microsoft.Extensions.Options
@using Newtonsoft.Json
@using WoWsShipBuilder.Features.Builds.Components
@using WoWsShipBuilder.Features.Builds
@using WoWsShipBuilder.Features.LinkShortening
Expand All @@ -17,6 +16,7 @@
@using WoWsShipBuilder.Infrastructure.Metrics
@using WoWsShipBuilder.Infrastructure.Utility
@using System.Collections.Immutable
@using System.Text.Json

@implements IAsyncDisposable
@inject ILocalizer Localizer
Expand All @@ -35,7 +35,7 @@
<MudItem xs="12">
<MudStack Row>
<MudTextField Immediate T="string" Label="@Localizer.GetAppLocalization(nameof(Translation.BuildStringInputDialog_EnterBuildStringOrLink)).Localization" @bind-Value="buildString"/>
<MudButton Disabled="@string.IsNullOrWhiteSpace(buildString)" Variant="Variant.Filled" Color="Color.Primary" DisableElevation="true" OnClick="ImportFromString">
<MudButton Disabled="@string.IsNullOrWhiteSpace(buildString)" Variant="Variant.Filled" Color="Color.Primary" DisableElevation="true" OnClick="@ImportFromString">
@Localizer.GetAppLocalization(nameof(Translation.WebApp_LoadBuild)).Localization
</MudButton>
<MudFileUpload T="IBrowserFile" FilesChanged="@FileSelected" Style="margin-top: 0;" Class="file-upload-full-height" Accept=".png">
Expand Down Expand Up @@ -524,7 +524,7 @@

try
{
var build = buildString.StartsWith('{') ? JsonConvert.DeserializeObject<Build>(buildString)! : Build.CreateBuildFromString(buildString);
var build = buildString.StartsWith('{') ? JsonSerializer.Deserialize<Build>(buildString, AppConstants.JsonSerializerOptions)! : Build.CreateBuildFromString(buildString);
AddSavedBuild(Build.UpgradeBuild(build));
buildString = string.Empty;
StateHasChanged();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Globalization;
using System.Collections.Immutable;
using System.Text.Json;
using System.Text.Json.Serialization;
using WoWsShipBuilder.Infrastructure.DataTransfer;

namespace WoWsShipBuilder.Infrastructure.ApplicationData;
Expand All @@ -15,40 +17,26 @@ public static class AppConstants

public const string BuildCuratorRoleName = "build-curator";

// Workaround for webworkers
static AppConstants()
{
try
{
DefaultCultureDetails = new(new("en-GB"), "en");
SupportedLanguages = new List<CultureDetails>
{
DefaultCultureDetails,
new(new("zh-CN"), "zh"),
new(new("zh-TW"), "zh_tw"),
new(new("nl-NL"), "nl"),
new(new("fr-FR"), "fr"),
new(new("de-DE"), "de"),
new(new("hu-HU"), "en"),
new(new("it-IT"), "it"),
new(new("ja-JP"), "ja"),
new(new("pt-BR"), "pt_br"),
new(new("ru-RU"), "ru"),
new(new("es-ES"), "es"),
new(new("tr-TR"), "tr"),
};
}
catch (Exception)
{
DefaultCultureDetails = new(CultureInfo.InvariantCulture, "en");
SupportedLanguages = new List<CultureDetails>
{
DefaultCultureDetails,
};
}
}
public static CultureDetails DefaultCultureDetails { get; } = new(new("en-GB"), "en");

public static CultureDetails DefaultCultureDetails { get; }
public static IEnumerable<CultureDetails> SupportedLanguages { get; } = ImmutableArray.Create(
DefaultCultureDetails,
new(new("zh-CN"), "zh"),
new(new("zh-TW"), "zh_tw"),
new(new("nl-NL"), "nl"),
new(new("fr-FR"), "fr"),
new(new("de-DE"), "de"),
new(new("hu-HU"), "en"),
new(new("it-IT"), "it"),
new(new("ja-JP"), "ja"),
new(new("pt-BR"), "pt_br"),
new(new("ru-RU"), "ru"),
new(new("es-ES"), "es"),
new(new("tr-TR"), "tr"));

public static IEnumerable<CultureDetails> SupportedLanguages { get; }
public static JsonSerializerOptions JsonSerializerOptions { get; } = new()
{
PropertyNameCaseInsensitive = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
};
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System.Collections.Immutable;
using Newtonsoft.Json;
using System.Text.Json;
using WoWsShipBuilder.DataStructures;
using WoWsShipBuilder.DataStructures.Aircraft;
using WoWsShipBuilder.DataStructures.Captain;
Expand Down Expand Up @@ -39,7 +39,7 @@ public static async Task AddToCache(string fileName, string category, string con
_ => throw new InvalidOperationException(),
};

object? jsonObject = JsonConvert.DeserializeObject(content, type);
object? jsonObject = JsonSerializer.Deserialize(content, type, AppConstants.JsonSerializerOptions);

await Semaphore.WaitAsync();
switch (category.ToLowerInvariant())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
using System.Globalization;
using System.Text.Json.Serialization;
using WoWsShipBuilder.Infrastructure.Utility;

namespace WoWsShipBuilder.Infrastructure.DataTransfer;

public sealed record CultureDetails(CultureInfo CultureInfo, string LocalizationFileName);
public sealed record CultureDetails(
[property: JsonConverter(typeof(CultureInfoConverter))]
CultureInfo CultureInfo,
string LocalizationFileName);
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace WoWsShipBuilder.Infrastructure.Utility;

public sealed class CultureInfoConverter : JsonConverter<CultureInfo>
{
public override CultureInfo? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return CultureInfo.CreateSpecificCulture(reader.GetString()!);
}

public override void Write(Utf8JsonWriter writer, CultureInfo value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.Name);
}
}
2 changes: 1 addition & 1 deletion WoWsShipBuilder.Common/WoWsShipBuilder.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="WoWsShipBuilder.DataStructures" Version="3.1.6" />
<PackageReference Include="WoWsShipBuilder.DataStructures" Version="4.0.0-alpha" />
<PackageReference Include="ReactiveUI" Version="18.4.44" />
</ItemGroup>

Expand Down
6 changes: 3 additions & 3 deletions WoWsShipBuilder.Common/wwwroot/scripts/settingsHelper.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export function getAppSettings() {
return window.localStorage['settings'];
return JSON.parse(window.localStorage['settings']);
}

export function setAppSettings(settings) {
window.localStorage['settings'] = settings;
}
window.localStorage['settings'] = JSON.stringify(settings);
}
9 changes: 5 additions & 4 deletions WoWsShipBuilder.Desktop.Test/DesktopDataServiceTest.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
using System.IO.Abstractions.TestingHelpers;
using System.Text.Json;
using FluentAssertions;
using Newtonsoft.Json;
using WoWsShipBuilder.Desktop.Infrastructure.Data;
using WoWsShipBuilder.Features.Settings;
using WoWsShipBuilder.Infrastructure.ApplicationData;

namespace WoWsShipBuilder.Desktop.Test;

Expand Down Expand Up @@ -34,7 +35,7 @@ public void Store_DirectoryNotExisting_DirectoryCreated()
mockFileSystem.Directory.Exists(settingsDirectory).Should().BeTrue();

var storedFile = mockFileSystem.File.ReadAllText(settingsPath);
var storedSettings = JsonConvert.DeserializeObject<AppSettings>(storedFile);
var storedSettings = JsonSerializer.Deserialize<AppSettings>(storedFile, AppConstants.JsonSerializerOptions);
storedSettings.Should().BeEquivalentTo(testSettings);
}

Expand All @@ -45,7 +46,7 @@ public async Task Store_FileAlreadyExists_FileReplaced()
const string settingsPath = settingsDirectory + @"/settings.json";
const string customDataPath = "1234";
var testSettings = new AppSettings { AutoUpdateEnabled = false, CustomDataPath = customDataPath };
mockFileSystem.AddFile(settingsPath, new(JsonConvert.SerializeObject(testSettings)));
mockFileSystem.AddFile(settingsPath, new(JsonSerializer.Serialize(testSettings, AppConstants.JsonSerializerOptions)));
testSettings.AutoUpdateEnabled = true;

await dataService.StoreAsync(testSettings, settingsPath);
Expand All @@ -54,7 +55,7 @@ public async Task Store_FileAlreadyExists_FileReplaced()
mockFileSystem.Directory.Exists(settingsDirectory).Should().BeTrue();

var storedFile = await mockFileSystem.File.ReadAllTextAsync(settingsPath);
var storedSettings = JsonConvert.DeserializeObject<AppSettings>(storedFile);
var storedSettings = JsonSerializer.Deserialize<AppSettings>(storedFile, AppConstants.JsonSerializerOptions);
storedSettings.Should().BeEquivalentTo(testSettings);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@
@using Avalonia
@using Avalonia.Controls
@using Avalonia.Controls.ApplicationLifetimes
@using Newtonsoft.Json
@using WoWsShipBuilder.Features.Builds
@using WoWsShipBuilder.Infrastructure.ApplicationData
@using WoWsShipBuilder.Infrastructure.Utility
@using Dispatcher = Avalonia.Threading.Dispatcher
@using System.IO.Abstractions
@using System.Net
@using System.IO
@using System.Text.Json
@using Avalonia.Platform.Storage

@implements IDisposable
Expand Down Expand Up @@ -335,7 +335,7 @@
customBuildImagePath = path;
}
}

private async Task ExportSavedBuilds()
{
var mainWindow = (Application.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow!;
Expand All @@ -344,10 +344,9 @@
if (path is not null)
{
var buildStrings = savedBuilds.Select(x => x.CreateShortStringFromBuild()).ToList();
await using (var stream = FileSystem.File.CreateText($"{path}/builds.json"))
await using (var stream = FileSystem.File.Create($"{path}/builds.json"))
{
var serializer = new JsonSerializer();
serializer.Serialize(stream, buildStrings);
await JsonSerializer.SerializeAsync(stream, buildStrings, AppConstants.JsonSerializerOptions);
}
Snackbar.Add("Builds successfully exported.", Severity.Success);
RefreshNotifierService.NotifyRefreshRequested();
Expand All @@ -363,9 +362,9 @@
IEnumerable<string>? buildList;
try
{
buildList = JsonConvert.DeserializeObject<IEnumerable<string>>(buildsString);
buildList = JsonSerializer.Deserialize<IEnumerable<string>>(buildsString, AppConstants.JsonSerializerOptions);
}
catch (JsonReaderException)
catch (JsonException)
{
Snackbar.Add("Corrupted JSON file.", Severity.Error);
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.IO.Abstractions;
using System.IO.Compression;
using System.Net.Http;
using System.Net.Http.Json;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
Expand Down Expand Up @@ -69,7 +70,7 @@ public async Task DownloadImages(IFileSystem fileSystem, string? fileName = null
public async Task<VersionInfo> DownloadVersionInfo(ServerType serverType)
{
string url = @$"{Host}/api/{serverType.StringName()}/VersionInfo.json";
return await GetJsonAsync<VersionInfo>(url) ?? throw new HttpRequestException("Unable to process VersionInfo response from AWS server.");
return await Client.GetFromJsonAsync<VersionInfo>(url, AppConstants.JsonSerializerOptions) ?? throw new HttpRequestException("Unable to process VersionInfo response from AWS server.");
}

public async Task DownloadFiles(ServerType serverType, List<(string, string)> relativeFilePaths, IProgress<int>? downloadProgress = null)
Expand Down
18 changes: 1 addition & 17 deletions WoWsShipBuilder.Desktop/Infrastructure/AwsClient/ClientBase.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
using WoWsShipBuilder.Desktop.Infrastructure.Data;
using WoWsShipBuilder.Infrastructure.ApplicationData;

Expand All @@ -25,21 +23,7 @@ protected ClientBase(IDataService dataService, IAppDataService appDataService)

protected virtual async Task DownloadFileAsync(Uri uri, string fileName)
{
await using Stream stream = await Client.GetStreamAsync(uri);
await using var stream = await Client.GetStreamAsync(uri);
await DataService.StoreAsync(stream, fileName);
}

protected virtual async Task<T?> GetJsonAsync<T>(string url, JsonSerializer? customSerializer = null)
{
await using Stream stream = await Client.GetStreamAsync(url);
return GetJson<T>(stream, customSerializer);
}

internal T? GetJson<T>(Stream stream, JsonSerializer? customSerializer = null)
{
using var streamReader = new StreamReader(stream);
using var jsonReader = new JsonTextReader(streamReader);
JsonSerializer serializer = customSerializer ?? new JsonSerializer();
return serializer.Deserialize<T>(jsonReader);
}
}
Loading

0 comments on commit 28e54b2

Please sign in to comment.