using Serein.Library;
using Serein.Library.Api;
using Serein.NodeFlow.Model.Library;
using Serein.NodeFlow.Tool;
using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Xml.Linq;
namespace Serein.NodeFlow.Services
{
///
/// 管理加载在运行环境中的外部程序集
///
public class FlowLibraryService
{
///
/// 构造函数,初始化流程依赖
///
///
public FlowLibraryService(IFlowEnvironment flowEnvironment)
{
this.flowEnvironment = flowEnvironment;
}
private readonly IFlowEnvironment flowEnvironment;
///
/// 缓存流程依赖
///
private readonly ConcurrentDictionary _flowLibraryCaches = new ConcurrentDictionary();
private readonly ConcurrentDictionary _flowLibraryAssemblyContexts
= new ConcurrentDictionary();
///
/// 每个类库下面至少需要有“Serein.Library.dll”类库依赖
///
///
///
///
private bool CheckBaseLibrary(string libraryfilePath, out string baseLibraryPath)
{
var dir = Path.GetDirectoryName(libraryfilePath); // 获取目录路径
ArgumentNullException.ThrowIfNullOrWhiteSpace(dir);
var sereinFlowBaseLibraryPath = Path.Combine(dir, SereinBaseLibrary);
if (!Path.Exists(sereinFlowBaseLibraryPath))
{
baseLibraryPath = string.Empty;
return false;
}
baseLibraryPath = sereinFlowBaseLibraryPath;
return true;
}
///
/// 加载基础依赖
///
public FlowLibraryInfo LoadBaseLibrary()
{
Assembly baseAssmbly = typeof(FlowBaseLibrary).Assembly;
var flowLibrary = new FlowLibraryCache(baseAssmbly);
flowLibrary.LoadFlowMethod();
var assemblyName = baseAssmbly.GetName().Name;
if (string.IsNullOrEmpty(assemblyName))
{
throw new Exception($"程序集\"{baseAssmbly}\"返回 Name 为 null");
}
_flowLibraryCaches.TryAdd(assemblyName, flowLibrary);
return flowLibrary.ToInfo();
}
///
/// 加载流程依赖
///
///
///
public FlowLibraryInfo? LoadFlowLibrary(string libraryfilePath)
{
if (!CheckBaseLibrary(libraryfilePath, out var baseLibraryPath))
{
throw new Exception($"从文件加载DLL失败,目标文件夹不存在{SereinBaseLibrary}文件");
}
FlowLibraryAssemblyContext flowAlc = new FlowLibraryAssemblyContext(baseLibraryPath, Path.GetFileName(libraryfilePath));
var flowAssembly = flowAlc.LoadFromAssemblyPath(libraryfilePath);
if(flowAssembly is null)
{
throw new Exception($"从文件加载DLL失败,FlowLibraryAssemblyContext 加载的程序集为 null \"{libraryfilePath}\"");
}
var flowLibrary = new FlowLibraryCache(flowAssembly);
var isSuccess = flowLibrary.LoadFlowMethod();
if (!isSuccess)
{
flowAlc?.Unload(); // 卸载程序集
GC.Collect(); // 强制触发GC确保卸载成功
GC.WaitForPendingFinalizers();
return null;
}
else
{
var assemblyName = flowAssembly.GetName().Name;
if (string.IsNullOrEmpty(assemblyName))
{
flowLibrary.Unload();
flowAlc?.Unload(); // 卸载程序集
GC.Collect(); // 强制触发GC确保卸载成功
GC.WaitForPendingFinalizers();
return null;
throw new Exception($"程序集\"{flowAssembly}\"返回 Name 为 null");
}
_flowLibraryCaches.TryAdd(assemblyName, flowLibrary);
return flowLibrary.ToInfo();
}
}
///
/// 卸载类库
///
///
///
public bool UnloadLibrary(string assemblyName)
{
if (_flowLibraryCaches.Remove(assemblyName, out var flowLibrary))
{
try
{
flowLibrary.Unload(); // 尝试卸载
flowLibrary = null;
return true;
}
catch (Exception ex)
{
SereinEnv.WriteLine(InfoType.ERROR, $"尝试卸载程序集[{assemblyName}]发生错误:{ex.Message}");
return false;
}
}
else
{
return false;
}
}
#region 获取流程依赖的相关方法
///
/// 获取方法描述
///
/// 程序集名称
/// 方法名称
/// 返回的方法描述
/// 是否获取成功
public bool TryGetMethodInfo(string assemblyName, string methodName, [MaybeNullWhen(false)] out MethodInfo methodInfo)
{
if (string.IsNullOrEmpty(assemblyName) || string.IsNullOrEmpty(methodName))
{
methodInfo = null;
return false;
}
if (_flowLibraryCaches.TryGetValue(assemblyName, out var flowLibrary)
&& flowLibrary.MethodInfos.TryGetValue(methodName, out methodInfo))
{
return true;
}
else
{
methodInfo = null;
return false;
}
}
///
/// 获取方法描述
///
/// 程序集名称
/// 方法名称
/// 返回的方法描述
/// 是否获取成功
public bool TryGetMethodDetails(string assemblyName, string methodName, [MaybeNullWhen(false)] out MethodDetails md)
{
if (_flowLibraryCaches.TryGetValue(assemblyName, out var flowLibrary)
&& flowLibrary.MethodDetailss.TryGetValue(methodName, out md))
{
return true;
}
else
{
md = null;
return false;
}
}
///
/// 获取方法调用的委托
///
/// 程序集名称
/// 方法名称
/// 返回的委托调用封装类
/// 是否获取成功
public bool TryGetDelegateDetails(string assemblyName, string methodName, [MaybeNullWhen(false)] out DelegateDetails dd)
{
if (_flowLibraryCaches.TryGetValue(assemblyName, out var flowLibrary)
&& flowLibrary.DelegateDetailss.TryGetValue(methodName, out dd))
{
return true;
}
else
{
dd = null;
return false;
}
}
///
/// 获取(初始化/加载时/退出后)相应的节点方法
///
///
///
public List GetMdsOnFlowStart(NodeType nodeType)
{
List mds = [];
foreach (var library in _flowLibraryCaches.Values)
{
var t_mds = library.MethodDetailss.Values.Where(it => it.MethodDynamicType == nodeType).ToList();
mds.AddRange(t_mds);
}
return mds;
}
///
/// 获取流程启动时在不同时间点需要自动实例化的类型
///
///
public Dictionary> GetaAutoRegisterType()
{
Dictionary> rsTypes = new Dictionary>();
foreach (var library in _flowLibraryCaches.Values)
{
foreach (var kv in library.RegisterTypes)
{
var @class = kv.Key;
var type = kv.Value;
if (!rsTypes.TryGetValue(@class, out var tmpTypes))
{
tmpTypes = new List();
rsTypes.Add(@class, tmpTypes);
}
tmpTypes.AddRange(type);
}
}
return rsTypes;
}
///
/// 获取某个程序集下的所有方法信息,用于保存项目时调用
///
///
public List GetLibraryMdsOfAssmbly(string assemblyName)
{
if (_flowLibraryCaches.TryGetValue(assemblyName, out var flowLibrary))
{
return flowLibrary.MethodDetailss.Values.ToList();
}
return [];
}
///
/// 获取流程方法信息,用于保存项目时调用
///
///
public List GetAllLibraryMds()
{
List mds = new List();
foreach (FlowLibraryCache library in _flowLibraryCaches.Values)
{
var tmp = new FlowLibraryInfo
{
AssemblyName = library.FullName,
MethodInfos = library.MethodDetailss.Values.Select(md => md.ToInfo()).ToList()
};
mds.Add(tmp);
}
return mds;
}
///
/// 序列化当前项目的依赖信息、节点信息,用于远程登录的场景,需要将依赖信息从本地(受控端)发送到远程(主控端)
///
///
public List GetAllLibraryInfo()
{
return _flowLibraryCaches.Values.Where(lib => lib.FullName != "Serein.Library.dll").Select(library => library.ToInfo()).ToList();
}
#endregion
#region 功能性方法
///
/// 基础依赖
///
public readonly static string SereinBaseLibrary = $"{nameof(Serein)}.{nameof(Library)}.dll";
#endregion
}
}