-
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: specific deserialization errors showing in Playnite logs (#728)
- Loading branch information
1 parent
23ebd04
commit bfc4591
Showing
1 changed file
with
146 additions
and
84 deletions.
There are no files selected for viewing
230 changes: 146 additions & 84 deletions
230
apps/PlayniteWebPlugin/src/Services/ObjectDeserializer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,112 +1,174 @@ | ||
using Playnite.SDK; | ||
using System; | ||
using System.Collections; | ||
using System.Collections.Generic; | ||
using System.Dynamic; | ||
using System.Globalization; | ||
using System.Reflection; | ||
using System.Text; | ||
using System.Text.Json; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace PlayniteWeb.Services | ||
{ | ||
public class PascalCaseJsonConverter : JsonConverter<ExpandoObject> | ||
{ | ||
public override ExpandoObject Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) | ||
public class PascalCaseJsonConverter : JsonConverter<ExpandoObject> | ||
{ | ||
using (JsonDocument doc = JsonDocument.ParseValue(ref reader)) | ||
{ | ||
var jsonObject = doc.RootElement; | ||
if (jsonObject.ValueKind == JsonValueKind.Object) | ||
private dynamic ReadValue(JsonElement valueDoc, JsonSerializerOptions options) | ||
{ | ||
var result = new ExpandoObject() as IDictionary<string, object>; | ||
foreach (var prop in jsonObject.EnumerateObject()) | ||
{ | ||
var name = ConvertToPascalCase(prop.Name); | ||
using (JsonDocument valueDoc = JsonDocument.Parse(prop.Value.GetRawText())) | ||
if (valueDoc.ValueKind == JsonValueKind.Object) | ||
{ | ||
dynamic value = null; | ||
if (valueDoc.RootElement.ValueKind == JsonValueKind.Object) | ||
{ | ||
value = JsonSerializer.Deserialize<ExpandoObject>(prop.Value.GetRawText(), options); | ||
} | ||
else if (valueDoc.RootElement.ValueKind == JsonValueKind.Array) | ||
{ | ||
var list = new List<dynamic>(); | ||
foreach (var valueItem in valueDoc.RootElement.EnumerateArray()) | ||
dynamic value = null; | ||
foreach (var prop in valueDoc.EnumerateObject()) | ||
{ | ||
list.Add(JsonSerializer.Deserialize<ExpandoObject>(valueItem.GetRawText(), options)); | ||
|
||
value[prop.Name] = ReadValue(prop.Value, options); | ||
} | ||
value = list; | ||
} | ||
else if (valueDoc.RootElement.ValueKind == JsonValueKind.String) | ||
{ | ||
value = valueDoc.RootElement.GetString(); | ||
} | ||
else if (valueDoc.RootElement.ValueKind == JsonValueKind.Number) | ||
{ | ||
value = valueDoc.RootElement.GetInt32(); | ||
} | ||
else if (valueDoc.RootElement.ValueKind == JsonValueKind.True || valueDoc.RootElement.ValueKind == JsonValueKind.False) | ||
{ | ||
value = valueDoc.RootElement.GetBoolean(); | ||
} | ||
else | ||
{ | ||
value = valueDoc.RootElement.GetRawText(); | ||
} | ||
return value; | ||
} | ||
else if (valueDoc.ValueKind == JsonValueKind.Array) | ||
{ | ||
var list = new ArrayList(); | ||
foreach (var valueItem in valueDoc.EnumerateArray()) | ||
{ | ||
list.Add(ReadValue(valueItem, options)); | ||
|
||
result[name] = value; | ||
return list; | ||
} | ||
} | ||
else if (valueDoc.ValueKind == JsonValueKind.String) | ||
{ | ||
return valueDoc.GetString(); | ||
} | ||
else if (valueDoc.ValueKind == JsonValueKind.Number) | ||
{ | ||
return valueDoc.GetInt32(); | ||
} | ||
else if (valueDoc.ValueKind == JsonValueKind.True || valueDoc.ValueKind == JsonValueKind.False) | ||
{ | ||
return valueDoc.GetBoolean(); | ||
} | ||
else | ||
{ | ||
return valueDoc.GetRawText(); | ||
} | ||
} | ||
return result as ExpandoObject; | ||
|
||
return null; | ||
} | ||
|
||
return null; | ||
} | ||
} | ||
public override ExpandoObject Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) | ||
{ | ||
using (JsonDocument doc = JsonDocument.ParseValue(ref reader)) | ||
{ | ||
var jsonObject = doc.RootElement; | ||
if (jsonObject.ValueKind == JsonValueKind.Object) | ||
{ | ||
var result = new ExpandoObject() as IDictionary<string, object>; | ||
foreach (var prop in jsonObject.EnumerateObject()) | ||
{ | ||
var name = ConvertToPascalCase(prop.Name); | ||
using (JsonDocument valueDoc = JsonDocument.Parse(prop.Value.GetRawText())) | ||
{ | ||
dynamic value = null; | ||
if (valueDoc.RootElement.ValueKind == JsonValueKind.Object) | ||
{ | ||
value = JsonSerializer.Deserialize<ExpandoObject>(prop.Value.GetRawText(), options); | ||
} | ||
else if (valueDoc.RootElement.ValueKind == JsonValueKind.Array) | ||
{ | ||
var list = new ArrayList(); | ||
foreach (var valueItem in valueDoc.RootElement.EnumerateArray()) | ||
{ | ||
if (valueItem.ValueKind == JsonValueKind.Object) | ||
{ | ||
list.Add(JsonSerializer.Deserialize<ExpandoObject>(valueItem.GetRawText(), options)); | ||
} | ||
else if (valueItem.ValueKind == JsonValueKind.Array) | ||
{ | ||
list.Add(JsonSerializer.Deserialize<ExpandoObject>(valueItem.GetRawText(), options)); | ||
} | ||
else if (valueItem.ValueKind == JsonValueKind.String) | ||
{ | ||
list.Add(valueItem.GetString()); | ||
} | ||
else if (valueItem.ValueKind == JsonValueKind.Number) | ||
{ | ||
list.Add(valueItem.GetInt32()); | ||
} | ||
else if (valueItem.ValueKind == JsonValueKind.True || valueItem.ValueKind == JsonValueKind.False) | ||
{ | ||
list.Add(valueItem.GetBoolean()); | ||
} | ||
else | ||
{ | ||
list.Add(valueItem.GetRawText()); | ||
} | ||
value = list; | ||
} | ||
} | ||
else if (valueDoc.RootElement.ValueKind == JsonValueKind.String) | ||
{ | ||
value = valueDoc.RootElement.GetString(); | ||
} | ||
else if (valueDoc.RootElement.ValueKind == JsonValueKind.Number) | ||
{ | ||
value = valueDoc.RootElement.GetInt32(); | ||
} | ||
else if (valueDoc.RootElement.ValueKind == JsonValueKind.True || valueDoc.RootElement.ValueKind == JsonValueKind.False) | ||
{ | ||
value = valueDoc.RootElement.GetBoolean(); | ||
} | ||
else | ||
{ | ||
value = valueDoc.RootElement.GetRawText(); | ||
} | ||
|
||
public override void Write(Utf8JsonWriter writer, ExpandoObject value, JsonSerializerOptions options) | ||
{ | ||
JsonSerializer.Serialize(writer, value, options); | ||
} | ||
result[name] = value; | ||
} | ||
} | ||
return result as ExpandoObject; | ||
} | ||
|
||
private string ConvertToPascalCase(string name) | ||
{ | ||
if (string.IsNullOrEmpty(name)) | ||
return name; | ||
return null; | ||
} | ||
} | ||
|
||
return char.ToUpper(name[0], CultureInfo.InvariantCulture) + name.Substring(1); | ||
} | ||
} | ||
public override void Write(Utf8JsonWriter writer, ExpandoObject value, JsonSerializerOptions options) | ||
{ | ||
JsonSerializer.Serialize(writer, value, options); | ||
} | ||
|
||
public class ObjectDeserializer : IDeserializeObjects | ||
{ | ||
private string ConvertToPascalCase(string name) | ||
{ | ||
if (string.IsNullOrEmpty(name)) | ||
return name; | ||
|
||
return char.ToUpper(name[0], CultureInfo.InvariantCulture) + name.Substring(1); | ||
} | ||
} | ||
|
||
public ExpandoObject Deserialize(string data) | ||
public class ObjectDeserializer : IDeserializeObjects | ||
{ | ||
try | ||
{ | ||
var options = new JsonSerializerOptions | ||
|
||
public ExpandoObject Deserialize(string data) | ||
{ | ||
PropertyNameCaseInsensitive = true, // Allows case-insensitive matches | ||
Converters = { new PascalCaseJsonConverter() } // Apply custom converter | ||
}; | ||
return JsonSerializer.Deserialize<ExpandoObject>(data, options); | ||
} | ||
catch (NotSupportedException nse) | ||
{ | ||
// Specific catch for NotSupportedException to handle serialization issues more specifically | ||
LogManager.GetLogger().Error($"Unsupported serialization attempt for {data.GetType()}: {nse.Message}"); | ||
throw; | ||
} | ||
catch (Exception error) | ||
{ | ||
// General exception handling | ||
LogManager.GetLogger().Error($"Error serializing object: {error}"); | ||
throw; | ||
} | ||
try | ||
{ | ||
var options = new JsonSerializerOptions | ||
{ | ||
PropertyNameCaseInsensitive = true, // Allows case-insensitive matches | ||
Converters = { new PascalCaseJsonConverter() } // Apply custom converter | ||
}; | ||
return JsonSerializer.Deserialize<ExpandoObject>(data, options); | ||
} | ||
catch (NotSupportedException nse) | ||
{ | ||
// Specific catch for NotSupportedException to handle serialization issues more specifically | ||
LogManager.GetLogger().Error($"Unsupported serialization attempt for {data.GetType()}: {nse.Message}"); | ||
throw; | ||
} | ||
catch (Exception error) | ||
{ | ||
// General exception handling | ||
LogManager.GetLogger().Error($"Error serializing object: {error}"); | ||
throw; | ||
} | ||
} | ||
} | ||
} | ||
} |