164 lines
No EOL
6.8 KiB
C#
164 lines
No EOL
6.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using PhoenixLib.Logging;
|
|
using YamlDotNet.Core;
|
|
using YamlDotNet.Core.Events;
|
|
using YamlDotNet.Serialization;
|
|
using YamlDotNet.Serialization.NamingConventions;
|
|
|
|
namespace PhoenixLib.Configuration
|
|
{
|
|
public class YamlNullableEnumTypeConverter : IYamlTypeConverter
|
|
{
|
|
public bool Accepts(Type type) => Nullable.GetUnderlyingType(type)?.IsEnum ?? false;
|
|
|
|
public object ReadYaml(IParser parser, Type type)
|
|
{
|
|
type = Nullable.GetUnderlyingType(type) ?? throw new ArgumentException("Expected nullable enum type for ReadYaml");
|
|
Scalar scalar = parser.Consume<Scalar>();
|
|
|
|
if (string.IsNullOrWhiteSpace(scalar.Value))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
try
|
|
{
|
|
return Enum.Parse(type, scalar.Value);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new Exception($"Invalid value: \"{scalar.Value}\" for {type.Name}", ex);
|
|
}
|
|
}
|
|
|
|
public void WriteYaml(IEmitter emitter, object value, Type type)
|
|
{
|
|
type = Nullable.GetUnderlyingType(type) ?? throw new ArgumentException("Expected nullable enum type for WriteYaml");
|
|
|
|
if (value == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
string? toWrite = Enum.GetName(type, value) ?? throw new InvalidOperationException($"Invalid value {value} for enum: {type}");
|
|
emitter.Emit(new Scalar(null, null, toWrite, ScalarStyle.Any, true, false));
|
|
}
|
|
}
|
|
|
|
public static class DependencyInjectionExtensions
|
|
{
|
|
public static void AddYamlConfigurationHelper(this IServiceCollection services,
|
|
Action<ConfigurationHelperConfig> configurationAction = null)
|
|
{
|
|
var config = new ConfigurationHelperConfig();
|
|
|
|
configurationAction?.Invoke(config);
|
|
|
|
services.AddSingleton(UnderscoredNamingConvention.Instance);
|
|
services.AddSingleton(s =>
|
|
new SerializerBuilder().WithNamingConvention(s.GetRequiredService<INamingConvention>()).WithTypeConverter(new YamlNullableEnumTypeConverter()).Build());
|
|
services.AddSingleton(s =>
|
|
new DeserializerBuilder().WithNamingConvention(s.GetRequiredService<INamingConvention>()).WithTypeConverter(new YamlNullableEnumTypeConverter()).Build());
|
|
services.AddTransient<IConfigurationHelper, YamlConfigurationHelper>();
|
|
services.AddSingleton<IConfigurationPathProvider>(new ConfigurationPathProvider(config.ConfigurationDirectory));
|
|
}
|
|
|
|
/// <summary>
|
|
/// The file will be named with underscore case with .yaml as its file extension
|
|
/// </summary>
|
|
/// <param name="services"></param>
|
|
/// <param name="path"></param>
|
|
/// <typeparam name="T"></typeparam>
|
|
public static void AddConfigurationsFromDirectory<T>(this IServiceCollection services, string path)
|
|
where T : class, new()
|
|
{
|
|
services.AddSingleton<IEnumerable<T>>(s =>
|
|
s.GetRequiredService<IConfigurationHelper>()
|
|
.GetConfigurations<T>(s.GetService<IConfigurationPathProvider>().GetConfigurationPath(path)));
|
|
}
|
|
|
|
/// <summary>
|
|
/// The file will be named with underscore case with .yaml as its file extension
|
|
/// </summary>
|
|
/// <param name="services"></param>
|
|
/// <param name="configName"></param>
|
|
/// <typeparam name="T"></typeparam>
|
|
public static void AddFileConfiguration<T>(this IServiceCollection services, string configName)
|
|
where T : class, new()
|
|
{
|
|
services.AddSingleton(s =>
|
|
s.GetRequiredService<IConfigurationHelper>().Load<T>(
|
|
s.GetService<IConfigurationPathProvider>().GetConfigurationPath(configName.ToUnderscoreCase() + ".yaml"), true));
|
|
}
|
|
|
|
/// <summary>
|
|
/// The file will be named with underscore case with .yaml as its file extension
|
|
/// </summary>
|
|
/// <param name="services"></param>
|
|
/// <param name="configName"></param>
|
|
/// <typeparam name="T"></typeparam>
|
|
public static void AddMultipleConfigurationOneFile<T>(this IServiceCollection services, string configName)
|
|
where T : class, new()
|
|
{
|
|
services.AddSingleton<IEnumerable<T>>(s =>
|
|
s.GetRequiredService<IConfigurationHelper>().Load<List<T>>(
|
|
s.GetService<IConfigurationPathProvider>().GetConfigurationPath(configName.ToUnderscoreCase() + ".yaml"), true));
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// The file will be named with underscore case with .yaml as its file extension
|
|
/// </summary>
|
|
/// <param name="services"></param>
|
|
/// <typeparam name="T"></typeparam>
|
|
public static void AddFileConfiguration<T>(this IServiceCollection services) where T : class, new()
|
|
{
|
|
services.AddSingleton(s =>
|
|
s.GetRequiredService<IConfigurationHelper>().Load<T>(
|
|
s.GetService<IConfigurationPathProvider>().GetConfigurationPath(typeof(T).Name.ToUnderscoreCase() + ".yaml"),
|
|
true));
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// The file will be named with underscore case with .yaml as its file extension
|
|
/// </summary>
|
|
/// <param name="services"></param>
|
|
/// <param name="defaultConfig">Default value in case the file does not exist</param>
|
|
/// <typeparam name="T"></typeparam>
|
|
public static void AddFileConfiguration<T>(this IServiceCollection services, T defaultConfig)
|
|
where T : class, new()
|
|
{
|
|
services.AddSingleton(s =>
|
|
s.GetRequiredService<IConfigurationHelper>().Load(
|
|
s.GetService<IConfigurationPathProvider>().GetConfigurationPath(typeof(T).Name.ToUnderscoreCase() + ".yaml"),
|
|
defaultConfig));
|
|
}
|
|
|
|
private static List<T> GetConfigurations<T>(this IConfigurationHelper helper, string path)
|
|
where T : class, new()
|
|
{
|
|
var configs = new List<T>();
|
|
if (!Directory.Exists(path))
|
|
{
|
|
Directory.CreateDirectory(path);
|
|
return configs;
|
|
}
|
|
|
|
foreach (string file in Directory.GetFiles(path, "*.yaml", SearchOption.AllDirectories).Concat(Directory.GetFiles(path, "*.yml", SearchOption.AllDirectories)))
|
|
{
|
|
var fileInfo = new FileInfo(file);
|
|
T config = helper.Load<T>(file);
|
|
configs.Add(config);
|
|
|
|
Log.Info($"[CONFIGURATION_HELPER] Loading configuration from {fileInfo.Name} as {typeof(T).Name}");
|
|
}
|
|
|
|
return configs;
|
|
}
|
|
}
|
|
} |