// Copyright Epic Games, Inc. All Rights Reserved. using System.Buffers; using System.Text.Json; using System.Text.Json.Nodes; using EpicGames.Core; namespace HordeServer.Utilities { using JsonObject = System.Text.Json.Nodes.JsonObject; /// /// Allows manipulating JSON config files without fully deserializing them /// public class JsonConfigFile { /// /// The root of the config file /// public JsonObject Root { get; } /// /// Constructor /// public JsonConfigFile(JsonObject root) { Root = root; } /// /// Reads a json config file from a file on disk /// public static async Task ReadAsync(FileReference file, CancellationToken cancellationToken = default) { byte[] data = await FileReference.ReadAllBytesAsync(file, cancellationToken); JsonObject? obj = JsonNode.Parse(data, new JsonNodeOptions { PropertyNameCaseInsensitive = true }, new JsonDocumentOptions { AllowTrailingCommas = true, CommentHandling = JsonCommentHandling.Skip }) as JsonObject; return new JsonConfigFile(obj ?? new JsonObject()); } /// /// Writes the config file back out to a file /// public async Task WriteAsync(FileReference file, CancellationToken cancellationToken = default) { ArrayBufferWriter buffer = new ArrayBufferWriter(); using (Utf8JsonWriter writer = new Utf8JsonWriter(buffer, new JsonWriterOptions { Indented = true })) { Root.WriteTo(writer); } await FileReference.WriteAllBytesAsync(file, buffer.WrittenMemory.ToArray(), cancellationToken); } /// /// Adds a node with the given name to an object /// public static T FindOrAddNode(JsonObject obj, string name, Func factory) where T : JsonNode { JsonNode? node = obj[name]; if (node != null) { if (node is T existingTypedNode) { return existingTypedNode; } else { obj.Remove(name); } } T newTypedNode = factory(); obj.Add(name, newTypedNode); return newTypedNode; } /// /// Finds an existing element, or adds a new element to an array, with the given name. /// public static JsonObject FindOrAddElementByKey(JsonArray array, string key, string name) { foreach (JsonNode? element in array) { if (element is JsonObject obj) { JsonNode? node = obj[key]; if (node != null && (string?)node.AsValue() == name) { return obj; } } } JsonObject newObj = new JsonObject(); newObj[key] = name; array.Add(newObj); return newObj; } } }