using System.Text.Encodings.Web; using System.Text.Json; using System.Text.Json.Serialization; using SPTarkov.Common.Annotations; using SPTarkov.Server.Core.Models; using SPTarkov.Server.Core.Models.Eft.Common.Tables; using SPTarkov.Server.Core.Models.Eft.Ws; using SPTarkov.Server.Core.Models.Enums; using SPTarkov.Server.Core.Models.Logging; using SPTarkov.Server.Core.Models.Spt.Dialog; using SPTarkov.Server.Core.Utils.Json.Converters; using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel; namespace SPTarkov.Server.Core.Utils; [Injectable(InjectionType.Singleton)] public class JsonUtil { private static JsonSerializerOptions jsonSerializerOptionsNoIndent = new() { WriteIndented = false, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, UnmappedMemberHandling = JsonUnmappedMemberHandling.Disallow, Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, Converters = { new BaseSptLoggerReferenceConverter(), new ListOrTConverterFactory(), new DictionaryOrListConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftEnumConverter(), new EftListEnumConverter(), new EftListEnumConverter(), new EftListEnumConverter(), new BaseInteractionRequestDataConverter() } }; protected static JsonSerializerOptions jsonSerializerOptionsIndented = new(jsonSerializerOptionsNoIndent) { WriteIndented = true }; /// /// Convert JSON into an object /// /// The type of the object to deserialize to /// The JSON string to deserialize /// Deserialized object or null public T? Deserialize(string? json) { return string.IsNullOrEmpty(json) ? default : JsonSerializer.Deserialize(json, jsonSerializerOptionsNoIndent); } /// /// Convert JSON into an object /// /// The JSON string to deserialize /// The type of the object to deserialize to /// public object? Deserialize(string? json, Type type) { return string.IsNullOrEmpty(json) ? null : JsonSerializer.Deserialize(json, type, jsonSerializerOptionsNoIndent); } /// /// Convert JSON into an object from a file /// /// The JSON File to read /// T public T? DeserializeFromFile(string file) { if (!File.Exists(file)) { return default; } using (FileStream fs = new(file, FileMode.Open, FileAccess.Read)) { return JsonSerializer.Deserialize(fs, jsonSerializerOptionsNoIndent); } } /// /// Convert JSON into an object from a file /// /// The JSON File to read /// The type of the object to deserialize to /// object public object? DeserializeFromFile(string file, Type type) { if (!File.Exists(file)) { return default; } using (FileStream fs = new(file, FileMode.Open, FileAccess.Read)) { return JsonSerializer.Deserialize(fs, type, jsonSerializerOptionsNoIndent); } } /// /// Convert JSON into an object from a FileStream /// /// The file stream to deserialize /// The type of the object to deserialize to /// public object? DeserializeFromFileStream(FileStream fs, Type type) { return JsonSerializer.Deserialize(fs, type, jsonSerializerOptionsNoIndent); } /// /// Convert an object into JSON /// /// Type of the object being serialised /// Object to serialise /// Should JSON be indented /// Serialised object as JSON, or null public string? Serialize(T? obj, bool indented = false) { return obj == null ? null : JsonSerializer.Serialize(obj, indented ? jsonSerializerOptionsIndented : jsonSerializerOptionsNoIndent); } /// /// Convert an object into JSON /// /// Object to serialise /// Type of object being serialized /// Should JSON be indented /// Serialized text public string? Serialize(object? obj, Type type, bool indented = false) { return obj == null ? null : JsonSerializer.Serialize(obj, type, indented ? jsonSerializerOptionsIndented : jsonSerializerOptionsNoIndent); } protected static void AddConverter(JsonSerializerOptions options, JsonConverter newConverter) { if (options.Converters.All(c => c.GetType() != newConverter.GetType())) { // Doesn't exist, add options.Converters.Add(newConverter); } } /// /// Register a Json converter to serializer options /// /// The converter to add public void RegisterJsonConverter(JsonConverter converter) { // This might actually be a terrible thing to do, but it is what it is for now if (!jsonSerializerOptionsNoIndent.IsReadOnly) { AddConverter(jsonSerializerOptionsNoIndent, converter); } else { var noIndentConverter = new JsonSerializerOptions(jsonSerializerOptionsNoIndent); AddConverter(noIndentConverter, converter); jsonSerializerOptionsNoIndent = noIndentConverter; } if (!jsonSerializerOptionsIndented.IsReadOnly) { AddConverter(jsonSerializerOptionsIndented, converter); } else { var indentedConverter = new JsonSerializerOptions(jsonSerializerOptionsIndented); AddConverter(indentedConverter, converter); jsonSerializerOptionsIndented = indentedConverter; } } }