diff --git a/Library.Core/NodeFlow/DynamicContext.cs b/Library.Core/DynamicContext.cs
similarity index 77%
rename from Library.Core/NodeFlow/DynamicContext.cs
rename to Library.Core/DynamicContext.cs
index 081f660..735a5f7 100644
--- a/Library.Core/NodeFlow/DynamicContext.cs
+++ b/Library.Core/DynamicContext.cs
@@ -2,13 +2,13 @@
using Serein.Library.Utils;
using System.Collections.Concurrent;
-namespace Serein.Library.Core.NodeFlow
+namespace Serein.Library.Core
{
///
/// 动态流程上下文
///
- public class DynamicContext: IDynamicContext
+ public class DynamicContext : IDynamicContext
{
///
/// 动态流程上下文
@@ -30,6 +30,11 @@ namespace Serein.Library.Core.NodeFlow
///
public RunState RunState { get; set; } = RunState.NoStart;
+ ///
+ /// 用来在当前流程上下文间传递数据
+ ///
+ public Dictionary ContextShareData { get; } = new Dictionary();
+
///
/// 当前节点执行完成后,设置该属性,让运行环境判断接下来要执行哪个分支的节点。
///
@@ -52,7 +57,7 @@ namespace Serein.Library.Core.NodeFlow
/// 上一节点
public void SetPreviousNode(NodeModelBase currentNodeModel, NodeModelBase PreviousNode)
{
- dictPreviousNodes.AddOrUpdate(currentNodeModel, (_)=> PreviousNode, (_,_) => PreviousNode);
+ dictPreviousNodes.AddOrUpdate(currentNodeModel, (_) => PreviousNode, (_, _) => PreviousNode);
}
///
@@ -80,7 +85,7 @@ namespace Serein.Library.Core.NodeFlow
///
public object? GetFlowData(string nodeGuid)
{
- if(dictNodeFlowData.TryGetValue(nodeGuid, out var data))
+ if (dictNodeFlowData.TryGetValue(nodeGuid, out var data))
{
return data;
}
@@ -98,7 +103,7 @@ namespace Serein.Library.Core.NodeFlow
public void AddOrUpdate(string nodeGuid, object? flowData)
{
// this.dictNodeFlowData.TryGetValue(nodeGuid, out var oldFlowData);
- this.dictNodeFlowData.AddOrUpdate(nodeGuid, _ => flowData, (_, _) => flowData);
+ dictNodeFlowData.AddOrUpdate(nodeGuid, _ => flowData, (_, _) => flowData);
}
///
@@ -108,12 +113,12 @@ namespace Serein.Library.Core.NodeFlow
public object? TransmissionData(NodeModelBase nodeModel)
{
if (dictPreviousNodes.TryGetValue(nodeModel, out var previousNode)) // 首先获取当前节点的上一节点
- {
- if (dictNodeFlowData.TryGetValue(previousNode.Guid, out var data)) // 其次获取上一节点的数据
- {
+ {
+ if (dictNodeFlowData.TryGetValue(previousNode.Guid, out var data)) // 其次获取上一节点的数据
+ {
return data;
//AddOrUpdate(nodeModel.Guid, data); // 然后作为当前节点的数据记录在上下文中
- }
+ }
}
return null;
}
@@ -134,7 +139,22 @@ namespace Serein.Library.Core.NodeFlow
}
}
}
+ foreach (var nodeObj in ContextShareData.Values)
+ {
+ if (nodeObj is null)
+ {
+ continue;
+ }
+ else
+ {
+ if (typeof(IDisposable).IsAssignableFrom(nodeObj?.GetType()) && nodeObj is IDisposable disposable)
+ {
+ disposable?.Dispose();
+ }
+ }
+ }
this.dictNodeFlowData?.Clear();
+ this.ContextShareData?.Clear();
RunState = RunState.Completion;
}
diff --git a/Library.Core/NodeFlow/FlipflopContext.cs b/Library.Core/FlipflopContext.cs
similarity index 97%
rename from Library.Core/NodeFlow/FlipflopContext.cs
rename to Library.Core/FlipflopContext.cs
index 47baffe..a9e6862 100644
--- a/Library.Core/NodeFlow/FlipflopContext.cs
+++ b/Library.Core/FlipflopContext.cs
@@ -1,6 +1,6 @@
using Serein.Library.Api;
-namespace Serein.Library.Core.NodeFlow
+namespace Serein.Library.Core
{
public static class FlipflopFunc
{
@@ -56,7 +56,7 @@ namespace Serein.Library.Core.NodeFlow
//if (innerType == typeof(IFlipflopContext))
//if (innerType.IsGenericType && innerType.GetGenericTypeDefinition() == typeof(FlipflopContext<>))
//{
- //return true;
+ //return true;
//}
}
diff --git a/Library.Core/Serein.Library.Core.csproj b/Library.Core/Serein.Library.Core.csproj
index e4daf39..0658f6b 100644
--- a/Library.Core/Serein.Library.Core.csproj
+++ b/Library.Core/Serein.Library.Core.csproj
@@ -1,7 +1,7 @@
- 1.0.15
+ 1.0.16
net8.0
enable
enable
@@ -23,7 +23,6 @@
-
@@ -31,7 +30,6 @@
-
@@ -39,15 +37,12 @@
-
-
-
diff --git a/Library.Framework/NodeFlow/DynamicContext.cs b/Library.Framework/DynamicContext.cs
similarity index 88%
rename from Library.Framework/NodeFlow/DynamicContext.cs
rename to Library.Framework/DynamicContext.cs
index b3770ca..9a971d8 100644
--- a/Library.Framework/NodeFlow/DynamicContext.cs
+++ b/Library.Framework/DynamicContext.cs
@@ -1,6 +1,7 @@
using Serein.Library.Api;
using System;
using System.Collections.Concurrent;
+using System.Collections.Generic;
namespace Serein.Library.Framework.NodeFlow
{
@@ -29,6 +30,11 @@ namespace Serein.Library.Framework.NodeFlow
///
public RunState RunState { get; set; } = RunState.NoStart;
+ ///
+ /// 用来在当前流程上下文间传递数据
+ ///
+ public Dictionary ContextShareData { get; } = new Dictionary();
+
///
/// 当前节点执行完成后,设置该属性,让运行环境判断接下来要执行哪个分支的节点。
///
@@ -132,7 +138,22 @@ namespace Serein.Library.Framework.NodeFlow
}
}
}
+ foreach (var nodeObj in ContextShareData.Values)
+ {
+ if (nodeObj is null)
+ {
+ continue;
+ }
+ else
+ {
+ if (typeof(IDisposable).IsAssignableFrom(nodeObj?.GetType()) && nodeObj is IDisposable disposable)
+ {
+ disposable?.Dispose();
+ }
+ }
+ }
this.dictNodeFlowData?.Clear();
+ this.ContextShareData?.Clear();
RunState = RunState.Completion;
}
// public NodeRunCts NodeRunCts { get; set; }
diff --git a/Library.Framework/NodeFlow/FlipflopContext.cs b/Library.Framework/FlipflopContext.cs
similarity index 100%
rename from Library.Framework/NodeFlow/FlipflopContext.cs
rename to Library.Framework/FlipflopContext.cs
diff --git a/Library.Framework/Serein.Library.Framework.csproj b/Library.Framework/Serein.Library.Framework.csproj
index 5fc1e64..332ba9c 100644
--- a/Library.Framework/Serein.Library.Framework.csproj
+++ b/Library.Framework/Serein.Library.Framework.csproj
@@ -50,8 +50,8 @@
-
-
+
+
diff --git a/Library.Framework/packages.config b/Library.Framework/packages.config
index 284ce17..c34824f 100644
--- a/Library.Framework/packages.config
+++ b/Library.Framework/packages.config
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/Library/Api/IDynamicContext.cs b/Library/Api/IDynamicContext.cs
index 54b3f81..53ada34 100644
--- a/Library/Api/IDynamicContext.cs
+++ b/Library/Api/IDynamicContext.cs
@@ -1,6 +1,7 @@
using Serein.Library;
using Serein.Library.Utils;
using System;
+using System.Collections.Generic;
using System.Threading.Tasks;
namespace Serein.Library.Api
@@ -20,6 +21,11 @@ namespace Serein.Library.Api
///
RunState RunState { get; }
+ ///
+ /// 用来在当前流程上下文间传递数据
+ ///
+ Dictionary ContextShareData { get; }
+
///
/// 下一个要执行的节点类别
///
@@ -52,7 +58,6 @@ namespace Serein.Library.Api
///
object TransmissionData(NodeModelBase nodeModel);
-
///
/// 添加或更新当前节点的数据
///
@@ -61,10 +66,12 @@ namespace Serein.Library.Api
void AddOrUpdate(string nodeGuid, object flowData);
///
- /// 用以提前结束分支运行
+ /// 用以提前结束当前上下文流程的运行
///
void Exit();
+
+
/*///
/// 定时循环触发
diff --git a/Library/Api/IFlowEnvironment.cs b/Library/Api/IFlowEnvironment.cs
index 35541c3..cef123b 100644
--- a/Library/Api/IFlowEnvironment.cs
+++ b/Library/Api/IFlowEnvironment.cs
@@ -619,7 +619,7 @@ namespace Serein.Library.Api
event EnvOutHandler OnEnvOut;
#endregion
- #region 接口
+ #region 流程接口
///
/// 设置输出
@@ -891,6 +891,24 @@ namespace Serein.Library.Api
void TriggerInterrupt(string nodeGuid, string expression, InterruptTriggerEventArgs.InterruptTriggerType type);
+ #endregion
+
+ #region 流程依赖类库的接口
+
+ ///
+ /// 运行时加载
+ ///
+ /// 文件名
+ ///
+ bool LoadNativeLibraryOfRuning(string file);
+
+ ///
+ /// 运行时加载指定目录下的类库
+ ///
+ /// 目录
+ /// 是否递归加载
+ void LoadAllNativeLibraryOfRuning(string path, bool isRecurrence = true);
+
#endregion
#region UI视觉
diff --git a/Library/FlowNode/MethodDetails.cs b/Library/FlowNode/MethodDetails.cs
index 53157c5..f20ba18 100644
--- a/Library/FlowNode/MethodDetails.cs
+++ b/Library/FlowNode/MethodDetails.cs
@@ -64,13 +64,20 @@ namespace Serein.Library
[PropertyInfo]
private string _methodAnotherName;
-
///
/// 参数描述
///
[PropertyInfo]
private ParameterDetails[] _parameterDetailss;
+ ///
+ /// 描述该方法是否存在可选参数
+ /// -1表示不存在
+ /// 0表示第一个参数是可选参数
+ ///
+ [PropertyInfo]
+ private int _isParamsArgIndex = -1;
+
///
/// 出参类型
///
@@ -81,6 +88,83 @@ namespace Serein.Library
public partial class MethodDetails
{
+
+ #region 新增可选参数
+ ///
+ /// 新增可选参数
+ ///
+ ///
+ public void AddParamsArg(int index = 0)
+ {
+ if (IsParamsArgIndex >= 0 // 方法是否包含可选参数
+ && index >= 0 // 如果包含,则判断从哪个参数赋值
+ && index >= IsParamsArgIndex // 需要判断是否为可选参数的部分
+ && index < ParameterDetailss.Length) // 防止下标越界
+ {
+ var newPd = ParameterDetailss[index].CloneOfModel(this.NodeModel); // 复制出属于本身节点的参数描述
+ newPd.Index = ParameterDetailss.Length; // 更新索引
+ newPd.IsParams = true;
+ ParameterDetailss = AddToArray(ParameterDetailss, newPd); // 新增
+ }
+ }
+ ///
+ /// 移除可选参数
+ ///
+ ///
+ public void RemoveParamsArg(int index = 0)
+ {
+ if (IsParamsArgIndex >= 0 // 方法是否包含可选参数
+ && index >= 0 // 如果包含,则判断从哪个参数赋值
+ && index >= IsParamsArgIndex // 需要判断是否为可选参数的部分
+ && index < ParameterDetailss.Length) // 防止下标越界
+ {
+ //var newPd = ParameterDetailss[index].CloneOfModel(this.NodeModel); // 复制出属于本身节点的参数描述
+ //newPd.Index = ParameterDetailss.Length; // 更新索引
+ ParameterDetailss[index] = null; // 释放对象引用
+ ParameterDetailss = RemoteToArray(ParameterDetailss, index); // 新增
+ }
+ }
+
+ public static T[] AddToArray(T[] original, T newObject)
+ {
+ // 创建一个新数组,比原数组大1
+ T[] newArray = new T[original.Length + 1];
+
+ // 复制原数组的元素
+ for (int i = 0; i < original.Length; i++)
+ {
+ newArray[i] = original[i];
+ }
+
+ // 将新对象放在最后一位
+ newArray[newArray.Length - 1] = newObject;
+
+ return newArray;
+ }
+ public static T[] RemoteToArray(T[] original, int index)
+ {
+ if(index == 0)
+ {
+ return new T[0];
+ }
+ // 创建一个新数组,比原数组小1
+ T[] newArray = new T[original.Length - 1];
+
+ for (int i = 0; i < index; i++)
+ {
+ newArray[i] = original[i];
+ }
+ for (int i = index; i < newArray.Length; i++)
+ {
+ newArray[i] = original[i+1];
+ }
+ return newArray;
+ }
+
+
+ #endregion
+
+
///
/// 不包含方法信息的基础节点(后续可能要改为DLL引入基础节点)
///
@@ -91,9 +175,8 @@ namespace Serein.Library
///
/// 生成元数据
///
- /// 节点运行的环境
/// 标识属于哪个节点
- public MethodDetails(IFlowEnvironment env, NodeModelBase nodeModel)
+ public MethodDetails(NodeModelBase nodeModel)
{
NodeModel = nodeModel;
}
@@ -114,6 +197,7 @@ namespace Serein.Library
MethodDynamicType = nodeType;
ReturnType = Type.GetType(Info.ReturnTypeFullName);
ParameterDetailss = Info.ParameterDetailsInfos.Select(pinfo => new ParameterDetails(pinfo)).ToArray();
+ IsParamsArgIndex = Info.IsParamsArgIndex;
}
///
@@ -122,25 +206,25 @@ namespace Serein.Library
///
public MethodDetailsInfo ToInfo()
{
-
-
return new MethodDetailsInfo
{
- MethodName = MethodName,
- MethodAnotherName = MethodAnotherName,
- NodeType = MethodDynamicType.ToString(),
- ParameterDetailsInfos = ParameterDetailss.Select(p => p.ToInfo()).ToArray(),
- ReturnTypeFullName = ReturnType.FullName,
+ MethodName = this.MethodName,
+ MethodAnotherName = this.MethodAnotherName,
+ NodeType = this.MethodDynamicType.ToString(),
+ ParameterDetailsInfos = this.ParameterDetailss.Select(p => p.ToInfo()).ToArray(),
+ ReturnTypeFullName = this.ReturnType.FullName,
+ IsParamsArgIndex = this.IsParamsArgIndex,
};
}
///
- /// 从DLL拖动出来时拷贝属于节点的实例
+ /// 从DLL拖动出来时,从元数据拷贝新的实例,作为属于节点独享的方法描述
///
///
- public MethodDetails CloneOfNode(IFlowEnvironment env, NodeModelBase nodeModel)
+ public MethodDetails CloneOfNode( NodeModelBase nodeModel)
{
- var md = new MethodDetails(env, nodeModel) // 创建新节点时拷贝实例
+ // this => 是元数据
+ var md = new MethodDetails( nodeModel) // 创建新节点时拷贝实例
{
ActingInstance = this.ActingInstance,
ActingInstanceType = this.ActingInstanceType,
@@ -150,8 +234,9 @@ namespace Serein.Library
MethodName = this.MethodName,
MethodLockName = this.MethodLockName,
IsProtectionParameter = this.IsProtectionParameter,
+ IsParamsArgIndex= this.IsParamsArgIndex,
};
- md.ParameterDetailss = this.ParameterDetailss?.Select(p => p?.CloneOfClone(env, nodeModel)).ToArray(); // 拷贝属于节点方法的新入参描述
+ md.ParameterDetailss = this.ParameterDetailss?.Select(p => p?.CloneOfModel(nodeModel)).ToArray(); // 拷贝属于节点方法的新入参描述
return md;
}
@@ -163,71 +248,16 @@ namespace Serein.Library
sb.AppendLine($"需要实例:{this.ActingInstanceType?.FullName}");
sb.AppendLine($"");
sb.AppendLine($"入参参数信息:");
- foreach (var arg in this.ParameterDetailss)
+ for (int i = 0; i < ParameterDetailss.Length; i++)
{
- sb.AppendLine($" {arg.ToString()}");
+ ParameterDetails arg = this.ParameterDetailss[i];
}
sb.AppendLine($"");
sb.AppendLine($"返回值信息:");
- sb.AppendLine($" {this.ReturnType.FullName}");
+ sb.AppendLine($" {this.ReturnType?.FullName}");
return sb.ToString();
}
- /////
- ///// 每个节点有独自的MethodDetails实例
- /////
- //public partial class TmpMethodDetails
- //{
- // ///
- // /// 是否保护参数(目前仅视觉效果参数,不影响运行实现,后续将设置作用在运行逻辑中)
- // ///
- // public bool IsProtectionParameter { get; set; } = false;
-
- // ///
- // /// 作用实例的类型(多个相同的节点将拥有相同的类型)
- // ///
- // public Type ActingInstanceType { get; set; }
-
- // ///
- // /// 作用实例(多个相同的节点将会共享同一个实例)
- // ///
- // public object ActingInstance { get; set; }
-
- // ///
- // /// 方法名称
- // ///
- // public string MethodName { get; set; }
-
- // ///
- // /// 节点类型
- // ///
- // public NodeType MethodDynamicType { get; set; }
-
- // ///
- // /// 锁名称(暂未实现)
- // ///
- // public string MethodLockName { get; set; }
-
-
- // ///
- // /// 方法说明
- // ///
- // public string MethodTips { get; set; }
-
-
- // ///
- // /// 参数描述
- // ///
-
- // public ParameterDetails[] ParameterDetailss { get; set; }
-
- // ///
- // /// 出参类型
- // ///
-
- // public Type ReturnType { get; set; }
- //}
-
}
}
diff --git a/Library/FlowNode/MethodDetailsInfo.cs b/Library/FlowNode/MethodDetailsInfo.cs
index 8e0383f..53e2fb9 100644
--- a/Library/FlowNode/MethodDetailsInfo.cs
+++ b/Library/FlowNode/MethodDetailsInfo.cs
@@ -37,6 +37,11 @@ namespace Serein.Library
public ParameterDetailsInfo[] ParameterDetailsInfos { get; set; }
+ ///
+ /// 可选参数信息
+ ///
+ public int IsParamsArgIndex { get; set; }
+
///
/// 出参类型
///
diff --git a/Library/FlowNode/NodeModelBaseData.cs b/Library/FlowNode/NodeModelBaseData.cs
index c999403..eca2ae8 100644
--- a/Library/FlowNode/NodeModelBaseData.cs
+++ b/Library/FlowNode/NodeModelBaseData.cs
@@ -87,9 +87,9 @@ namespace Serein.Library
public abstract partial class NodeModelBase : IDynamicFlowNode
{
///
- /// 加载完成后调用的方法
+ /// 实体节点创建完成后调用的方法,调用时间早于 LoadInfo() 方法
///
- public abstract void OnLoading();
+ public abstract void OnCreating();
public NodeModelBase(IFlowEnvironment environment)
{
diff --git a/Library/FlowNode/NodeModelBaseFunc.cs b/Library/FlowNode/NodeModelBaseFunc.cs
index 9c21502..0842402 100644
--- a/Library/FlowNode/NodeModelBaseFunc.cs
+++ b/Library/FlowNode/NodeModelBaseFunc.cs
@@ -80,16 +80,43 @@ namespace Serein.Library
this.Position = nodeInfo.Position;// 加载位置信息
if (this.MethodDetails != null)
{
- for (int i = 0; i < nodeInfo.ParameterData.Length; i++)
+ if(this.MethodDetails.ParameterDetailss is null)
{
- var mdPd = this.MethodDetails.ParameterDetailss[i];
- ParameterData pd = nodeInfo.ParameterData[i];
- mdPd.IsExplicitData = pd.State;
- mdPd.DataValue = pd.Value;
- mdPd.ArgDataSourceType = EnumHelper.ConvertEnum(pd.SourceType);
- mdPd.ArgDataSourceNodeGuid = pd.SourceNodeGuid;
-
+ this.MethodDetails.ParameterDetailss = new ParameterDetails[nodeInfo.ParameterData.Length];
+ this.MethodDetails.ParameterDetailss = nodeInfo.ParameterData.Select((pd,index) =>
+ {
+ return new ParameterDetails()
+ {
+ Index = index,
+ NodeModel = this,
+ DataType = typeof(object),
+ ExplicitType = typeof(object),
+ Name = string.Empty,
+ ExplicitTypeName = "Value",
+ IsExplicitData = pd.State,
+ DataValue = pd.Value,
+ ArgDataSourceType = EnumHelper.ConvertEnum(pd.SourceType),
+ ArgDataSourceNodeGuid = pd.SourceNodeGuid,
+ };
+ }).ToArray();
}
+ else
+ {
+ for (int i = 0; i < nodeInfo.ParameterData.Length; i++)
+ {
+ var mdPd = this.MethodDetails.ParameterDetailss[i];
+ ParameterData pd = nodeInfo.ParameterData[i];
+ mdPd.IsExplicitData = pd.State;
+ mdPd.DataValue = pd.Value;
+ mdPd.ArgDataSourceType = EnumHelper.ConvertEnum(pd.SourceType);
+ mdPd.ArgDataSourceNodeGuid = pd.SourceNodeGuid;
+
+ }
+ }
+
+
+
+
}
return this;
}
@@ -160,7 +187,7 @@ namespace Serein.Library
// 从栈中弹出一个节点作为当前节点进行处理
var currentNode = stack.Pop();
-
+#if false
// 筛选出上游分支
var upstreamNodes = currentNode.SuccessorNodes[ConnectionInvokeType.Upstream].ToArray();
for (int index = 0; index < upstreamNodes.Length; index++)
@@ -183,33 +210,64 @@ namespace Serein.Library
break;
}
}
- }
+ }
+#endif
// 上游分支执行完成,才执行当前节点
if (IsBradk(context, flowCts)) break; // 退出执行
context.NextOrientation = ConnectionInvokeType.None; // 重置上下文状态
- object newFlowData = await currentNode.ExecutingAsync(context);
- if (IsBradk(context, flowCts)) break; // 退出执行
+
+ object newFlowData;
+ try
+ {
+
+ if (IsBradk(context, flowCts)) break; // 退出执行
+ newFlowData = await currentNode.ExecutingAsync(context);
+ if (IsBradk(context, flowCts)) break; // 退出执行
+ if (context.NextOrientation == ConnectionInvokeType.None) // 没有手动设置时,进行自动设置
+ {
+ context.NextOrientation = ConnectionInvokeType.IsSucceed;
+ }
+
+ }
+ catch (Exception ex)
+ {
+ newFlowData = null;
+ await Console.Out.WriteLineAsync($"节点[{this.MethodDetails?.MethodName}]异常:" + ex);
+ context.NextOrientation = ConnectionInvokeType.IsError;
+ currentNode.RuningException = ex;
+ }
+
await RefreshFlowDataAndExpInterrupt(context, currentNode, newFlowData); // 执行当前节点后刷新数据
#endregion
-
#region 执行完成
- // 选择后继分支
- var nextNodes = currentNode.SuccessorNodes[context.NextOrientation];
- // 将下一个节点集合中的所有节点逆序推入栈中
- for (int i = nextNodes.Count - 1; i >= 0; i--)
+
+
+ // 首先将指定类别后继分支的所有节点逆序推入栈中
+ var nextNodes = currentNode.SuccessorNodes[context.NextOrientation];
+ for (int index = nextNodes.Count - 1; index >= 0; index--)
{
// 筛选出启用的节点的节点
- if (nextNodes[i].DebugSetting.IsEnable)
+ if (nextNodes[index].DebugSetting.IsEnable)
{
- context.SetPreviousNode(nextNodes[i], currentNode);
- stack.Push(nextNodes[i]);
+ context.SetPreviousNode(nextNodes[index], currentNode);
+ stack.Push(nextNodes[index]);
+ }
+ }
+ // 然后将指上游分支的所有节点逆序推入栈中
+ var upstreamNodes = currentNode.SuccessorNodes[ConnectionInvokeType.Upstream];
+ for (int index = upstreamNodes.Count - 1; index >= 0; index--)
+ {
+ // 筛选出启用的节点的节点
+ if (upstreamNodes[index].DebugSetting.IsEnable)
+ {
+ context.SetPreviousNode(upstreamNodes[index], currentNode);
+ stack.Push(upstreamNodes[index]);
}
}
-
#endregion
}
@@ -245,73 +303,20 @@ namespace Serein.Library
{
md.ActingInstance = context.Env.IOC.Get(md.ActingInstanceType);
}
- try
- {
- object[] args = await GetParametersAsync(context, this, md);
- var result = await dd.InvokeAsync(md.ActingInstance, args);
- if(context.NextOrientation == ConnectionInvokeType.None) // 没有手动设置时,进行自动设置
- {
- context.NextOrientation = ConnectionInvokeType.IsSucceed;
- }
- return result;
- }
- catch (Exception ex)
- {
- await Console.Out.WriteLineAsync($"节点[{this.MethodDetails?.MethodName}]异常:" + ex);
- context.NextOrientation = ConnectionInvokeType.IsError;
- RuningException = ex;
- return null;
- }
- }
- ///
- /// 执行单个节点对应的方法,并不做状态检查
- ///
- /// 运行时上下文
- ///
- public virtual async Task
public string SourceType { get; set; }
-
///
/// 自定义入参
///
public string Value { get; set; }
+
///
/// 表达式相关节点的表达式内容
///
- public string Expression { get; set; }
+ // public string Expression { get; set; }
}
diff --git a/Library/Network/Mqtt/MqttServer.cs b/Library/Network/Mqtt/MqttServer.cs
new file mode 100644
index 0000000..f2f6950
--- /dev/null
+++ b/Library/Network/Mqtt/MqttServer.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Serein.Library.Network.Mqtt
+{
+ internal interface IMqttServer
+ {
+ void Staer();
+
+ void Stop();
+
+ void HandleMsg(string msg);
+
+ void AddHandleConfig();
+
+ }
+}
diff --git a/Library/Network/WebSocket/Handle/WebSocketHandleModule.cs b/Library/Network/WebSocket/Handle/WebSocketHandleModule.cs
index acfd58d..d71068d 100644
--- a/Library/Network/WebSocket/Handle/WebSocketHandleModule.cs
+++ b/Library/Network/WebSocket/Handle/WebSocketHandleModule.cs
@@ -3,10 +3,6 @@ using Newtonsoft.Json.Linq;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
-using System.Reflection;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading;
using System.Threading.Tasks;
namespace Serein.Library.Network.WebSocketCommunication.Handle
diff --git a/Library/Network/WebSocket/Handle/WebSocketHandleModuleConfig.cs b/Library/Network/WebSocket/Handle/WebSocketHandleModuleConfig.cs
index c6b3d4b..577cf0b 100644
--- a/Library/Network/WebSocket/Handle/WebSocketHandleModuleConfig.cs
+++ b/Library/Network/WebSocket/Handle/WebSocketHandleModuleConfig.cs
@@ -1,10 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Serein.Library.Network.WebSocketCommunication.Handle
+namespace Serein.Library.Network.WebSocketCommunication.Handle
{
///
/// 远程环境配置
diff --git a/Library/Network/WebSocket/Handle/WebSocketMsgContext.cs b/Library/Network/WebSocket/Handle/WebSocketMsgContext.cs
index acbd5a4..f297182 100644
--- a/Library/Network/WebSocket/Handle/WebSocketMsgContext.cs
+++ b/Library/Network/WebSocket/Handle/WebSocketMsgContext.cs
@@ -1,8 +1,5 @@
using Newtonsoft.Json.Linq;
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
using System.Threading.Tasks;
namespace Serein.Library.Network.WebSocketCommunication.Handle
diff --git a/Library/Network/WebSocket/Handle/WebSocketMsgHandleHelper.cs b/Library/Network/WebSocket/Handle/WebSocketMsgHandleHelper.cs
index c54c379..902a5a7 100644
--- a/Library/Network/WebSocket/Handle/WebSocketMsgHandleHelper.cs
+++ b/Library/Network/WebSocket/Handle/WebSocketMsgHandleHelper.cs
@@ -1,23 +1,8 @@
-using Newtonsoft.Json.Linq;
-using System;
+using System;
using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Linq;
-using System.Net.WebSockets;
-using System.Reflection;
-using System.Text;
-using System.Threading.Tasks;
-using System.Threading;
-using System.Runtime.CompilerServices;
-using Newtonsoft.Json;
-using Serein.Library.Utils;
-using System.Net.Http.Headers;
-using System.Linq.Expressions;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-using System.Security.Cryptography;
using System.Diagnostics.CodeAnalysis;
-using System.Reactive;
+using System.Linq;
+using System.Reflection;
namespace Serein.Library.Network.WebSocketCommunication.Handle
{
diff --git a/Library/Serein.Library.csproj b/Library/Serein.Library.csproj
index be41dc9..b4a3b35 100644
--- a/Library/Serein.Library.csproj
+++ b/Library/Serein.Library.csproj
@@ -1,7 +1,7 @@
- 1.0.18
+ 1.0.19
net8.0;net462
D:\Project\C#\DynamicControl\SereinFlow\.Output
@@ -32,11 +32,13 @@
+
+
diff --git a/Library/Utils/EmitHelper.cs b/Library/Utils/EmitHelper.cs
index 200e3b4..1ab5e89 100644
--- a/Library/Utils/EmitHelper.cs
+++ b/Library/Utils/EmitHelper.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Reactive;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
@@ -56,43 +57,37 @@ namespace Serein.Library.Utils
///
///
///
- public static EmitMethodType CreateDynamicMethod( MethodInfo methodInfo,out Delegate @delegate)
+ public static EmitMethodType CreateDynamicMethod(MethodInfo methodInfo,out Delegate @delegate)
{
bool IsTask = IsGenericTask(methodInfo.ReturnType, out var taskGenericsType);
bool IsTaskGenerics = taskGenericsType != null;
DynamicMethod dynamicMethod;
- if (IsTask)
- {
- if (IsTaskGenerics)
- {
- dynamicMethod = new DynamicMethod(
- name: methodInfo.Name + "_DynamicMethod",
- returnType: typeof(Task),
- parameterTypes: new[] { typeof(object), typeof(object[]) },
- restrictedSkipVisibility: true // 跳过私有方法访问限制
- );
- }
- else
- {
- dynamicMethod = new DynamicMethod(
- name: methodInfo.Name + "_DynamicMethod",
- returnType: typeof(Task),
- parameterTypes: new[] { typeof(object), typeof(object[]) },
- restrictedSkipVisibility: true // 跳过私有方法访问限制
- );
- }
+ Type returnType;
+ if (!IsTask)
+ {
+ // 普通方法
+ returnType = typeof(object);
}
else
{
- dynamicMethod = new DynamicMethod(
- name: methodInfo.Name + "_DynamicMethod",
- returnType: typeof(object),
- parameterTypes: new[] { typeof(object), typeof(object[]) },
- restrictedSkipVisibility: true // 跳过私有方法访问限制
- );
+ // 异步方法
+ if (IsTaskGenerics)
+ {
+ returnType = typeof(Task);
+ }
+ else
+ {
+ returnType = typeof(Task);
+ }
}
+ dynamicMethod = new DynamicMethod(
+ name: methodInfo.Name + "_DynamicEmitMethod",
+ returnType: returnType,
+ parameterTypes: new[] { typeof(object), typeof(object[]) }, // 方法实例、方法入参
+ restrictedSkipVisibility: true // 跳过私有方法访问限制
+ );
diff --git a/Library/Utils/NativeDllHelper.cs b/Library/Utils/NativeDllHelper.cs
new file mode 100644
index 0000000..9c6e556
--- /dev/null
+++ b/Library/Utils/NativeDllHelper.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Serein.Library.Utils
+{
+
+}
diff --git a/Library/Utils/SereinExpression/SerinExpressionEvaluator.cs b/Library/Utils/SereinExpression/SerinExpressionEvaluator.cs
index 9f73aa0..f15ad8b 100644
--- a/Library/Utils/SereinExpression/SerinExpressionEvaluator.cs
+++ b/Library/Utils/SereinExpression/SerinExpressionEvaluator.cs
@@ -51,6 +51,10 @@ namespace Serein.Library.Utils.SereinExpression
///
public static object Evaluate(string expression, object targetObJ, out bool isChange)
{
+ if(expression is null || targetObJ is null)
+ {
+ throw new Exception("表达式条件expression is null、 targetObJ is null");
+ }
var parts = expression.Split(new[] { ' ' }, 2, StringSplitOptions.None);
if (parts.Length != 2)
{
@@ -60,6 +64,7 @@ namespace Serein.Library.Utils.SereinExpression
var operation = parts[0].ToLower();
var operand = parts[1][0] == '.' ? parts[1].Substring(1) : parts[1];
object result;
+ isChange = false;
if (operation == "@num")
{
result = ComputedNumber(targetObJ, operand);
@@ -70,10 +75,12 @@ namespace Serein.Library.Utils.SereinExpression
}
else if (operation == "@get")
{
+ isChange = true;
result = GetMember(targetObJ, operand);
}
else if (operation == "@set")
{
+ isChange = true;
result = SetMember(targetObJ, operand);
}
else
@@ -81,14 +88,7 @@ namespace Serein.Library.Utils.SereinExpression
throw new NotSupportedException($"Operation {operation} is not supported.");
}
- if(operation == "@set")
- {
- isChange = true;
- }
- else
- {
- isChange = false;
- }
+
return result;
}
diff --git a/Net462DllTest/Main.cs b/Net462DllTest/Main.cs
index aed5926..881e7a9 100644
--- a/Net462DllTest/Main.cs
+++ b/Net462DllTest/Main.cs
@@ -1,4 +1,5 @@
-using System;
+using Serein.Library;
+using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
diff --git a/NodeFlow/Env/FlowEnvironment.cs b/NodeFlow/Env/FlowEnvironment.cs
index b4533b1..064e39d 100644
--- a/NodeFlow/Env/FlowEnvironment.cs
+++ b/NodeFlow/Env/FlowEnvironment.cs
@@ -2,7 +2,7 @@
using Newtonsoft.Json;
using Serein.Library;
using Serein.Library.Api;
-using Serein.Library.Core.NodeFlow;
+using Serein.Library.Core;
using Serein.Library.FlowNode;
using Serein.Library.Utils;
using Serein.Library.Utils.SereinExpression;
@@ -12,6 +12,7 @@ using System.Collections.Concurrent;
using System.Numerics;
using System.Reflection;
using System.Reflection.Metadata.Ecma335;
+using System.Runtime.Loader;
using System.Xml.Linq;
using static Serein.Library.Utils.ChannelFlowInterrupt;
@@ -364,7 +365,7 @@ namespace Serein.NodeFlow.Env
{
ExitFlow(); // 未运行触发器时,才会调用结束方法
}
- flowStarter = null;
+
}
///
@@ -379,7 +380,7 @@ namespace Serein.NodeFlow.Env
{
return;
}
- if (FlowState == RunState.Running || FlipFlopState == RunState.Running)
+ if (true || FlowState == RunState.Running || FlipFlopState == RunState.Running)
{
NodeModelBase? nodeModel = GuidToModel(startNodeGuid);
if (nodeModel is null || nodeModel is SingleFlipflopNode)
@@ -410,20 +411,22 @@ namespace Serein.NodeFlow.Env
object result = true;
if (this.NodeModels.TryGetValue(nodeGuid, out var model))
{
- result = await model.InvokeAsync(context);
+ result = await model.ExecutingAsync(context);
}
return result;
}
///
- /// 退出
+ /// 结束流程
///
public void ExitFlow()
{
ChannelFlowInterrupt?.CancelAllTasks();
flowStarter?.Exit();
UIContextOperation?.Invoke(() => OnFlowRunComplete?.Invoke(new FlowEventArgs()));
+ flowStarter = null;
GC.Collect();
+
}
///
@@ -500,7 +503,6 @@ namespace Serein.NodeFlow.Env
};
}
-
///
/// 清除所有
///
@@ -512,7 +514,6 @@ namespace Serein.NodeFlow.Env
}
-
///
/// 加载项目文件
///
@@ -749,7 +750,7 @@ namespace Serein.NodeFlow.Env
var groupedNodes = NodeModels.Values
.Where(node => node.MethodDetails is not null)
.ToArray()
- .GroupBy(node => node.MethodDetails!.MethodName)
+ .GroupBy(node => node.MethodDetails?.MethodName)
.ToDictionary(
key => key.Key,
group => group.Count());
@@ -1341,13 +1342,36 @@ namespace Serein.NodeFlow.Env
#endregion
+ #region 流程依赖类库的接口
+
+ ///
+ /// 运行时加载
+ ///
+ /// 文件名
+ ///
+ public bool LoadNativeLibraryOfRuning(string file)
+ {
+ return NativeDllHelper.LoadDll(file);
+ }
+
+ ///
+ /// 运行时加载指定目录下的类库
+ ///
+ /// 目录
+ /// 是否递归加载
+ public void LoadAllNativeLibraryOfRuning(string path, bool isRecurrence = true)
+ {
+ NativeDllHelper.LoadAllDll(path, isRecurrence);
+ }
+
+ #endregion
+
#region 私有方法
///
/// 加载指定路径的DLL文件
///
///
-
private void LoadDllNodeInfo(string dllPath)
{
(var nodeLibrary, var registerTypes, var mdlist) = LoadAssembly(dllPath);
@@ -1431,10 +1455,17 @@ namespace Serein.NodeFlow.Env
return true;
}
+ ///
+ ///
+ ///
+ ///
+ ///
private (NodeLibrary?, Dictionary>, List) LoadAssembly(string dllPath)
{
try
{
+ //FlowLibraryLoader flowLibraryLoader = new FlowLibraryLoader(dllPath);
+ //Assembly assembly = flowLibraryLoader.LoadFromAssemblyPath(dllPath);
Assembly assembly = Assembly.LoadFrom(dllPath); // 加载DLL文件
List types = assembly.GetTypes().ToList(); // 获取程序集中的所有类型
Dictionary> autoRegisterTypes = new Dictionary>();
@@ -1454,10 +1485,6 @@ namespace Serein.NodeFlow.Env
}
- //Dictionary autoRegisterTypes = assembly.GetTypes().Where(t => t.GetCustomAttribute() is not null).ToList();
-
-
-
List<(Type, string)> scanTypes = types.Select(t =>
{
if (t.GetCustomAttribute() is DynamicFlowAttribute dynamicFlowAttribute
@@ -1504,8 +1531,6 @@ namespace Serein.NodeFlow.Env
Console.WriteLine($"节点委托创建失败:{md.MethodName}");
}
}
-
- //methodDetails.AddRange(itemMethodDetails);
}
var nodeLibrary = new NodeLibrary
@@ -1714,10 +1739,24 @@ namespace Serein.NodeFlow.Env
ConnectionArgSourceType connectionArgSourceType,
int argIndex)
{
-
- if (!string.IsNullOrEmpty(toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceNodeGuid))
+ var oldNodeGuid = toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceNodeGuid;
+
+ if (!string.IsNullOrEmpty(oldNodeGuid))
{
- await RemoteConnectAsync(fromNode,toNode,argIndex); // 已经存在连接,将其移除
+ //if(NodeModels.TryGetValue(oldNodeGuid, out var oldNodeModel))
+ //{
+ // // 已经存在连接
+ // await RemoteConnectAsync(oldNodeModel, toNode, argIndex); // 已经存在连接,将其移除
+ //}
+ if (oldNodeGuid.Equals(fromNode.Guid))
+ {
+ await RemoteConnectAsync(fromNode, toNode, argIndex); // 相同起始节点不同控制点已经连接,将其移除
+ }
+ else
+ {
+ Console.WriteLine("目标入参已确定参数来源,不可连接 ");
+ return false;
+ }
}
toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceNodeGuid = fromNode.Guid;
toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceType = connectionArgSourceType;
@@ -1906,11 +1945,7 @@ namespace Serein.NodeFlow.Env
}
-
-
-
-
-
+
diff --git a/NodeFlow/Env/FlowEnvironmentDecorator.cs b/NodeFlow/Env/FlowEnvironmentDecorator.cs
index 53c7b76..142ca55 100644
--- a/NodeFlow/Env/FlowEnvironmentDecorator.cs
+++ b/NodeFlow/Env/FlowEnvironmentDecorator.cs
@@ -2,6 +2,7 @@
using Serein.Library.Api;
using Serein.Library.FlowNode;
using Serein.Library.Utils;
+using Serein.NodeFlow.Tool;
namespace Serein.NodeFlow.Env
{
@@ -426,6 +427,30 @@ namespace Serein.NodeFlow.Env
+ #region 流程依赖类库的接口
+
+ ///
+ /// 运行时加载
+ ///
+ /// 文件名
+ ///
+ public bool LoadNativeLibraryOfRuning(string file)
+ {
+ return currentFlowEnvironment.LoadNativeLibraryOfRuning(file);
+ }
+
+ ///
+ /// 运行时加载指定目录下的类库
+ ///
+ /// 目录
+ /// 是否递归加载
+ public void LoadAllNativeLibraryOfRuning(string path, bool isRecurrence = true)
+ {
+ currentFlowEnvironment.LoadAllNativeLibraryOfRuning(path,isRecurrence);
+ }
+
+ #endregion
+
#region IOC容器
public ISereinIOC Build()
{
diff --git a/NodeFlow/Env/FlowFunc.cs b/NodeFlow/Env/FlowFunc.cs
index 867300d..cb4c2c3 100644
--- a/NodeFlow/Env/FlowFunc.cs
+++ b/NodeFlow/Env/FlowFunc.cs
@@ -55,7 +55,7 @@ namespace Serein.NodeFlow.Env
var md = methodDetails.CloneOfNode(nodeModel.Env, nodeModel);
nodeModel.DisplayName = md.MethodAnotherName;
nodeModel.MethodDetails = md;
- nodeModel.OnLoading();
+ nodeModel.OnCreating();
return nodeModel;
}
diff --git a/NodeFlow/Env/RemoteFlowEnvironment.cs b/NodeFlow/Env/RemoteFlowEnvironment.cs
index cc52c63..2312ae8 100644
--- a/NodeFlow/Env/RemoteFlowEnvironment.cs
+++ b/NodeFlow/Env/RemoteFlowEnvironment.cs
@@ -835,5 +835,31 @@ namespace Serein.NodeFlow.Env
});
}
+
+
+ #region 流程依赖类库的接口
+
+ ///
+ /// 运行时加载
+ ///
+ /// 文件名
+ ///
+ public bool LoadNativeLibraryOfRuning(string file)
+ {
+ Console.WriteLine("远程环境尚未实现的接口:LoadNativeLibraryOfRuning");
+ return false;
+ }
+
+ ///
+ /// 运行时加载指定目录下的类库
+ ///
+ /// 目录
+ /// 是否递归加载
+ public void LoadAllNativeLibraryOfRuning(string path, bool isRecurrence = true)
+ {
+ Console.WriteLine("远程环境尚未实现的接口:LoadAllNativeLibraryOfRuning");
+ }
+
+ #endregion
}
}
diff --git a/NodeFlow/FlowStarter.cs b/NodeFlow/FlowStarter.cs
index 076da5a..961b110 100644
--- a/NodeFlow/FlowStarter.cs
+++ b/NodeFlow/FlowStarter.cs
@@ -1,10 +1,12 @@
using Serein.Library;
using Serein.Library.Api;
-using Serein.Library.Core.NodeFlow;
+using Serein.Library.Core;
using Serein.Library.Network.WebSocketCommunication;
+using Serein.Library.Utils;
using Serein.Library.Web;
using Serein.NodeFlow.Env;
using Serein.NodeFlow.Model;
+using Serein.NodeFlow.Tool;
using System.Collections.Concurrent;
namespace Serein.NodeFlow
@@ -48,9 +50,9 @@ namespace Serein.NodeFlow
{
IDynamicContext context;
#if NET6_0_OR_GREATER
- context = new Serein.Library.Core.NodeFlow.DynamicContext(env); // 从起始节点启动流程时创建上下文
+ context = new Serein.Library.Core.DynamicContext(env); // 从起始节点启动流程时创建上下文
#else
- Context = new Serein.Library.Framework.NodeFlow.DynamicContext(env);
+ Context = new Serein.Library.Framework.DynamicContext(env);
#endif
await startNode.StartFlowAsync(context); // 开始运行时从选定节点开始运行
context.Exit();
@@ -112,9 +114,9 @@ namespace Serein.NodeFlow
// 判断使用哪一种流程上下文
IDynamicContext Context;
#if NET6_0_OR_GREATER
- Context = new Serein.Library.Core.NodeFlow.DynamicContext(env); // 从起始节点启动流程时创建上下文
+ Context = new Serein.Library.Core.DynamicContext(env); // 从起始节点启动流程时创建上下文
#else
- Context = new Serein.Library.Framework.NodeFlow.DynamicContext(env);
+ Context = new Serein.Library.Framework.DynamicContext(env);
#endif
#endregion
@@ -233,13 +235,19 @@ namespace Serein.NodeFlow
await dd.InvokeAsync(md.ActingInstance, [Context]);
}
- TerminateAllGlobalFlipflop();
-
if (_flipFlopCts != null && !_flipFlopCts.IsCancellationRequested)
{
_flipFlopCts?.Cancel();
_flipFlopCts?.Dispose();
- }
+ } // 通知所有流程上下文停止运行
+ TerminateAllGlobalFlipflop(); // 确保所有触发器不再运行
+
+
+ NativeDllHelper.FreeLibrarys(); // 卸载所有已加载的 Native Dll
+
+ //NativeDllHelper.FreeLibrarys(); // 卸载所有已加载的 Native Dll
+
+
env.FlowState = RunState.Completion;
env.FlipFlopState = RunState.Completion;
@@ -379,8 +387,8 @@ namespace Serein.NodeFlow
await Console.Out.WriteLineAsync($"[{nextNodes[i].MethodDetails.MethodName}]中断已{cancelType},开始执行后继分支");
}
await nextNodes[i].StartFlowAsync(context); // 启动执行触发器后继分支的节点
- context.Exit();
}
+ context.Exit();
});
}
diff --git a/NodeFlow/Model/CompositeConditionNode.cs b/NodeFlow/Model/CompositeConditionNode.cs
index f3295a0..316fe12 100644
--- a/NodeFlow/Model/CompositeConditionNode.cs
+++ b/NodeFlow/Model/CompositeConditionNode.cs
@@ -32,7 +32,7 @@ namespace Serein.NodeFlow.Model
///
/// 加载完成后调用的方法
///
- public override void OnLoading()
+ public override void OnCreating()
{
Console.WriteLine("CompositeConditionNode 暂未实现 OnLoading");
}
diff --git a/NodeFlow/Model/SingleActionNode.cs b/NodeFlow/Model/SingleActionNode.cs
index a8a25df..6311d25 100644
--- a/NodeFlow/Model/SingleActionNode.cs
+++ b/NodeFlow/Model/SingleActionNode.cs
@@ -17,9 +17,9 @@ namespace Serein.NodeFlow.Model
///
/// 加载完成后调用的方法
///
- public override void OnLoading()
+ public override void OnCreating()
{
- Console.WriteLine("SingleActionNode 暂未实现 OnLoading");
+ // Console.WriteLine("SingleActionNode 暂未实现 OnLoading");
}
public override ParameterData[] GetParameterdatas()
diff --git a/NodeFlow/Model/SingleConditionNode.cs b/NodeFlow/Model/SingleConditionNode.cs
index 2225633..c97666b 100644
--- a/NodeFlow/Model/SingleConditionNode.cs
+++ b/NodeFlow/Model/SingleConditionNode.cs
@@ -1,5 +1,6 @@
using Serein.Library;
using Serein.Library.Api;
+using Serein.Library.Utils;
using Serein.Library.Utils.SereinExpression;
using System.ComponentModel;
@@ -22,14 +23,13 @@ namespace Serein.NodeFlow.Model
/// 自定义参数值
///
[PropertyInfo(IsNotification = true)]
- private object? _customData;
+ private string? _customData;
///
/// 条件表达式
///
[PropertyInfo(IsNotification = true)]
private string _expression;
-
}
public partial class SingleConditionNode : NodeModelBase
@@ -39,32 +39,9 @@ namespace Serein.NodeFlow.Model
this.IsCustomData = false;
this.CustomData = null;
this.Expression = "PASS";
-
}
- ///
- /// 加载完成后调用的方法
- ///
- public override void OnLoading()
- {
- var pd = new ParameterDetails
- {
- Index = 0,
- Name = "Exp",
- DataType = typeof(object),
- ExplicitType = typeof(object),
- IsExplicitData = false,
- DataValue = string.Empty,
- ArgDataSourceNodeGuid = string.Empty,
- ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData,
- NodeModel = this,
- Convertor = null,
- ExplicitTypeName = "Value",
- Items = Array.Empty(),
- };
-
- this.MethodDetails.ParameterDetailss = new ParameterDetails[] { pd };
- }
+
///
@@ -138,36 +115,102 @@ namespace Serein.NodeFlow.Model
return result;
}
+
+
public override ParameterData[] GetParameterdatas()
{
- var value = CustomData switch
- {
- Type when CustomData.GetType() == typeof(int)
- && CustomData.GetType() == typeof(double)
- && CustomData.GetType() == typeof(float)
- => ((double)CustomData).ToString(),
- Type when CustomData.GetType() == typeof(bool) => ((bool)CustomData).ToString(),
- _ => CustomData?.ToString()!,
- };
- return [new ParameterData
- {
- State = IsCustomData,
- Expression = Expression,
- Value = value,
- }];
+ var pd1 = MethodDetails.ParameterDetailss[0];
+ var pd2 = MethodDetails.ParameterDetailss[1];
+ var pd3 = MethodDetails.ParameterDetailss[2];
+ return [
+ new ParameterData // 保存表达式
+ {
+ Value = Expression ,
+ SourceNodeGuid = pd1.ArgDataSourceNodeGuid,
+ SourceType = pd1.ArgDataSourceType.ToString(),
+ },
+ new ParameterData // 保存自定义参数
+ {
+ Value = CustomData?.ToString() ,
+ SourceNodeGuid = pd2.ArgDataSourceNodeGuid,
+ SourceType = pd2.ArgDataSourceType.ToString(),
+ },
+ new ParameterData // 参数来源状态
+ {
+ Value = IsCustomData.ToString() ,
+ SourceNodeGuid = pd3.ArgDataSourceNodeGuid,
+ SourceType = pd3.ArgDataSourceType.ToString(),
+ }];
}
+ public override void OnCreating()
+ {
+ // 自定义节点初始化默认的参数实体
+ var tmpParameterDetails = new ParameterDetails[3];
+ for (int index = 0; index <= 2; index++)
+ {
+ tmpParameterDetails[index] = new ParameterDetails
+ {
+ Index = index,
+ IsExplicitData = false,
+ DataValue = string.Empty,
+ ArgDataSourceNodeGuid = string.Empty,
+ ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData,
+ NodeModel = this,
+ Convertor = null,
+ ExplicitTypeName = "Value",
+ Items = Array.Empty(),
+ };
+ }
+
+ var pd1 = tmpParameterDetails[0]; // 表达式
+ var pd2 = tmpParameterDetails[1]; // 自定义参数
+ var pd3 = tmpParameterDetails[2]; // 参数来源
+
+ // 表达式
+ pd1.Name = nameof(Expression);
+ pd1.DataType = typeof(string);
+ pd1.ExplicitType = typeof(string);
+
+ // 自定义参数
+ pd2.Name = nameof(CustomData);
+ pd2.DataType = typeof(string);
+ pd2.ExplicitType = typeof(string);
+
+ // 参数来源
+ pd3.Name = nameof(IsCustomData);
+ pd3.DataType = typeof(bool);
+ pd3.ExplicitType = typeof(bool);
+
+ //this.MethodDetails.ParameterDetailss = new ParameterDetails[2] { pd1, pd2 };
+ this.MethodDetails.ParameterDetailss = [..tmpParameterDetails];
+ }
+
+
+
+
public override NodeModelBase LoadInfo(NodeInfo nodeInfo)
{
- var node = this;
- node.Guid = nodeInfo.Guid;
+ this.Guid = nodeInfo.Guid;
this.Position = nodeInfo.Position;// 加载位置信息
+
+ var pdInfo1 = nodeInfo.ParameterData[0];
+ this.Expression = pdInfo1.Value; // 加载表达式
+
+ var pdInfo2 = nodeInfo.ParameterData[1];
+ this.CustomData = pdInfo2.Value; // 加载自定义参数信息
+
+ var pdInfo3 = nodeInfo.ParameterData[2];
+ bool.TryParse(pdInfo3.Value,out var @bool); // 参数来源状态
+ this.IsCustomData = @bool;
+
for (int i = 0; i < nodeInfo.ParameterData.Length; i++)
{
- ParameterData? pd = nodeInfo.ParameterData[i];
- node.IsCustomData = pd.State;
- node.CustomData = pd.Value;
- node.Expression = pd.Expression;
+ var pd = this.MethodDetails.ParameterDetailss[i]; // 本节点的参数信息
+ ParameterData? pdInfo = nodeInfo.ParameterData[i]; // 项目文件的保存信息
+
+ pd.ArgDataSourceNodeGuid = pdInfo.SourceNodeGuid;
+ pd.ArgDataSourceType = EnumHelper.ConvertEnum(pdInfo.SourceType);
}
return this;
}
diff --git a/NodeFlow/Model/SingleExpOpNode.cs b/NodeFlow/Model/SingleExpOpNode.cs
index 09054d8..4de043e 100644
--- a/NodeFlow/Model/SingleExpOpNode.cs
+++ b/NodeFlow/Model/SingleExpOpNode.cs
@@ -1,5 +1,6 @@
using Serein.Library;
using Serein.Library.Api;
+using Serein.Library.Utils;
using Serein.Library.Utils.SereinExpression;
using System.Reactive;
using System.Reflection.Metadata;
@@ -32,14 +33,14 @@ namespace Serein.NodeFlow.Model
///
/// 加载完成后调用的方法
///
- public override void OnLoading()
+ public override void OnCreating()
{
var pd = new ParameterDetails
{
Index = 0,
- Name = "Exp",
- DataType = typeof(object),
- ExplicitType = typeof(object),
+ Name = nameof(Expression),
+ DataType = typeof(string),
+ ExplicitType = typeof(string),
IsExplicitData = false,
DataValue = string.Empty,
ArgDataSourceNodeGuid = string.Empty,
@@ -92,7 +93,7 @@ namespace Serein.NodeFlow.Model
}
context.NextOrientation = ConnectionInvokeType.IsSucceed;
- return Task.FromResult(result);
+ return result;
}
catch (Exception ex)
{
@@ -105,7 +106,11 @@ namespace Serein.NodeFlow.Model
public override ParameterData[] GetParameterdatas()
{
- return [new ParameterData { Expression = Expression }];
+ return [new ParameterData {
+ Value = Expression,
+ SourceNodeGuid = this.MethodDetails.ParameterDetailss[0].ArgDataSourceNodeGuid,
+ SourceType = this.MethodDetails.ParameterDetailss[0].ArgDataSourceType.ToString(),
+ }];
}
@@ -113,11 +118,17 @@ namespace Serein.NodeFlow.Model
public override NodeModelBase LoadInfo(NodeInfo nodeInfo)
{
var node = this;
- this.Position = nodeInfo.Position;// 加载位置信息
node.Guid = nodeInfo.Guid;
+ this.Position = nodeInfo.Position;// 加载位置信息
+
+ var pdInfo1 = nodeInfo.ParameterData[0];
+ node.Expression = pdInfo1.Value; // 加载表达式
+
for (int i = 0; i < nodeInfo.ParameterData.Length; i++)
{
- node.Expression = nodeInfo.ParameterData[i].Expression;
+ ParameterData? pd = nodeInfo.ParameterData[i];
+ node.MethodDetails.ParameterDetailss[i].ArgDataSourceNodeGuid = pd.SourceNodeGuid;
+ node.MethodDetails.ParameterDetailss[i].ArgDataSourceType = EnumHelper.ConvertEnum(pd.SourceType);
}
return this;
}
diff --git a/NodeFlow/Model/SingleFlipflopNode.cs b/NodeFlow/Model/SingleFlipflopNode.cs
index 9025da1..f6b99fe 100644
--- a/NodeFlow/Model/SingleFlipflopNode.cs
+++ b/NodeFlow/Model/SingleFlipflopNode.cs
@@ -19,9 +19,9 @@ namespace Serein.NodeFlow.Model
///
/// 加载完成后调用的方法
///
- public override void OnLoading()
+ public override void OnCreating()
{
- Console.WriteLine("SingleFlipflopNode 暂未实现 OnLoading");
+ // Console.WriteLine("SingleFlipflopNode 暂未实现 OnLoading");
}
@@ -50,16 +50,18 @@ namespace Serein.NodeFlow.Model
object instance = md.ActingInstance;
try
{
+
var args = await GetParametersAsync(context, this, md);
- var result = await dd.InvokeAsync(md.ActingInstance, args);
- dynamic flipflopContext = result;
- FlipflopStateType flipflopStateType = flipflopContext.State;
+ // 因为这里会返回不确定的泛型 IFlipflopContext
+ // 而我们只需要获取到 State 和 Value(返回的数据)
+ dynamic dynamicFlipflopContext = await dd.InvokeAsync(md.ActingInstance, args);
+ FlipflopStateType flipflopStateType = dynamicFlipflopContext.State;
context.NextOrientation = flipflopStateType.ToContentType();
- if (flipflopContext.Type == TriggerType.Overtime)
+ if (dynamicFlipflopContext.Type == TriggerType.Overtime)
{
throw new FlipflopException(base.MethodDetails.MethodName + "触发器超时触发。Guid" + base.Guid);
}
- return flipflopContext.Value;
+ return dynamicFlipflopContext.Value;
}
catch (FlipflopException ex)
diff --git a/NodeFlow/Serein.NodeFlow.csproj b/NodeFlow/Serein.NodeFlow.csproj
index e57693b..0c55436 100644
--- a/NodeFlow/Serein.NodeFlow.csproj
+++ b/NodeFlow/Serein.NodeFlow.csproj
@@ -1,7 +1,7 @@
- 1.0.18
+ 1.0.19
net8.0
enable
enable
@@ -60,6 +60,7 @@
+
diff --git a/NodeFlow/Tool/FlowLibraryLoader.cs b/NodeFlow/Tool/FlowLibraryLoader.cs
new file mode 100644
index 0000000..6be1d4b
--- /dev/null
+++ b/NodeFlow/Tool/FlowLibraryLoader.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.Loader;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Serein.NodeFlow.Tool
+{
+ ///
+ /// 管理加载在流程的程序集
+ ///
+ public class FlowLibraryLoader : AssemblyLoadContext
+ {
+ private Assembly _pluginAssembly;
+
+ ///
+ /// 加载程序集
+ ///
+ ///
+ public FlowLibraryLoader(string pluginPath) : base(isCollectible: true)
+ {
+ _pluginAssembly = LoadFromAssemblyPath(pluginPath);
+ }
+
+ ///
+ /// 保持默认加载行为
+ ///
+ ///
+ ///
+
+ protected override Assembly Load(AssemblyName assemblyName)
+ {
+ return null; // 保持默认加载行为
+ }
+
+ ///
+ /// 是否对程序集的引用
+ ///
+ public void UnloadPlugin()
+ {
+ _pluginAssembly = null; // 释放对程序集的引用
+ Unload(); // 触发卸载
+ // 强制进行垃圾回收,以便完成卸载
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ }
+ }
+
+
+
+}
diff --git a/NodeFlow/Tool/NativeDllHelper.cs b/NodeFlow/Tool/NativeDllHelper.cs
new file mode 100644
index 0000000..1f35c03
--- /dev/null
+++ b/NodeFlow/Tool/NativeDllHelper.cs
@@ -0,0 +1,182 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Serein.NodeFlow.Tool
+{
+
+ internal class NativeDllHelper
+ {
+
+ // 引入 Windows API 函数
+ [DllImport("kernel32.dll", SetLastError = true)]
+ private static extern IntPtr LoadLibrary(string lpFileName);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ private static extern bool FreeLibrary(IntPtr hModule);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
+
+
+
+ // 引入 Unix/Linux 的动态库加载函数
+ [DllImport("libdl.so.2", SetLastError = true)]
+ private static extern IntPtr dlopen(string filename, int flag);
+
+ [DllImport("libdl.so.2", SetLastError = true)]
+ private static extern IntPtr dlsym(IntPtr handle, string symbol);
+
+ [DllImport("libdl.so.2", SetLastError = true)]
+ private static extern int dlclose(IntPtr handle);
+
+ private const int RTLD_NOW = 2;
+
+ // bool LoadDll(string file)
+ // void LoadAllDll(string path, bool isRecurrence = true);
+
+ private static List Nints = new List();
+
+ ///
+ /// 加载单个Dll
+ ///
+ ///
+ public static bool LoadDll(string file)
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ return LoadWindowsLibrarie(file);
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ return LoadLinuxLibrarie(file);
+ }
+ else
+ {
+ Console.WriteLine("Unsupported OS.");
+ return false;
+ }
+ }
+
+ public static void LoadAllDll(string path, bool isRecurrence = true)
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ foreach (var file in Directory.GetFiles(path, "*.dll"))
+ {
+ LoadWindowsLibrarie(file);
+ }
+
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ foreach (var file in Directory.GetFiles(path, "*.so"))
+ {
+ LoadLinuxLibrarie(file);
+ }
+ }
+ else
+ {
+ Console.WriteLine("Unsupported OS.");
+ }
+
+ foreach (var dir in Directory.GetDirectories(path))
+ {
+ LoadAllDll(dir, true);
+ }
+
+ }
+
+
+ ///
+ /// 加载Windows类库
+ ///
+ ///
+ /// 是否递归加载
+ private static bool LoadWindowsLibrarie(string file)
+ {
+ IntPtr hModule = IntPtr.Zero;
+ try
+ {
+ hModule = LoadLibrary(file);
+ // 加载 DLL
+ if (hModule != IntPtr.Zero)
+ {
+ Nints.Add(hModule);
+ Console.WriteLine($"Loaded: {file}");
+ return true;
+ }
+ else
+ {
+ Console.WriteLine($"Failed to load {file}: {Marshal.GetLastWin32Error()}");
+ return false;
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error loading {file}: {ex.Message}");
+ return false;
+ }
+ }
+
+
+ ///
+ /// 加载Linux类库
+ ///
+ ///
+ private static bool LoadLinuxLibrarie(string file)
+ {
+
+ IntPtr handle = IntPtr.Zero;
+
+ try
+ {
+ handle = dlopen(file, RTLD_NOW);
+ if (handle != IntPtr.Zero)
+ {
+ Nints.Add(handle);
+ Console.WriteLine($"Loaded: {file}");
+ return true;
+ // 可以调用共享库中的函数
+ // IntPtr procAddress = dlsym(handle, "my_function");
+ }
+ else
+ {
+ Console.WriteLine($"Failed to load {file}: {Marshal.GetLastWin32Error()}");
+ return false;
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error loading {file}: {ex.Message}");
+ return false;
+ }
+
+
+
+ }
+
+
+
+
+
+
+ ///
+ /// 卸载所有已加载DLL
+ ///
+ public static void FreeLibrarys()
+ {
+ for (int i = 0; i < Nints.Count; i++)
+ {
+ IntPtr hModule = Nints[i];
+ FreeLibrary(hModule);
+ }
+ Nints.Clear();
+ }
+ }
+}
diff --git a/NodeFlow/Tool/NodeMethodDetailsHelper.cs b/NodeFlow/Tool/NodeMethodDetailsHelper.cs
index 3d5e324..1b5a371 100644
--- a/NodeFlow/Tool/NodeMethodDetailsHelper.cs
+++ b/NodeFlow/Tool/NodeMethodDetailsHelper.cs
@@ -174,11 +174,11 @@ public static class NodeMethodDetailsHelper
ConvertorInstance[key] = (instance, convertMethod);
}
- Func func = (enumValue) =>
+ object func(object enumValue)
{
- (var obj,var methodInfo) = ConvertorInstance[key];
+ (var obj, var methodInfo) = ConvertorInstance[key];
return methodInfo?.Invoke(obj, [enumValue]);
- };
+ }
// 确保实例实现了所需接口
ParameterDetails ed = GetExplicitDataOfParameter(it, index, paremType, true, func);
@@ -206,26 +206,29 @@ public static class NodeMethodDetailsHelper
}
private static ParameterDetails GetExplicitDataOfParameter(ParameterInfo parameterInfo,
- int index,
- Type paremType,
- bool isExplicitData,
- Func func = null)
+ int index,
+ Type paremType,
+ bool isExplicitData,
+ Func func = null)
{
+ bool hasParams = parameterInfo.IsDefined(typeof(ParamArrayAttribute)); // 判断是否为可变参数
+
string explicitTypeName = GetExplicitTypeName(paremType);
var items = GetExplicitItems(paremType, explicitTypeName);
if ("Bool".Equals(explicitTypeName)) explicitTypeName = "Select"; // 布尔值 转为 可选类型
return new ParameterDetails
{
IsExplicitData = isExplicitData, //attribute is null ? parameterInfo.HasDefaultValue : true,
- Index = index,
- ExplicitTypeName = explicitTypeName,
- ExplicitType = paremType,
- Convertor = func,
- DataType = parameterInfo.ParameterType,
+ Index = index, // 索引
+ ExplicitTypeName = explicitTypeName, // Select/Bool/Value
+ ExplicitType = paremType,// 显示的入参类型
+ Convertor = func, // 转换器
+ DataType = parameterInfo.ParameterType, // 实际的入参类型
Name = parameterInfo.Name,
DataValue = parameterInfo.HasDefaultValue ? parameterInfo?.DefaultValue?.ToString() : "", // 如果存在默认值,则使用默认值
Items = items.ToArray(), // 如果是枚举值入参,则获取枚举类型的字面量
+ IsParams = hasParams, // 判断是否为可变参数
};
}
diff --git a/Serein.Library.MyGenerator/Serein.Library.NodeGenerator.csproj b/Serein.Library.MyGenerator/Serein.Library.NodeGenerator.csproj
index a813521..e111244 100644
--- a/Serein.Library.MyGenerator/Serein.Library.NodeGenerator.csproj
+++ b/Serein.Library.MyGenerator/Serein.Library.NodeGenerator.csproj
@@ -22,8 +22,11 @@
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
-