Reworked the Config system

This commit is contained in:
2024-08-06 19:07:08 +03:00
parent 8366de28cc
commit 721c28c283
28 changed files with 740 additions and 318 deletions

View File

@@ -0,0 +1,93 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace DiscordBotCore.Others.Settings;
public class CustomSettingsDictionary : CustomSettingsDictionaryBase<string, object>
{
private bool _EnableAutoAddOnGetWithDefault;
private CustomSettingsDictionary(string diskLocation, bool enableAutoAddOnGetWithDefault): base(diskLocation)
{
_EnableAutoAddOnGetWithDefault = enableAutoAddOnGetWithDefault;
}
public override async Task SaveToFile()
{
var json = JsonConvert.SerializeObject(_InternalDictionary, Formatting.Indented);
await File.WriteAllTextAsync(_DiskLocation, json);
}
public override T Get<T>(string key, T defaultValue)
{
T value = base.Get(key, defaultValue);
if (_EnableAutoAddOnGetWithDefault && value.Equals(defaultValue))
{
Add(key, defaultValue);
}
return value;
}
public override List<T> GetList<T>(string key, List<T> defaultValue)
{
List<T> result = base.GetList(key, defaultValue);
if (_EnableAutoAddOnGetWithDefault && defaultValue.All(result.Contains))
{
Add(key,defaultValue);
}
return result;
}
public override async Task LoadFromFile()
{
string jsonContent = await File.ReadAllTextAsync(_DiskLocation);
var jObject = JsonConvert.DeserializeObject<JObject>(jsonContent);
_InternalDictionary.Clear();
foreach (var kvp in jObject)
{
AddPairToDictionary(kvp, _InternalDictionary);
}
}
private void AddPairToDictionary(KeyValuePair<string, JToken> kvp, IDictionary<string, object> dict)
{
if (kvp.Value is JObject nestedJObject)
{
dict[kvp.Key] = nestedJObject.ToObject<Dictionary<string, object>>();
foreach (var nestedKvp in nestedJObject)
{
AddPairToDictionary(nestedKvp, dict[kvp.Key] as Dictionary<string, object>);
}
}
else if (kvp.Value is JArray nestedJArray)
{
dict[kvp.Key] = nestedJArray.ToObject<List<object>>();
}
else
{
dict[kvp.Key] = kvp.Value;
}
}
/// <summary>
/// Create a new Settings Dictionary from a file
/// </summary>
/// <param name="baseFile">The file location</param>
/// <param name="enableAutoAddOnGetWithDefault">Set this to true if you want to update the dictionary with default values on get</param>
internal static async Task<CustomSettingsDictionary> CreateFromFile(string baseFile, bool enableAutoAddOnGetWithDefault)
{
var settings = new CustomSettingsDictionary(baseFile, enableAutoAddOnGetWithDefault);
await settings.LoadFromFile();
return settings;
}
}

View File

@@ -0,0 +1,160 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace DiscordBotCore.Others.Settings;
public abstract class CustomSettingsDictionaryBase<TKey,TValue> : ICustomSettingsDictionary<TKey,TValue>
{
protected readonly IDictionary<TKey,TValue> _InternalDictionary = new Dictionary<TKey, TValue>();
protected readonly string _DiskLocation;
protected CustomSettingsDictionaryBase(string diskLocation)
{
this._DiskLocation = diskLocation;
}
public virtual void Add(TKey key, TValue value)
{
if (_InternalDictionary.ContainsKey(key))
return;
if (value is null)
return;
_InternalDictionary.Add(key, value);
}
public virtual void Set(TKey key, TValue value)
{
_InternalDictionary[key] = value;
}
public virtual TValue Get(TKey key)
{
return _InternalDictionary[key];
}
public virtual T Get<T>(TKey key, T defaultValue)
{
if (_InternalDictionary.TryGetValue(key, out var value))
{
return (T)Convert.ChangeType(value, typeof(T));
}
return defaultValue;
}
public virtual T? Get<T>(TKey key)
{
if (_InternalDictionary.TryGetValue(key, out var value))
{
return (T)Convert.ChangeType(value, typeof(T));
}
return default;
}
public virtual List<T> GetList<T>(TKey key, List<T> defaultValue)
{
if(_InternalDictionary.TryGetValue(key, out var value))
{
if (value is not IList)
{
throw new Exception("The value is not a list");
}
var list = new List<T>();
foreach (var item in (IList)value)
{
list.Add(ConvertValue<T>(item));
}
return list;
}
return defaultValue;
}
public virtual void Remove(TKey key)
{
_InternalDictionary.Remove(key);
}
public virtual IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return _InternalDictionary.GetEnumerator();
}
public virtual void Clear()
{
_InternalDictionary.Clear();
}
public virtual bool ContainsKey(TKey key)
{
return _InternalDictionary.ContainsKey(key);
}
public virtual IEnumerable<KeyValuePair<TKey, TValue>> Where(Func<KeyValuePair<TKey, TValue>, bool> predicate)
{
return _InternalDictionary.Where(predicate);
}
public virtual IEnumerable<KeyValuePair<TKey, TValue>> Where(Func<KeyValuePair<TKey, TValue>, int, bool> predicate)
{
return _InternalDictionary.Where(predicate);
}
public virtual IEnumerable<TResult> Where<TResult>(Func<KeyValuePair<TKey, TValue>, TResult> selector)
{
return _InternalDictionary.Select(selector);
}
public virtual IEnumerable<TResult> Where<TResult>(Func<KeyValuePair<TKey, TValue>, int, TResult> selector)
{
return _InternalDictionary.Select(selector);
}
public virtual KeyValuePair<TKey, TValue> FirstOrDefault(Func<KeyValuePair<TKey, TValue>, bool> predicate)
{
return _InternalDictionary.FirstOrDefault(predicate);
}
public virtual KeyValuePair<TKey, TValue> FirstOrDefault()
{
return _InternalDictionary.FirstOrDefault();
}
public virtual bool ContainsAllKeys(params TKey[] keys)
{
return keys.All(ContainsKey);
}
public virtual bool TryGetValue(TKey key, out TValue? value)
{
return _InternalDictionary.TryGetValue(key, out value);
}
public abstract Task SaveToFile();
public abstract Task LoadFromFile();
protected virtual T? ConvertValue<T>(object value)
{
if (typeof(T) == typeof(ulong) && value is long longValue)
{
return (T)(object)Convert.ToUInt64(longValue);
}
if (typeof(T).IsEnum && value is string stringValue)
{
return (T)Enum.Parse(typeof(T), stringValue);
}
return (T)Convert.ChangeType(value, typeof(T));
}
}

