초기커밋
This commit is contained in:
175
ServerCore/Config/ConfigManager.cs
Normal file
175
ServerCore/Config/ConfigManager.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
|
||||
using YamlDotNet.Serialization;
|
||||
using YamlDotNet.Serialization.NamingConventions;
|
||||
|
||||
|
||||
|
||||
namespace ServerCore;
|
||||
|
||||
|
||||
public sealed class ConfigManager : Singleton<ConfigManager>
|
||||
{
|
||||
private readonly List<(string path, string type)> m_file_sources = new();
|
||||
private readonly List<JObject> m_jobject_sources = new();
|
||||
|
||||
private readonly Dictionary<string, FileSystemWatcher> m_watchers = new();
|
||||
private bool m_is_detect_duplicates = true;
|
||||
|
||||
public ConfigManager() { }
|
||||
|
||||
public void dnableDuplicateDetection(bool enable)
|
||||
{
|
||||
m_is_detect_duplicates = enable;
|
||||
}
|
||||
|
||||
public ConfigManager addJson(string path)
|
||||
{
|
||||
loadJson(path);
|
||||
watchFile(path, "json");
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConfigManager addYaml(string path)
|
||||
{
|
||||
loadYaml(path);
|
||||
watchFile(path, "yaml");
|
||||
return this;
|
||||
}
|
||||
|
||||
private void loadJson(string path)
|
||||
{
|
||||
if (false == File.Exists(path))
|
||||
{
|
||||
throw new FileNotFoundException($"Not found Json File !!! : path:{path}");
|
||||
}
|
||||
|
||||
var json_text = File.ReadAllText(path);
|
||||
var jObject = JObject.Parse(json_text);
|
||||
m_file_sources.Add((path, "json"));
|
||||
m_jobject_sources.Add(jObject);
|
||||
}
|
||||
|
||||
private void loadYaml(string path)
|
||||
{
|
||||
if (false == File.Exists(path))
|
||||
{
|
||||
throw new FileNotFoundException($"Not found Yaml File !!! : path:{path}");
|
||||
}
|
||||
|
||||
var yamlText = File.ReadAllText(path);
|
||||
var deserializer = new DeserializerBuilder()
|
||||
.WithNamingConvention(CamelCaseNamingConvention.Instance)
|
||||
.Build();
|
||||
|
||||
var yamlObject = deserializer.Deserialize<object>(yamlText);
|
||||
var serializer = new SerializerBuilder()
|
||||
.JsonCompatible()
|
||||
.Build();
|
||||
|
||||
var json = serializer.Serialize(yamlObject);
|
||||
var jObject = JObject.Parse(json);
|
||||
m_file_sources.Add((path, "yaml"));
|
||||
m_jobject_sources.Add(jObject);
|
||||
}
|
||||
|
||||
private void watchFile(string path, string type)
|
||||
{
|
||||
if (m_watchers.ContainsKey(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var directory_name = Path.GetDirectoryName(path);
|
||||
NullReferenceCheckHelper.throwIfNull(directory_name, () => $"directory_name is null !!! : path:{path}, format:{type}");
|
||||
var watcher = new FileSystemWatcher(directory_name)
|
||||
{
|
||||
Filter = Path.GetFileName(path),
|
||||
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.Size
|
||||
};
|
||||
|
||||
watcher.Changed += (sender, e) => reloadAll();
|
||||
watcher.Created += (sender, e) => reloadAll();
|
||||
watcher.Renamed += (sender, e) => reloadAll();
|
||||
watcher.EnableRaisingEvents = true;
|
||||
|
||||
m_watchers[path] = watcher;
|
||||
}
|
||||
|
||||
private void reloadAll()
|
||||
{
|
||||
Log.getLogger().error("Detected changes in config file !!!, Reloading...");
|
||||
|
||||
m_jobject_sources.Clear();
|
||||
foreach (var (path, type) in m_file_sources)
|
||||
{
|
||||
if (type == "json")
|
||||
{
|
||||
loadJson(path);
|
||||
}
|
||||
else if (type == "yaml")
|
||||
{
|
||||
loadYaml(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public T bind<T>(string sectionName)
|
||||
{
|
||||
if (m_jobject_sources.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException("No config sources have been loaded !!!");
|
||||
}
|
||||
|
||||
var merged = new JObject();
|
||||
|
||||
foreach (var source in m_jobject_sources)
|
||||
{
|
||||
if (true == m_is_detect_duplicates)
|
||||
{
|
||||
detectDuplicateKeys(merged, source);
|
||||
}
|
||||
|
||||
merged.Merge(source, new JsonMergeSettings
|
||||
{
|
||||
MergeArrayHandling = MergeArrayHandling.Replace,
|
||||
MergeNullValueHandling = MergeNullValueHandling.Merge
|
||||
});
|
||||
}
|
||||
|
||||
JToken? target_token = null;
|
||||
if (false == merged.TryGetValue(sectionName, out var found_target_token))
|
||||
{
|
||||
target_token = merged;
|
||||
}
|
||||
else
|
||||
{
|
||||
target_token = found_target_token;
|
||||
}
|
||||
|
||||
if (target_token == null)
|
||||
{
|
||||
throw new Exception($"Section could not be found !!! : sectionName:{sectionName}");
|
||||
}
|
||||
|
||||
return target_token.ToObject<T>()!;
|
||||
}
|
||||
|
||||
private void detectDuplicateKeys(JObject existing, JObject incoming)
|
||||
{
|
||||
foreach (var prop in incoming.Properties())
|
||||
{
|
||||
if (existing.ContainsKey(prop.Name))
|
||||
{
|
||||
Log.getLogger().error($"Duplicate key detected !!!, overwritten by later value : propertyName:{prop.Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user