// Copyright Epic Games, Inc. All Rights Reserved.
using System.Text.Json;
using System.Text.Json.Serialization;
using EpicGames.Core;
namespace HordeServer.Configuration
{
///
/// Special resource type in configuration files which stores data from an external source
///
[JsonSchemaString]
[JsonConverter(typeof(ConfigResourceSerializer))]
public sealed class ConfigResource
{
///
/// Path to the resource
///
[ConfigRelativePath]
public string? Path { get; set; }
///
/// Data for the resource. This will be stored externally to the config data.
///
public ReadOnlyMemory Data { get; set; } = ReadOnlyMemory.Empty;
}
///
/// Serializer for objects
///
public class ConfigResourceSerializer : JsonConverter
{
readonly bool _withData;
///
/// Explicit default constructor (cannot use default argument with JsonSerializer)
///
public ConfigResourceSerializer()
: this(true) { }
///
/// Constructor
///
/// Whether to include data in serialized resource objects
public ConfigResourceSerializer(bool withData)
=> _withData = withData;
///
public override ConfigResource Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
ConfigResource resource = new ConfigResource();
if (reader.TokenType == JsonTokenType.String)
{
resource.Path = reader.GetString();
}
else if (reader.TokenType == JsonTokenType.StartObject)
{
while (reader.Read() && reader.TokenType != JsonTokenType.EndObject)
{
if (reader.TokenType == JsonTokenType.PropertyName)
{
if (reader.ValueTextEquals(nameof(ConfigResource.Path)))
{
reader.Read();
resource.Path = reader.GetString();
}
else if (reader.ValueTextEquals(nameof(ConfigResource.Data)) && _withData)
{
reader.Read();
resource.Data = reader.GetBytesFromBase64();
}
}
}
}
else
{
throw new InvalidOperationException();
}
return resource;
}
///
public override void Write(Utf8JsonWriter writer, ConfigResource resource, JsonSerializerOptions options)
{
if (resource.Data.Length == 0 || !_withData)
{
writer.WriteStringValue(resource.Path);
}
else
{
writer.WriteStartObject();
writer.WriteString(nameof(ConfigResource.Path), resource.Path);
writer.WriteBase64String(nameof(ConfigResource.Data), resource.Data.Span);
writer.WriteEndObject();
}
}
}
}