View File

@@ -0,0 +1,136 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace DiscordBotCore.Others.Settings;
internal interface ICustomSettingsDictionary<TKey,TValue>
{
/// <summary>
/// Adds an element to the custom settings dictionary
/// </summary>
/// <param name="key">The key</param>
/// <param name="value">The value</param>
void Add(TKey key, TValue value);
/// <summary>
/// Sets the value of a key in the custom settings dictionary
/// </summary>
/// <param name="key">The key</param>
/// <param name="value">The value</param>
void Set(TKey key, TValue value);
/// <summary>
/// Gets the value of a key in the custom settings dictionary. If the T type is different then the TValue type, it will try to convert it.
/// </summary>
/// <param name="key">The key</param>
/// <param name="defaultValue">The default value to be returned if the searched value is not found</param>
/// <typeparam name="T">The type of the returned value</typeparam>
/// <returns></returns>
T Get<T>(TKey key, T defaultValue);
/// <summary>
/// Gets the value of a key in the custom settings dictionary. If the T type is different then the TValue type, it will try to convert it.
/// </summary>
/// <param name="key">The key</param>
/// <typeparam name="T">The type of the returned value</typeparam>
/// <returns></returns>
T? Get<T>(TKey key);
/// <summary>
/// Get a list of values from the custom settings dictionary
/// </summary>
/// <param name="key">The key</param>
/// <param name="defaultValue">The default list to be returned if nothing is found</param>
/// <typeparam name="T">The type of the returned value</typeparam>
/// <returns></returns>
List<T> GetList<T>(TKey key, List<T> defaultValue);
/// <summary>
/// Remove a key from the custom settings dictionary
/// </summary>
/// <param name="key">The key</param>
void Remove(TKey key);
/// <summary>
/// Get the enumerator of the custom settings dictionary
/// </summary>
/// <returns></returns>
IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator();
/// <summary>
/// Clear the custom settings dictionary
/// </summary>
void Clear();
/// <summary>
/// Check if the custom settings dictionary contains a key
/// </summary>
/// <param name="key">The key</param>
/// <returns></returns>
bool ContainsKey(TKey key);
/// <summary>
/// Filter the custom settings dictionary based on a predicate
/// </summary>
/// <param name="predicate">The predicate</param>
/// <returns></returns>
IEnumerable<KeyValuePair<TKey, TValue>> Where(Func<KeyValuePair<TKey, TValue>, bool> predicate);
/// <summary>
/// Filter the custom settings dictionary based on a predicate
/// </summary>
/// <param name="predicate">The predicate</param>
IEnumerable<KeyValuePair<TKey, TValue>> Where(Func<KeyValuePair<TKey, TValue>, int, bool> predicate);
/// <summary>
/// Filter the custom settings dictionary based on a predicate
/// </summary>
/// <param name="selector">The predicate</param>
IEnumerable<TResult> Where<TResult>(Func<KeyValuePair<TKey, TValue>, TResult> selector);
/// <summary>
/// Filter the custom settings dictionary based on a predicate
/// </summary>
/// <param name="selector">The predicate</param>
IEnumerable<TResult> Where<TResult>(Func<KeyValuePair<TKey, TValue>, int, TResult> selector);
/// <summary>
/// Get the first element of the custom settings dictionary based on a predicate
/// </summary>
/// <param name="predicate">The predicate</param>
KeyValuePair<TKey, TValue> FirstOrDefault(Func<KeyValuePair<TKey, TValue>, bool> predicate);
/// <summary>
/// Get the first element of the custom settings dictionary
/// </summary>
/// <returns></returns>
KeyValuePair<TKey, TValue> FirstOrDefault();
/// <summary>
/// Checks if the custom settings dictionary contains all the keys
/// </summary>
/// <param name="keys">A list of keys</param>
/// <returns></returns>
bool ContainsAllKeys(params TKey[] keys);
/// <summary>
/// Try to get the value of a key in the custom settings dictionary
/// </summary>
/// <param name="key">The key</param>
/// <param name="value">The value</param>
/// <returns></returns>
bool TryGetValue(TKey key, out TValue? value);
/// <summary>
/// Save the custom settings dictionary to a file
/// </summary>
/// <returns></returns>
Task SaveToFile();
/// <summary>
/// Load the custom settings dictionary from a file
/// </summary>
/// <returns></returns>
Task LoadFromFile();
}