// 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;
}
}
}