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