using System.Collections.Generic; using System.IO; using System.IO.Abstractions; using System.Linq; using FluentValidation; using TrashLib.Config; using TrashLib.Config.Services; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Serialization; namespace Trash.Config; public class ConfigurationLoader : IConfigurationLoader where T : IServiceConfiguration { private readonly IConfigurationProvider _configProvider; private readonly IDeserializer _deserializer; private readonly IFileSystem _fileSystem; private readonly IValidator _validator; public ConfigurationLoader( IConfigurationProvider configProvider, IFileSystem fileSystem, IYamlSerializerFactory yamlFactory, IValidator validator) { _configProvider = configProvider; _fileSystem = fileSystem; _validator = validator; _deserializer = yamlFactory.CreateDeserializer(); } public IEnumerable Load(string propertyName, string configSection) { using var stream = _fileSystem.File.OpenText(propertyName); return LoadFromStream(stream, configSection); } public IEnumerable LoadFromStream(TextReader stream, string configSection) { var parser = new Parser(stream); parser.Consume(); parser.Consume(); parser.Consume(); var validConfigs = new List(); while (parser.TryConsume(out var key)) { if (key.Value != configSection) { parser.SkipThisAndNestedEvents(); continue; } var configs = _deserializer.Deserialize?>(parser); if (configs == null) { parser.SkipThisAndNestedEvents(); continue; } ValidateConfigs(configSection, configs, validConfigs); parser.SkipThisAndNestedEvents(); } if (validConfigs.Count == 0) { throw new ConfigurationException(configSection, typeof(T), "There are no configured instances defined"); } return validConfigs; } private void ValidateConfigs(string configSection, IEnumerable configs, ICollection validConfigs) { foreach (var config in configs) { var result = _validator.Validate(config); if (result is {IsValid: false}) { throw new ConfigurationException(configSection, typeof(T), result.Errors); } validConfigs.Add(config); } } public IEnumerable LoadMany(IEnumerable configFiles, string configSection) { foreach (var config in configFiles.SelectMany(file => Load(file, configSection))) { _configProvider.ActiveConfiguration = config; yield return config; } } }