diff --git a/DisCatSharp.Configuration/ConfigurationExtensions.cs b/DisCatSharp.Configuration/ConfigurationExtensions.cs
index 76e6d9633..931e424e8 100644
--- a/DisCatSharp.Configuration/ConfigurationExtensions.cs
+++ b/DisCatSharp.Configuration/ConfigurationExtensions.cs
@@ -1,227 +1,270 @@
// This file is part of the DisCatSharp project, a fork of DSharpPlus.
//
// Copyright (c) 2021 AITSYS
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
using System;
using System.Collections;
using System.Linq;
using System.Reflection;
using DisCatSharp.Configuration.Models;
using Microsoft.Extensions.Configuration;
namespace DisCatSharp.Configuration
{
internal static class ConfigurationExtensions
{
private const string FactoryErrorMessage = "Require a function which provides a default entity to work with";
public const string DefaultRootLib = "DisCatSharp";
+ private const string ConfigSuffix = "Configuration";
+
///
/// Easily piece together paths that will work within
///
/// (not used - only for adding context based functionality)
/// The strings to piece together
/// Strings joined together via ':'
public static string ConfigPath(this IConfiguration config, params string[] values) => string.Join(":", values);
///
/// Skims over the configuration section and only overrides values that are explicitly defined within the config
///
/// Instance of config
/// Section which contains values for
private static void HydrateInstance(ref object config, ConfigSection section)
{
PropertyInfo[] props = config.GetType().GetProperties();
foreach (var prop in props)
{
// Must have a set method for this to work, otherwise continue on
if (prop.SetMethod == null)
continue;
string entry = section.GetValue(prop.Name);
object? value = null;
if (typeof(string) == prop.PropertyType)
{
// We do NOT want to override value if nothing was provided
if(!string.IsNullOrEmpty(entry))
prop.SetValue(config, entry);
continue;
}
// We need to address collections a bit differently
// They can come in the form of "root:section:name" with a string representation OR
// "root:section:name:0" <--- this is not detectable when checking the above path
if (typeof(IEnumerable).IsAssignableFrom(prop.PropertyType))
{
if (string.IsNullOrEmpty(section.GetValue(prop.Name)))
value = section.Config
.GetSection(section.GetPath(prop.Name)).Get(prop.PropertyType);
else
value = Newtonsoft.Json.JsonConvert.DeserializeObject(entry, prop.PropertyType);
if (value == null)
continue;
prop.SetValue(config, value);
}
// From this point onward we require the 'entry' value to have something useful
if (string.IsNullOrEmpty(entry))
continue;
try
{
// Primitive types are simple to convert
if (prop.PropertyType.IsPrimitive)
value = Convert.ChangeType(entry, prop.PropertyType);
else
{
// The following types require a different approach
if (prop.PropertyType.IsEnum)
value = Enum.Parse(prop.PropertyType, entry);
else if (typeof(TimeSpan) == prop.PropertyType)
value = TimeSpan.Parse(entry);
else if (typeof(DateTime) == prop.PropertyType)
value = DateTime.Parse(entry);
else if (typeof(DateTimeOffset) == prop.PropertyType)
value = DateTimeOffset.Parse(entry);
}
// Update value within our config instance
prop.SetValue(config, value);
}
catch (Exception ex)
{
Console.Error.WriteLine(
$"Unable to convert value of '{entry}' to type '{prop.PropertyType.Name}' for prop '{prop.Name}' in config '{config.GetType().Name}'\n\t\t{ex.Message}");
}
}
}
///
/// Instantiate an entity using then walk through the specified
/// and translate user-defined config values to the instantiated instance from
///
/// Section containing values for targeted config
/// Function which generates a default entity
/// Hydrated instance of an entity which contains user-defined values (if any)
/// When is null
public static object ExtractConfig(this ConfigSection section, Func