lampac/Shared/Engine/ModuleInvoke.cs
lampac-talks f843f04fd4 chore: initial commit 154.3
Signed-off-by: lampac-talks <lampac-talks@users.noreply.github.com>
2026-01-30 16:23:09 +03:00

194 lines
6.3 KiB
C#

using Newtonsoft.Json.Linq;
using Shared.Engine.Utilities;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
namespace Shared.Engine
{
/// <summary>
/// [Copilot AI]
/// </summary>
public static class ModuleInvoke
{
public static T Init<T>(string filed, T val)
{
if (val == null)
return val;
// Use existing ConfObject logic to get merged JObject/token
var confObj = Conf(filed, val);
if (confObj == null)
return val;
// If caller expects a JObject, return directly
if (typeof(T) == typeof(JObject))
return (T)(object)confObj;
// If we have a wrapper for non-object values { "value": ... }, extract it
if (confObj.Count == 1 && confObj.ContainsKey("value"))
{
try
{
var token = confObj["value"];
return token.ToObject<T>();
}
catch
{
return val;
}
}
// Otherwise try to convert the merged object back to T
try
{
return confObj.ToObject<T>();
}
catch
{
return val;
}
}
public static JObject Conf(string filed, object val)
{
if (val == null)
return null;
// Convert incoming value to JToken/JObject
JToken baseToken = val as JToken ?? JToken.FromObject(val);
if (baseToken == null)
return null;
if (baseToken.Type != JTokenType.Object)
{
// For non-object values wrap into a simple object so merging still possible
return new JObject { ["value"] = baseToken };
}
var baseObj = (JObject)baseToken;
try
{
if (!File.Exists("init.conf") && !File.Exists("init.yaml"))
return baseObj;
JObject jo = null;
// First try init.conf if exists
if (File.Exists("init.conf"))
{
string initfile = File.ReadAllText("init.conf").Trim();
if (!string.IsNullOrEmpty(initfile))
{
if (!initfile.StartsWith("{"))
initfile = "{" + initfile + "}";
try
{
jo = JObject.Parse(initfile);
}
catch
{
try
{
jo = JObject.FromObject(Newtonsoft.Json.JsonConvert.DeserializeObject(initfile) ?? new JObject());
}
catch { jo = null; }
}
}
}
// Then try init.yaml and merge/override into jo if present
if (File.Exists("init.yaml"))
{
try
{
var yaml = File.ReadAllText("init.yaml").Trim();
if (!string.IsNullOrEmpty(yaml))
{
var deserializer = new DeserializerBuilder()
.WithNamingConvention(CamelCaseNamingConvention.Instance)
.IgnoreUnmatchedProperties()
.Build();
var deserialized = deserializer.Deserialize<object>(yaml) ?? new object();
// Convert deserialized YAML to JSON and then to JObject
var json = JsonConvertPool.SerializeObject(deserialized);
JObject yamlJo = null;
try
{
yamlJo = JObject.Parse(json);
}
catch
{
try
{
yamlJo = JObject.FromObject(Newtonsoft.Json.JsonConvert.DeserializeObject(json) ?? new JObject());
}
catch { yamlJo = null; }
}
if (yamlJo != null)
{
if (jo == null)
jo = yamlJo;
else
Merge(jo, yamlJo);
}
}
}
catch
{
// ignore yaml parse errors
}
}
if (jo == null || !jo.ContainsKey(filed))
return baseObj;
var node = jo[filed];
// If field explicitly false -> return original val
if (node.Type == JTokenType.Boolean && node.Value<bool>() == false)
return baseObj;
// If node is not an object, nothing to merge -> return original
if (node.Type != JTokenType.Object)
return baseObj;
var overrideObj = (JObject)node;
// Deep clone base
var result = (JObject)baseObj.DeepClone();
Merge(result, overrideObj);
return result;
}
catch
{
return baseObj;
}
}
static void Merge(JObject target, JObject source)
{
foreach (var prop in source.Properties())
{
var tprop = target.Property(prop.Name);
if (tprop != null && tprop.Value.Type == JTokenType.Object && prop.Value.Type == JTokenType.Object)
{
Merge((JObject)tprop.Value, (JObject)prop.Value);
}
else
{
// Replace or add
target[prop.Name] = prop.Value.DeepClone();
}
}
}
}
}