diff --git a/Library/Api/IDynamicContext.cs b/Library/Api/IDynamicContext.cs
index 9add8da..db5b973 100644
--- a/Library/Api/IDynamicContext.cs
+++ b/Library/Api/IDynamicContext.cs
@@ -26,12 +26,6 @@ namespace Serein.Library.Api
///
RunState RunState { get; }
- ///
- /// 用来在当前流程上下文间传递数据
- ///
- //Dictionary ContextShareData { get; }
-
- object Tag { get; set; }
///
/// 下一个要执行的节点类别
@@ -77,6 +71,11 @@ namespace Serein.Library.Api
///
void AddOrUpdate(string nodeGuid, object flowData);
+ ///
+ /// 重置流程状态(用于对象池回收)
+ ///
+ void Reset();
+
///
/// 用以提前结束当前上下文流程的运行
///
diff --git a/Library/Api/IFlowEnvironment.cs b/Library/Api/IFlowEnvironment.cs
index 8b491bd..4cf05e8 100644
--- a/Library/Api/IFlowEnvironment.cs
+++ b/Library/Api/IFlowEnvironment.cs
@@ -693,7 +693,7 @@ namespace Serein.Library.Api
///
/// 全局触发器运行状态
///
- RunState FlipFlopState { get; set; }
+ //RunState FlipFlopState { get; set; }
///
/// 表示当前环境
diff --git a/Library/Api/ISereinIoc.cs b/Library/Api/ISereinIoc.cs
index 5516b4b..f8f181a 100644
--- a/Library/Api/ISereinIoc.cs
+++ b/Library/Api/ISereinIoc.cs
@@ -49,7 +49,7 @@ namespace Serein.Library.Api
/// 登记使用的名称
/// 实例对象
/// 是否注册成功
- bool RegisterInstance(string key, object instance);
+ /// bool RegisterInstance(string key, object instance);
///
/// 获取类型的实例。如果需要获取的类型以“接口-实现类”的方式注册,请使用接口的类型。
@@ -67,7 +67,7 @@ namespace Serein.Library.Api
///
/// 登记实例时使用的Key
///
- T Get(string key);
+ /// T Get(string key);
diff --git a/Library/FlowNode/ContainerFlowEnvironment.cs b/Library/FlowNode/ContainerFlowEnvironment.cs
index 97b6aff..1677008 100644
--- a/Library/FlowNode/ContainerFlowEnvironment.cs
+++ b/Library/FlowNode/ContainerFlowEnvironment.cs
@@ -295,10 +295,10 @@ namespace Serein.Library
{
return (T)sereinIOC.Get(typeof(T));
}
- T ISereinIOC.Get(string key)
- {
- return sereinIOC.Get(key);
- }
+ //T ISereinIOC.Get(string key)
+ //{
+ // return sereinIOC.Get(key);
+ //}
bool ISereinIOC.RegisterPersistennceInstance(string key, object instance)
@@ -311,10 +311,10 @@ namespace Serein.Library
return sereinIOC.RegisterPersistennceInstance(key, instance);
}
- bool ISereinIOC.RegisterInstance(string key, object instance)
- {
- return sereinIOC.RegisterInstance(key, instance);
- }
+ //bool ISereinIOC.RegisterInstance(string key, object instance)
+ //{
+ // return sereinIOC.RegisterInstance(key, instance);
+ //}
object ISereinIOC.Instantiate(Type type)
diff --git a/Library/FlowNode/DynamicContext.cs b/Library/FlowNode/DynamicContext.cs
index 09ff1e0..a1b6bc6 100644
--- a/Library/FlowNode/DynamicContext.cs
+++ b/Library/FlowNode/DynamicContext.cs
@@ -22,7 +22,7 @@ namespace Serein.Library
RunState = RunState.Running;
}
- private readonly string _guid = global::System.Guid.NewGuid().ToString();
+ private string _guid = global::System.Guid.NewGuid().ToString();
string IDynamicContext.Guid => _guid;
///
@@ -35,11 +35,6 @@ namespace Serein.Library
///
public RunState RunState { get; set; } = RunState.NoStart;
- ///
- /// 用来在当前流程上下文间传递数据
- ///
- //public Dictionary ContextShareData { get; } = new Dictionary();
- public object Tag { get; set; }
///
/// 当前节点执行完成后,设置该属性,让运行环境判断接下来要执行哪个分支的节点。
@@ -133,6 +128,37 @@ namespace Serein.Library
return null;
}
+ ///
+ /// 重置
+ ///
+ public void Reset()
+ {
+ //foreach (var nodeObj in dictNodeFlowData.Values)
+ //{
+ // if (nodeObj is null)
+ // {
+
+ // }
+ // else
+ // {
+ // if (typeof(IDisposable).IsAssignableFrom(nodeObj?.GetType()) && nodeObj is IDisposable disposable)
+ // {
+ // disposable?.Dispose();
+ // }
+ // }
+ //}
+ //if (Tag != null && typeof(IDisposable).IsAssignableFrom(Tag?.GetType()) && Tag is IDisposable tagDisposable)
+ //{
+ // tagDisposable?.Dispose();
+ //}
+ this.dictNodeFlowData?.Clear();
+ ExceptionOfRuning = null;
+ NextOrientation = ConnectionInvokeType.None;
+ RunState = RunState.Running;
+ _guid = global::System.Guid.NewGuid().ToString();
+ }
+
+
///
/// 结束当前流程上下文
///
@@ -156,9 +182,11 @@ namespace Serein.Library
//{
// tagDisposable?.Dispose();
//}
- this.Tag = null;
this.dictNodeFlowData?.Clear();
+ ExceptionOfRuning = null;
+ NextOrientation = ConnectionInvokeType.None;
RunState = RunState.Completion;
+ _guid = global::System.Guid.NewGuid().ToString();
}
private void Dispose(ref IDictionary keyValuePairs)
diff --git a/Library/FlowNode/MethodDetails.cs b/Library/FlowNode/MethodDetails.cs
index c4916a5..2c37b47 100644
--- a/Library/FlowNode/MethodDetails.cs
+++ b/Library/FlowNode/MethodDetails.cs
@@ -45,8 +45,8 @@ namespace Serein.Library
///
/// 作用实例(多个相同的节点将会共享同一个实例)
///
- [PropertyInfo]
- private object _actingInstance;
+ // [PropertyInfo]
+ // private object _actingInstance;
///
/// 方法名称
@@ -237,16 +237,16 @@ namespace Serein.Library
// this => 是元数据
var md = new MethodDetails( nodeModel) // 创建新节点时拷贝实例
{
- AssemblyName = this.AssemblyName,
- ActingInstance = this.ActingInstance,
- ActingInstanceType = this.ActingInstanceType,
- MethodDynamicType = this.MethodDynamicType,
- MethodAnotherName = this.MethodAnotherName,
- ReturnType = this.ReturnType,
- MethodName = this.MethodName,
- MethodLockName = this.MethodLockName,
- IsProtectionParameter = this.IsProtectionParameter,
- ParamsArgIndex = this.ParamsArgIndex,
+ AssemblyName = this.AssemblyName, // 拷贝
+ //ActingInstance = this.ActingInstance,
+ ActingInstanceType = this.ActingInstanceType, // 拷贝
+ MethodDynamicType = this.MethodDynamicType, // 拷贝
+ MethodAnotherName = this.MethodAnotherName, // 拷贝
+ ReturnType = this.ReturnType, // 拷贝
+ MethodName = this.MethodName, // 拷贝
+ MethodLockName = this.MethodLockName, // 拷贝
+ IsProtectionParameter = this.IsProtectionParameter, // 拷贝
+ ParamsArgIndex = this.ParamsArgIndex, // 拷贝
ParameterDetailss = this.ParameterDetailss?.Select(p => p?.CloneOfModel(nodeModel)).ToArray(), // 拷贝属于节点方法的新入参描述
};
diff --git a/Library/FlowNode/NodeModelBaseFunc.cs b/Library/FlowNode/NodeModelBaseFunc.cs
index bd2a1d8..c836087 100644
--- a/Library/FlowNode/NodeModelBaseFunc.cs
+++ b/Library/FlowNode/NodeModelBaseFunc.cs
@@ -81,7 +81,7 @@ namespace Serein.Library
}
this.MethodDetails.ParameterDetailss = null;
- this.MethodDetails.ActingInstance = null;
+ //this.MethodDetails.ActingInstance = null;
this.MethodDetails.NodeModel = null;
this.MethodDetails.ReturnType = null;
this.MethodDetails.AssemblyName = null;
@@ -249,43 +249,46 @@ namespace Serein.Library
///
///
///
- public static bool IsBradk(IDynamicContext context, CancellationTokenSource flowCts)
- {
- // 上下文不再执行
- if (context.RunState == RunState.Completion)
- {
- return true;
- }
+ //public static bool IsBradk(IDynamicContext context)
+ //{
+ // // 上下文不再执行
+ // if (context.RunState == RunState.Completion)
+ // {
+ // return true;
+ // }
- // 不存在全局触发器时,流程运行状态被设置为完成,退出执行,用于打断无限循环分支。
- if (flowCts is null && context.Env.FlowState == RunState.Completion)
- {
- return true;
- }
+ // // 不存在全局触发器时,流程运行状态被设置为完成,退出执行,用于打断无限循环分支。
+ // if (flowCts is null && context.Env.FlowState == RunState.Completion)
+ // {
+ // return true;
+ // }
- // 如果存在全局触发器,且触发器的执行任务已经被取消时,退出执行。
- if (flowCts != null)
- {
- if (flowCts.IsCancellationRequested)
- return true;
- }
- return false;
- }
+ // // 如果存在全局触发器,且触发器的执行任务已经被取消时,退出执行。
+ // if (flowCts != null)
+ // {
+ // if (flowCts.IsCancellationRequested)
+ // return true;
+ // }
+ // return false;
+ //}
///
/// 开始执行
///
///
+ /// 流程运行
///
- public async Task StartFlowAsync(IDynamicContext context)
+ public async Task StartFlowAsync(IDynamicContext context, CancellationToken token)
{
Stack stack = new Stack();
HashSet processedNodes = new HashSet(); // 用于记录已处理上游节点的节点
stack.Push(this);
- var flowCts = context.Env.IOC.Get(NodeStaticConfig.FlipFlopCtsName);
- bool hasFlipflow = flowCts != null;
- while (stack.Count > 0) // 循环中直到栈为空才会退出循环
+ while (context.RunState != RunState.Completion // 没有完成
+ && token.IsCancellationRequested == false // 没有取消
+ && stack.Count > 0) // 循环中直到栈为空才会退出循环
{
+
+
#if DEBUG
await Task.Delay(1);
#endif
@@ -299,15 +302,12 @@ namespace Serein.Library
object newFlowData;
try
{
+ newFlowData = await currentNode.ExecutingAsync(context, token);
- 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)
{
@@ -316,9 +316,7 @@ namespace Serein.Library
context.NextOrientation = ConnectionInvokeType.IsError;
context.ExceptionOfRuning = ex;
}
-
-
- await RefreshFlowDataAndExpInterrupt(context, currentNode, newFlowData); // 执行当前节点后刷新数据
+ context.AddOrUpdate(currentNode.Guid, newFlowData); // 上下文中更新数据
#endregion
#region 执行完成
@@ -355,14 +353,10 @@ namespace Serein.Library
///
/// 流程上下文
/// 节点传回数据对象
- public virtual async Task
public Task ExitFlowAsync()
{
- flowStarter?.Exit();
+ flowTaskManagement?.Exit();
UIContextOperation?.Invoke(() => OnFlowRunComplete?.Invoke(new FlowEventArgs()));
IOC.Reset();
- flowStarter = null;
+ flowTaskManagement = null;
GC.Collect();
return Task.FromResult(true);
}
@@ -480,12 +498,12 @@ namespace Serein.NodeFlow.Env
{
var nodeModel = GuidToModel(nodeGuid);
if (nodeModel is null) return;
- if (flowStarter is not null && nodeModel is SingleFlipflopNode flipflopNode) // 子节点为触发器
+ if (flowTaskManagement is not null && nodeModel is SingleFlipflopNode flipflopNode) // 子节点为触发器
{
if (FlowState != RunState.Completion
&& flipflopNode.NotExitPreviousNode()) // 正在运行,且该触发器没有上游节点
{
- _ = flowStarter.RunGlobalFlipflopAsync(this, flipflopNode);// 被父节点移除连接关系的子节点若为触发器,且无上级节点,则当前流程正在运行,则加载到运行环境中
+ _ = flowTaskManagement.RunGlobalFlipflopAsync(this, flipflopNode);// 被父节点移除连接关系的子节点若为触发器,且无上级节点,则当前流程正在运行,则加载到运行环境中
}
}
@@ -499,9 +517,9 @@ namespace Serein.NodeFlow.Env
{
var nodeModel = GuidToModel(nodeGuid);
if (nodeModel is null) return;
- if (flowStarter is not null && nodeModel is SingleFlipflopNode flipflopNode) // 子节点为触发器
+ if (flowTaskManagement is not null && nodeModel is SingleFlipflopNode flipflopNode) // 子节点为触发器
{
- flowStarter.TerminateGlobalFlipflopRuning(flipflopNode);
+ flowTaskManagement.TerminateGlobalFlipflopRuning(flipflopNode);
}
}
@@ -793,7 +811,7 @@ namespace Serein.NodeFlow.Env
}
#endregion
- var nodeModel = FlowFunc.CreateNode(this, controlType, methodDetails); // 加载项目时创建节点
+ var nodeModel = FlowNodeExtension.CreateNode(this, controlType, methodDetails); // 加载项目时创建节点
if (nodeModel is null)
{
nodeInfo.Guid = string.Empty;
@@ -926,7 +944,7 @@ namespace Serein.NodeFlow.Env
NodeModelBase? nodeModel;
if (methodDetailsInfo is null)
{
- nodeModel = FlowFunc.CreateNode(this, nodeControlType); // 加载基础节点
+ nodeModel = FlowNodeExtension.CreateNode(this, nodeControlType); // 加载基础节点
}
else
{
@@ -934,7 +952,7 @@ namespace Serein.NodeFlow.Env
methodDetailsInfo.MethodName,
out var methodDetails))
{
- nodeModel = FlowFunc.CreateNode(this, nodeControlType, methodDetails); // 一般的加载节点方法
+ nodeModel = FlowNodeExtension.CreateNode(this, nodeControlType, methodDetails); // 一般的加载节点方法
}
else
{
@@ -1032,7 +1050,7 @@ namespace Serein.NodeFlow.Env
if (remoteNode is SingleFlipflopNode flipflopNode)
{
- flowStarter?.TerminateGlobalFlipflopRuning(flipflopNode); // 假设被移除的是全局触发器,尝试从启动器移除
+ flowTaskManagement?.TerminateGlobalFlipflopRuning(flipflopNode); // 假设被移除的是全局触发器,尝试从启动器移除
}
remoteNode.Remove(); // 调用节点的移除方法
@@ -1689,7 +1707,7 @@ namespace Serein.NodeFlow.Env
if (toNode is SingleFlipflopNode flipflopNode)
{
- flowStarter?.TerminateGlobalFlipflopRuning(flipflopNode); // 假设被连接的是全局触发器,尝试移除
+ flowTaskManagement?.TerminateGlobalFlipflopRuning(flipflopNode); // 假设被连接的是全局触发器,尝试移除
}
var isPass = false;
@@ -1896,10 +1914,10 @@ namespace Serein.NodeFlow.Env
{
return (T)sereinIOC.Get(typeof(T));
}
- T ISereinIOC.Get(string key)
- {
- return sereinIOC.Get(key);
- }
+ //T ISereinIOC.Get(string key)
+ //{
+ // return sereinIOC.Get(key);
+ //}
bool ISereinIOC.RegisterPersistennceInstance(string key, object instance)
@@ -1908,10 +1926,10 @@ namespace Serein.NodeFlow.Env
return sereinIOC.RegisterPersistennceInstance(key, instance);
}
- bool ISereinIOC.RegisterInstance(string key, object instance)
- {
- return sereinIOC.RegisterInstance(key, instance);
- }
+ //bool ISereinIOC.RegisterInstance(string key, object instance)
+ //{
+ // return sereinIOC.RegisterInstance(key, instance);
+ //}
object ISereinIOC.Instantiate(Type type)
diff --git a/NodeFlow/Env/FlowEnvironmentDecorator.cs b/NodeFlow/Env/FlowEnvironmentDecorator.cs
index 6fffc02..8cc8b48 100644
--- a/NodeFlow/Env/FlowEnvironmentDecorator.cs
+++ b/NodeFlow/Env/FlowEnvironmentDecorator.cs
@@ -102,7 +102,7 @@ namespace Serein.NodeFlow.Env
///
public InfoClass InfoClass { get => currentFlowEnvironment.InfoClass; set => currentFlowEnvironment.InfoClass = value; }
public RunState FlowState { get => currentFlowEnvironment.FlowState; set => currentFlowEnvironment.FlowState = value; }
- public RunState FlipFlopState { get => currentFlowEnvironment.FlipFlopState; set => currentFlowEnvironment.FlipFlopState = value; }
+ //public RunState FlipFlopState { get => currentFlowEnvironment.FlipFlopState; set => currentFlowEnvironment.FlipFlopState = value; }
public event LoadDllHandler OnDllLoad {
add { currentFlowEnvironmentEvent.OnDllLoad += value; }
@@ -607,10 +607,10 @@ namespace Serein.NodeFlow.Env
return IOC.RegisterPersistennceInstance(key, instance);
}
- public bool RegisterInstance(string key, object instance)
- {
- return IOC.RegisterInstance(key, instance);
- }
+ //public bool RegisterInstance(string key, object instance)
+ //{
+ // return IOC.RegisterInstance(key, instance);
+ //}
public object Get(Type type)
{
@@ -622,10 +622,10 @@ namespace Serein.NodeFlow.Env
return IOC.Get();
}
- public T Get(string key)
- {
- return IOC.Get(key);
- }
+ //public T Get(string key)
+ //{
+ // return IOC.Get(key);
+ //}
public object Instantiate(Type type)
{
diff --git a/NodeFlow/Env/RemoteFlowEnvironment.cs b/NodeFlow/Env/RemoteFlowEnvironment.cs
index ebadaf1..e0d63b9 100644
--- a/NodeFlow/Env/RemoteFlowEnvironment.cs
+++ b/NodeFlow/Env/RemoteFlowEnvironment.cs
@@ -784,7 +784,7 @@ namespace Serein.NodeFlow.Env
}
//MethodDetailss.TryGetValue(methodDetailsInfo.MethodName, out var methodDetails);// 加载项目时尝试获取方法信息
- var nodeModel = FlowFunc.CreateNode(this, nodeControlType, methodDetails); // 远程环境下加载节点
+ var nodeModel = FlowNodeExtension.CreateNode(this, nodeControlType, methodDetails); // 远程环境下加载节点
nodeModel.LoadInfo(nodeInfo);
TryAddNode(nodeModel);
IsLoadingNode = false;
@@ -1098,7 +1098,7 @@ namespace Serein.NodeFlow.Env
}
#endregion
- var nodeModel = FlowFunc.CreateNode(this, controlType, methodDetails); // 加载项目时创建节点
+ var nodeModel = FlowNodeExtension.CreateNode(this, controlType, methodDetails); // 加载项目时创建节点
if (nodeModel is null)
{
nodeInfo.Guid = string.Empty;
diff --git a/NodeFlow/FlowFunc.cs b/NodeFlow/FlowNodeExtension.cs
similarity index 77%
rename from NodeFlow/FlowFunc.cs
rename to NodeFlow/FlowNodeExtension.cs
index 2609bca..dbf9c44 100644
--- a/NodeFlow/FlowFunc.cs
+++ b/NodeFlow/FlowNodeExtension.cs
@@ -12,7 +12,7 @@ namespace Serein.NodeFlow
///
/// 流程环境需要的扩展方法
///
- public static class FlowFunc
+ public static class FlowNodeExtension
{
///
/// 判断是否为基础节点
@@ -71,37 +71,6 @@ namespace Serein.NodeFlow
- /////
- ///// 从节点信息读取节点类型
- /////
- /////
- /////
- /////
- //public static NodeControlType GetNodeControlType(NodeInfo nodeInfo)
- //{
- // if(!EnumHelper.TryConvertEnum(nodeInfo.Type, out var controlType))
- // {
- // return NodeControlType.None;
- // }
- // return controlType;
- // // 创建控件实例
- // //NodeControlType controlType = nodeInfo.Type switch
- // //{
- // // $"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleActionNode)}" => NodeControlType.Action,// 动作节点控件
- // // $"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleFlipflopNode)}" => NodeControlType.Flipflop, // 触发器节点控件
-
- // // $"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleConditionNode)}" => NodeControlType.ExpCondition,// 条件表达式控件
- // // $"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleExpOpNode)}" => NodeControlType.ExpOp, // 操作表达式控件
-
- // // $"{NodeStaticConfig.NodeSpaceName}.{nameof(CompositeConditionNode)}" => NodeControlType.ConditionRegion, // 条件区域控件
-
- // // $"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleGlobalDataNode)}" => NodeControlType.GlobalData, // 数据节点
- // // $"{NodeStaticConfig.NodeSpaceName}.{nameof(SingleScriptNode)}" => NodeControlType.Script, // 数据节点
- // // _ => NodeControlType.None,
- // //};
- // //return controlType;
- //}
-
///
/// 程序集封装依赖
///
diff --git a/NodeFlow/FlowStarter.cs b/NodeFlow/FlowStarter.cs
deleted file mode 100644
index 4f8f127..0000000
--- a/NodeFlow/FlowStarter.cs
+++ /dev/null
@@ -1,413 +0,0 @@
-using Serein.Library;
-using Serein.Library.Api;
-using Serein.Library.Utils;
-using Serein.NodeFlow.Model;
-using Serein.NodeFlow.Tool;
-using System.Collections.Concurrent;
-
-namespace Serein.NodeFlow
-{
- ///
- /// 流程启动器
- ///
- public class FlowStarter
- {
- ///
- /// 控制所有全局触发器的结束
- ///
- private CancellationTokenSource? _flipFlopCts;
-
- ///
- /// 是否停止启动
- ///
- private bool IsStopStart = false;
-
- ///
- /// 结束运行时需要执行的方法
- ///
- private Func? ExitAction { get; set; }
-
- ///
- /// 从选定的节点开始运行
- ///
- ///
- ///
- ///
- public async Task StartFlowInSelectNodeAsync(IFlowEnvironment env, NodeModelBase startNode)
- {
- IDynamicContext context;
- context = new Serein.Library.DynamicContext(env); // 从起始节点启动流程时创建上下文
- await startNode.StartFlowAsync(context); // 开始运行时从选定节点开始运行
- context.Exit();
- }
-
-
- ///
- /// 开始运行(需要准备好方法信息)
- ///
- /// 运行环境
- /// 环境中已加载的所有节点
- /// 初始化方法
- /// 加载时方法
- /// 结束时方法
- ///
- public async Task RunAsync(IFlowEnvironment env,
- List nodes,
- Dictionary> autoRegisterTypes,
- List initMethods,
- List loadingMethods,
- List exitMethods)
- {
-
- #region 注册基本类
- env.IOC.Register(); // 注册脚本接口
- #endregion
-
- env.FlowState = RunState.Running; // 开始运行
- NodeModelBase? startNode = nodes.FirstOrDefault(node => node.IsStart);
- if (startNode is null) {
- env.FlowState = RunState.Completion; // 不存在起点,退出流程
- return;
- }
-
- #region 获取所有触发器,以及已加载节点的方法信息
- List runNodeMd;
- List flipflopNodes;
-
- flipflopNodes = nodes.Where(it => it.MethodDetails?.MethodDynamicType == NodeType.Flipflop && it.IsStart == false)
- .Select(it => (SingleFlipflopNode)it)
- .Where(node => node.DebugSetting.IsEnable && node is SingleFlipflopNode flipflopNode && flipflopNode.NotExitPreviousNode())
- .ToList();// 获取需要再运行开始之前启动的触发器节点
- runNodeMd = nodes.Select(item => item.MethodDetails).ToList(); // 获取环境中所有节点的方法信息
-
-
- #endregion
-
- #region 选择运行环境的上下文
-
- // 判断使用哪一种流程上下文
- IDynamicContext Context = new Serein.Library.DynamicContext(env); // 从起始节点启动流程时创建上下文
- #endregion
-
- #region 初始化运行环境的Ioc容器
-
- // 清除节点使用的对象,筛选出需要初始化的方法描述
- var thisRuningMds = new List();
- thisRuningMds.AddRange(runNodeMd.Where(md => md?.ActingInstanceType is not null));
- thisRuningMds.AddRange(initMethods.Where(md => md?.ActingInstanceType is not null));
- thisRuningMds.AddRange(loadingMethods.Where(md => md?.ActingInstanceType is not null));
- thisRuningMds.AddRange(exitMethods.Where(md => md?.ActingInstanceType is not null));
-
-
- foreach (var nodeMd in thisRuningMds)
- {
- nodeMd.ActingInstance = null;
- }
-
- // 初始化ioc容器中的类型对象
- foreach (var md in thisRuningMds)
- {
- if (md.ActingInstanceType != null)
- {
- env.IOC.Register(md.ActingInstanceType);
- }
- else
- {
- await Console.Out.WriteLineAsync($"{md.MethodName} - 没有类型声明");
- IsStopStart = true;
- }
- }
-
- if (IsStopStart) return;// 检查所有dll节点是否存在类型
-
- env.IOC.Build(); // 流程启动前的初始化
-
- foreach (var md in thisRuningMds)
- {
- md.ActingInstance = env.IOC.Get(md.ActingInstanceType);
- if(md.ActingInstance is null)
- {
- await Console.Out.WriteLineAsync($"{md.MethodName} - 无法获取类型[{md.ActingInstanceType}]的实例");
- IsStopStart = true;
- }
- }
- if (IsStopStart)
- {
- return;// 调用节点初始化后检查状态
- }
-
-
- #endregion
-
- #region 执行初始化,绑定IOC容器,再执行加载时
-
- if (autoRegisterTypes.TryGetValue(RegisterSequence.FlowInit, out var flowInitTypes))
- {
- foreach (var type in flowInitTypes)
- {
- env.IOC.Register(type); // 初始化前注册
- }
- }
- Context.Env.IOC.Build(); // 绑定初始化时注册的类型
- //object?[]? args = [Context];
- foreach (var md in initMethods) // 初始化
- {
- if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) // 流程运行初始化
- {
- throw new Exception("不存在对应委托");
- }
- await dd.InvokeAsync(md.ActingInstance, [Context]);
- //((Func)dd.EmitDelegate).Invoke(md.ActingInstance, [Context]);
- }
- Context.Env.IOC.Build(); // 绑定初始化时注册的类型
-
- if(autoRegisterTypes.TryGetValue(RegisterSequence.FlowLoading,out var flowLoadingTypes))
- {
- foreach (var type in flowLoadingTypes)
- {
- env.IOC.Register(type); // 初始化前注册
- }
- }
- Context.Env.IOC.Build(); // 绑定初始化时注册的类型
- foreach (var md in loadingMethods) // 加载
- {
- //object?[]? data = [md.ActingInstance, args];
- //md.MethodDelegate.DynamicInvoke(data);
- if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) // 流程运行正在加载
- {
- throw new Exception("不存在对应委托");
- }
- await dd.InvokeAsync(md.ActingInstance, [Context]);
- //((Action)del).Invoke(md.ActingInstance, [Context]);
- //((Func)dd.EmitDelegate).Invoke(md.ActingInstance, [Context]);
- }
- Context.Env.IOC.Build(); // 预防有人在加载时才注册类型,再绑定一次
- #endregion
-
- #region 设置流程退出时的回调函数
- ExitAction = async () =>
- {
- //env.IOC.Run(web => {
- // web?.Stop();
- //});
- //env.IOC.Run(server => {
- // server?.Stop();
- //});
-
- foreach (MethodDetails? md in exitMethods)
- {
- if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) // 流程运行退出执行
- {
- throw new Exception("不存在对应委托");
- }
- await dd.InvokeAsync(md.ActingInstance, [Context]);
- }
-
- if (_flipFlopCts != null && !_flipFlopCts.IsCancellationRequested)
- {
- _flipFlopCts?.Cancel();
- _flipFlopCts?.Dispose();
- } // 通知所有流程上下文停止运行
- TerminateAllGlobalFlipflop(); // 确保所有触发器不再运行
- SereinEnv.ClearFlowGlobalData(); // 清空全局数据缓存
- NativeDllHelper.FreeLibrarys(); // 卸载所有已加载的 Native Dll
- env.IOC.Run(fit => fit.CancelAllTrigger());// 取消所有中断
- env.FlowState = RunState.Completion;
- env.FlipFlopState = RunState.Completion;
-
- };
- #endregion
-
- #region 开始启动流程
-
- try
- {
- //await TestScript(env);
- await startNode.StartFlowAsync(Context); // 开始运行时从起始节点开始运行
-
- if (flipflopNodes.Count > 0)
- {
- env.FlipFlopState = RunState.Running;
- // 如果存在需要启动的触发器,则开始启动
- _flipFlopCts = new CancellationTokenSource();
- env.IOC.RegisterInstance(NodeStaticConfig.FlipFlopCtsName, _flipFlopCts);
-
- // 使用 TaskCompletionSource 创建未启动的触发器任务
- var tasks = flipflopNodes.Select(async node =>
- {
- await RunGlobalFlipflopAsync(env,node); // 启动流程时启动全局触发器
- }).ToArray();
- _ = Task.WhenAll(tasks);
- }
-
-
- // 等待结束
- if(env.FlipFlopState == RunState.Running && _flipFlopCts is not null)
- {
- while (!_flipFlopCts.IsCancellationRequested)
- {
- await Task.Delay(100);
- }
- }
- }
- catch (Exception ex)
- {
- await Console.Out.WriteLineAsync(ex.ToString());
- }
- finally
- {
- env.FlowState = RunState.Completion;
- SereinEnv.WriteLine(InfoType.INFO, $"流程运行完毕{Environment.NewLine}");;
- }
- #endregion
- }
-
- private ConcurrentDictionary dictGlobalFlipflop = [];
-
- ///
- /// 尝试添加全局触发器
- ///
- ///
- ///
- public async Task RunGlobalFlipflopAsync(IFlowEnvironment env, SingleFlipflopNode singleFlipFlopNode)
- {
- if (dictGlobalFlipflop.TryAdd(singleFlipFlopNode, new CancellationTokenSource()))
- {
- singleFlipFlopNode.MethodDetails.ActingInstance ??= env.IOC.Get(singleFlipFlopNode.MethodDetails.ActingInstanceType);
- await FlipflopExecuteAsync(env, singleFlipFlopNode, dictGlobalFlipflop[singleFlipFlopNode]);
- }
- }
-
- ///
- /// 尝试移除全局触发器
- ///
- ///
- public void TerminateGlobalFlipflopRuning(SingleFlipflopNode singleFlipFlopNode)
- {
- if (dictGlobalFlipflop.TryRemove(singleFlipFlopNode, out var cts))
- {
- if (!cts.IsCancellationRequested)
- {
- cts.Cancel();
- }
- cts.Dispose();
- }
- }
-
- ///
- /// 终结所有全局触发器
- ///
- private void TerminateAllGlobalFlipflop()
- {
- foreach ((var node, var cts) in dictGlobalFlipflop)
- {
- if (!cts.IsCancellationRequested)
- {
- cts.Cancel();
- }
- cts.Dispose();
- }
- dictGlobalFlipflop.Clear();
- }
-
- ///
- /// 启动全局触发器
- ///
- /// 流程运行全局环境
- /// 需要全局监听信号的触发器
- ///
- private async Task FlipflopExecuteAsync(IFlowEnvironment env,
- SingleFlipflopNode singleFlipFlopNode,
- CancellationTokenSource cts)
- {
- if(_flipFlopCts is null)
- {
- SereinEnv.WriteLine(InfoType.INFO, "流程尚未启动,flowStarter尚未创建,无法启动该节点");
- return;
- }
-
- while (!_flipFlopCts.IsCancellationRequested && !cts.IsCancellationRequested)
- {
- try
- {
- var context = new Library.DynamicContext(env); // 启动全局触发器时新建上下文
- var newFlowData = await singleFlipFlopNode.ExecutingAsync(context); // 获取触发器等待Task
- context.AddOrUpdate(singleFlipFlopNode.Guid, newFlowData);
- await NodeModelBase.RefreshFlowDataAndExpInterrupt(context, singleFlipFlopNode, newFlowData); // 全局触发器触发后刷新该触发器的节点数据
- if (context.NextOrientation == ConnectionInvokeType.None)
- {
- continue;
- }
- _ = Task.Run(async () => {
- var nextNodes = singleFlipFlopNode.SuccessorNodes[context.NextOrientation];
- for (int i = nextNodes.Count - 1; i >= 0 && !_flipFlopCts.IsCancellationRequested; i--)
- {
- // 筛选出启用的节点
- if (!nextNodes[i].DebugSetting.IsEnable)
- {
- continue ;
- }
-
- context.SetPreviousNode(nextNodes[i], singleFlipFlopNode);
- if (nextNodes[i].DebugSetting.IsInterrupt) // 执行触发前
- {
- await nextNodes[i].DebugSetting.GetInterruptTask.Invoke();
- await Console.Out.WriteLineAsync($"[{nextNodes[i].MethodDetails.MethodName}]中断已取消,开始执行后继分支");
- }
- await nextNodes[i].StartFlowAsync(context); // 启动执行触发器后继分支的节点
- }
-
- nextNodes = singleFlipFlopNode.SuccessorNodes[ConnectionInvokeType.Upstream];
- for (int i = nextNodes.Count - 1; i >= 0 && !_flipFlopCts.IsCancellationRequested; i--)
- {
- // 筛选出启用的节点
- if (!nextNodes[i].DebugSetting.IsEnable)
- {
- continue;
- }
-
- context.SetPreviousNode(nextNodes[i], singleFlipFlopNode);
- if (nextNodes[i].DebugSetting.IsInterrupt) // 执行触发前
- {
- await nextNodes[i].DebugSetting.GetInterruptTask.Invoke();
- await Console.Out.WriteLineAsync($"[{nextNodes[i].MethodDetails.MethodName}]中断已取消,开始执行后继分支");
- }
- await nextNodes[i].StartFlowAsync(context); // 启动执行触发器后继分支的节点
- }
-
- context.Exit();
- });
-
- }
- catch (FlipflopException ex)
- {
- SereinEnv.WriteLine(InfoType.ERROR, $"触发器[{singleFlipFlopNode.MethodDetails.MethodName}]因非预期异常终止。"+ex.Message);
- if (ex.Type == FlipflopException.CancelClass.CancelFlow)
- {
- break;
- }
- }
- catch (Exception ex)
- {
- SereinEnv.WriteLine(InfoType.ERROR, $"触发器[{singleFlipFlopNode.Guid}]异常。"+ ex.Message);
- await Task.Delay(1000);
- }
- }
-
- }
-
- ///
- /// 结束流程
- ///
- public void Exit()
- {
- ExitAction?.Invoke();
-
- }
-
- }
-}
-
-
-
-
diff --git a/NodeFlow/FlowTaskLibrary.cs b/NodeFlow/FlowTaskLibrary.cs
new file mode 100644
index 0000000..f6eb5c1
--- /dev/null
+++ b/NodeFlow/FlowTaskLibrary.cs
@@ -0,0 +1,52 @@
+using Microsoft.Extensions.ObjectPool;
+using Serein.Library;
+using Serein.Library.Api;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Serein.NodeFlow
+{
+
+ public class FlowTaskLibrary()
+ {
+ ///
+ /// 流程运行环境
+ ///
+ public IFlowEnvironment Environment { get; set; }// = environment;
+
+ ///
+ /// 表示运行环境状态
+ ///
+ public CancellationTokenSource CancellationTokenSource { get; } = new CancellationTokenSource();
+
+ ///
+ /// 上下文线程池
+ ///
+ public Serein.Library.Utils.ObjectPool FlowContextPool { get; set; }
+
+ ///
+ /// 当前任务加载的所有节点
+ ///
+ public List Nodes { get; set; }// = nodes;
+ ///
+ /// 需要注册的类型
+ ///
+ public Dictionary> AutoRegisterTypes { get; set; } //= autoRegisterTypes;
+ ///
+ /// 初始化时需要的方法
+ ///
+ public List InitMds { get; set; }// = initMds;
+ ///
+ /// 加载时需要的方法
+ ///
+ public List LoadMds { get; set; }// = loadMds;
+ ///
+ /// 退出时需要调用的方法
+ ///
+ public List ExitMds { get; set; } //= exitMds;
+ }
+
+}
diff --git a/NodeFlow/FlowWorkManagement.cs b/NodeFlow/FlowWorkManagement.cs
new file mode 100644
index 0000000..2953505
--- /dev/null
+++ b/NodeFlow/FlowWorkManagement.cs
@@ -0,0 +1,386 @@
+using Microsoft.CodeAnalysis;
+using Serein.Library;
+using Serein.Library.Api;
+using Serein.Library.Utils;
+using Serein.NodeFlow.Model;
+using Serein.NodeFlow.Tool;
+using System;
+using System.Collections.Concurrent;
+using System.Xml.Linq;
+
+namespace Serein.NodeFlow
+{
+ ///
+ /// 流程任务管理
+ ///
+ public class FlowWorkManagement
+ {
+ ///
+ /// 触发器对应的Cts
+ ///
+ private ConcurrentDictionary dictGlobalFlipflop = [];
+
+
+
+
+ ///
+ /// 结束运行时需要执行的方法
+ ///
+ private Func? ExitAction { get; set; }
+ ///
+ /// 初始化选项
+ ///
+ public FlowTaskLibrary WorkLibrary { get; }
+
+ ///
+ /// 流程任务管理
+ ///
+ ///
+ public FlowWorkManagement(FlowTaskLibrary library)
+ {
+ WorkLibrary = library;
+
+ }
+
+ ///
+ /// 初始化啊
+ ///
+ ///
+ public async Task RunAsync(CancellationToken token)
+ {
+ NodeModelBase? startNode = WorkLibrary.Nodes.FirstOrDefault(node => node.IsStart);
+ if (startNode is null)
+ {
+ return false;
+ }
+
+ if (!RegisterAllType())
+ {
+ return false;
+ };
+ var initState = await TryInit();
+ if (!initState)
+ {
+ return false;
+ };
+ var loadState = await TryLoadAsync();
+ if (!loadState)
+ {
+ return false;
+ };
+ var task = CallFlipflopNode();
+ await CallStartNode(startNode);
+ await task;
+ await CallExit();
+ return true;
+ }
+
+ #region 初始化
+ private bool RegisterAllType()
+ {
+ var env = WorkLibrary.Environment;
+ var nodeMds = WorkLibrary.Nodes.Select(item => item.MethodDetails).ToList(); // 获取环境中所有节点的方法信息
+ var allMds = new List();
+ allMds.AddRange(nodeMds.Where(md => md?.ActingInstanceType is not null));
+ allMds.AddRange(WorkLibrary.InitMds.Where(md => md?.ActingInstanceType is not null));
+ allMds.AddRange(WorkLibrary.LoadMds.Where(md => md?.ActingInstanceType is not null));
+ allMds.AddRange(WorkLibrary.ExitMds.Where(md => md?.ActingInstanceType is not null));
+ var isSuccessful = true;
+ foreach (var md in allMds)
+ {
+ if (md.ActingInstanceType != null)
+ {
+ env.IOC.Register(md.ActingInstanceType);
+ }
+ else
+ {
+ SereinEnv.WriteLine(InfoType.ERROR, "{md.MethodName} - 没有类型声明");
+ isSuccessful = false ;
+ }
+ }
+ env.IOC.Build(); // 绑定初始化时注册的类型
+ foreach (var md in allMds)
+ {
+ var instance = env.IOC.Get(md.ActingInstanceType);
+ if (instance is null)
+ {
+ SereinEnv.WriteLine(InfoType.ERROR, $"{md.MethodName} - 无法获取类型[{md.ActingInstanceType}]的实例");
+ isSuccessful = false;
+ }
+ }
+
+ return isSuccessful;
+ }
+
+ private async Task TryInit()
+ {
+ var env = WorkLibrary.Environment;
+ var initMds = WorkLibrary.InitMds;
+ var pool = WorkLibrary.FlowContextPool;
+ var ioc = WorkLibrary.Environment.IOC;
+ foreach (var md in initMds) // 初始化
+ {
+ if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) // 流程运行初始化
+ {
+ throw new Exception("不存在对应委托");
+ }
+ var context = pool.Allocate();
+ var instance = ioc.Get(md.ActingInstanceType);
+ await dd.InvokeAsync(instance, [context]);
+ context.Reset();
+ pool.Free(context);
+ }
+ env.IOC.Build(); // 绑定初始化时注册的类型
+ var isSuccessful = true;
+ return isSuccessful;
+ }
+ private async Task TryLoadAsync()
+ {
+ var env = WorkLibrary.Environment;
+ var loadMds = WorkLibrary.LoadMds;
+ var pool = WorkLibrary.FlowContextPool;
+ var ioc = WorkLibrary.Environment.IOC;
+ foreach (var md in loadMds) // 加载时
+ {
+ if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) // 流程运行初始化
+ {
+ throw new Exception("不存在对应委托");
+ }
+ var context = pool.Allocate();
+ var instance = ioc.Get(md.ActingInstanceType);
+ await dd.InvokeAsync(instance, [context]);
+ context.Reset();
+ pool.Free(context);
+ }
+ env.IOC.Build(); // 绑定初始化时注册的类型
+ var isSuccessful = true;
+ return isSuccessful;
+
+ }
+ private async Task CallExit()
+ {
+ var env = WorkLibrary.Environment;
+ var mds = WorkLibrary.ExitMds;
+ var pool = WorkLibrary.FlowContextPool;
+ var ioc = WorkLibrary.Environment.IOC;
+
+ ioc.Run(fit => fit.CancelAllTrigger());// 取消所有中断
+ foreach (var md in mds) // 结束时
+ {
+ if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) // 流程运行初始化
+ {
+ throw new Exception("不存在对应委托");
+ }
+ var context = pool.Allocate();
+ var instance = ioc.Get(md.ActingInstanceType);
+ await dd.InvokeAsync(instance, [context]);
+ context.Reset();
+ pool.Free(context);
+ }
+
+ TerminateAllGlobalFlipflop(); // 确保所有触发器不再运行
+ SereinEnv.ClearFlowGlobalData(); // 清空全局数据缓存
+ NativeDllHelper.FreeLibrarys(); // 卸载所有已加载的 Native Dll
+
+ var isSuccessful = true;
+ return isSuccessful;
+ }
+
+ private Task CallFlipflopNode()
+ {
+ var env = WorkLibrary.Environment;
+ var flipflopNodes = WorkLibrary.Nodes.Where(item => item is SingleFlipflopNode node
+ && !node.IsStart
+ && node.DebugSetting.IsEnable
+ && node.NotExitPreviousNode())
+ .Select(item => (SingleFlipflopNode)item);
+ //.ToList();// 获取需要再运行开始之前启动的触发器节点
+
+ if (flipflopNodes.Count() > 0)
+ {
+ var tasks = flipflopNodes.Select(async node =>
+ {
+ await RunGlobalFlipflopAsync(env, node); // 启动流程时启动全局触发器
+ });
+ Task.WhenAll(tasks);
+ }
+ return Task.CompletedTask;
+ }
+ private async Task CallStartNode(NodeModelBase startNode)
+ {
+ var pool = WorkLibrary.FlowContextPool;
+ var token = WorkLibrary.CancellationTokenSource.Token;
+ var context = pool.Allocate();
+ await startNode.StartFlowAsync(context, token);
+ context.Exit();
+ pool.Free(context);
+ return;
+ }
+
+ #endregion
+
+ ///
+ /// 从选定的节点开始运行
+ ///
+ ///
+ ///
+ ///
+ public async Task StartFlowInSelectNodeAsync(IFlowEnvironment env, NodeModelBase startNode)
+ {
+ var pool = WorkLibrary.FlowContextPool;
+ var context = pool.Allocate();
+ var token = WorkLibrary.CancellationTokenSource.Token;
+ await startNode.StartFlowAsync(context, token); // 开始运行时从选定节点开始运行
+ context.Reset();
+ pool.Free(context);
+ }
+
+
+
+
+ ///
+ /// 尝试添加全局触发器
+ ///
+ ///
+ ///
+ public async Task RunGlobalFlipflopAsync(IFlowEnvironment env, SingleFlipflopNode singleFlipFlopNode)
+ {
+ if (dictGlobalFlipflop.TryAdd(singleFlipFlopNode, new CancellationTokenSource()))
+ {
+ var cts = dictGlobalFlipflop[singleFlipFlopNode];
+ await FlipflopExecuteAsync(singleFlipFlopNode, cts.Token);
+ }
+ }
+
+ ///
+ /// 尝试移除全局触发器
+ ///
+ ///
+ public void TerminateGlobalFlipflopRuning(SingleFlipflopNode singleFlipFlopNode)
+ {
+ if (dictGlobalFlipflop.TryRemove(singleFlipFlopNode, out var cts))
+ {
+ if (!cts.IsCancellationRequested)
+ {
+ cts.Cancel();
+ }
+ cts.Dispose();
+ }
+ }
+
+ ///
+ /// 终结所有全局触发器
+ ///
+ private void TerminateAllGlobalFlipflop()
+ {
+ foreach ((var node, var cts) in dictGlobalFlipflop)
+ {
+ if (!cts.IsCancellationRequested)
+ {
+ cts.Cancel();
+ }
+ cts.Dispose();
+ }
+ dictGlobalFlipflop.Clear();
+ }
+
+ ///
+ /// 启动全局触发器
+ ///
+ /// 需要全局监听信号的触发器
+ /// 单个触发器持有的
+ ///
+ private async Task FlipflopExecuteAsync(SingleFlipflopNode singleFlipFlopNode,
+ CancellationToken singleToken)
+ {
+
+ var pool = WorkLibrary.FlowContextPool;
+ while (!singleToken.IsCancellationRequested && !singleToken.IsCancellationRequested)
+ {
+ try
+ {
+ var context = pool.Allocate(); // 启动全局触发器时新建上下文
+ var newFlowData = await singleFlipFlopNode.ExecutingAsync(context, singleToken); // 获取触发器等待Task
+ context.AddOrUpdate(singleFlipFlopNode.Guid, newFlowData);
+ if (context.NextOrientation == ConnectionInvokeType.None)
+ {
+ continue;
+ }
+ _ = Task.Run(() => CallSubsequentNode(singleFlipFlopNode, singleToken, pool, context)); // 重新启动触发器
+
+ }
+ catch (FlipflopException ex)
+ {
+ SereinEnv.WriteLine(InfoType.ERROR, $"触发器[{singleFlipFlopNode.MethodDetails.MethodName}]因非预期异常终止。"+ex.Message);
+ if (ex.Type == FlipflopException.CancelClass.CancelFlow)
+ {
+ break;
+ }
+ }
+ catch (Exception ex)
+ {
+ SereinEnv.WriteLine(InfoType.ERROR, $"触发器[{singleFlipFlopNode.Guid}]异常。"+ ex.Message);
+ await Task.Delay(100);
+ }
+ }
+
+ }
+
+ private static async Task? CallSubsequentNode(SingleFlipflopNode singleFlipFlopNode, CancellationToken singleToken, ObjectPool pool, IDynamicContext context)
+ {
+ var flowState = context.NextOrientation; // 记录一下流程状态
+ var nextNodes = singleFlipFlopNode.SuccessorNodes[ConnectionInvokeType.Upstream]; // 优先调用上游分支
+ for (int i = nextNodes.Count - 1; i >= 0 && !singleToken.IsCancellationRequested; i--)
+ {
+ // 筛选出启用的节点
+ if (!nextNodes[i].DebugSetting.IsEnable)
+ {
+ continue;
+ }
+ context.SetPreviousNode(nextNodes[i], singleFlipFlopNode); // 设置调用关系
+
+ if (nextNodes[i].DebugSetting.IsInterrupt) // 执行触发前检查终端
+ {
+ await nextNodes[i].DebugSetting.GetInterruptTask.Invoke();
+ await Console.Out.WriteLineAsync($"[{nextNodes[i].MethodDetails.MethodName}]中断已取消,开始执行后继分支");
+ }
+ await nextNodes[i].StartFlowAsync(context, singleToken); // 启动执行触发器后继分支的节点
+ }
+
+ nextNodes = singleFlipFlopNode.SuccessorNodes[flowState]; // 调用对应分支
+ for (int i = nextNodes.Count - 1; i >= 0 && !singleToken.IsCancellationRequested; i--)
+ {
+ // 筛选出启用的节点
+ if (!nextNodes[i].DebugSetting.IsEnable)
+ {
+ continue;
+ }
+
+ context.SetPreviousNode(nextNodes[i], singleFlipFlopNode);
+ if (nextNodes[i].DebugSetting.IsInterrupt) // 执行触发前
+ {
+ await nextNodes[i].DebugSetting.GetInterruptTask.Invoke();
+ await Console.Out.WriteLineAsync($"[{nextNodes[i].MethodDetails.MethodName}]中断已取消,开始执行后继分支");
+ }
+ await nextNodes[i].StartFlowAsync(context, singleToken); // 启动执行触发器后继分支的节点
+ }
+
+ context.Reset();
+ pool.Free(context);
+ }
+
+ ///
+ /// 结束流程
+ ///
+ public void Exit()
+ {
+ ExitAction?.Invoke();
+
+ }
+
+ }
+}
+
+
+
+
diff --git a/NodeFlow/Model/CompositeConditionNode.cs b/NodeFlow/Model/CompositeConditionNode.cs
index 23cfe97..23212a2 100644
--- a/NodeFlow/Model/CompositeConditionNode.cs
+++ b/NodeFlow/Model/CompositeConditionNode.cs
@@ -36,14 +36,18 @@ namespace Serein.NodeFlow.Model
///
///
///
- public override async Task ExecutingAsync(IDynamicContext context)
+ public override async Task ExecutingAsync(IDynamicContext context, CancellationToken token)
{
try
{
// 条件区域中遍历每个条件节点
foreach (SingleConditionNode? node in ConditionNodes)
{
- var state = await node.ExecutingAsync(context);
+ if (token.IsCancellationRequested)
+ {
+ return null;
+ }
+ var state = await node.ExecutingAsync(context, token);
if (context.NextOrientation != ConnectionInvokeType.IsSucceed)
{
// 如果条件不通过,立刻推出循环
diff --git a/NodeFlow/Model/SingleConditionNode.cs b/NodeFlow/Model/SingleConditionNode.cs
index 48ee5ab..64f4dbd 100644
--- a/NodeFlow/Model/SingleConditionNode.cs
+++ b/NodeFlow/Model/SingleConditionNode.cs
@@ -110,8 +110,9 @@ namespace Serein.NodeFlow.Model
///
///
///
- public override async Task ExecutingAsync(IDynamicContext context)
+ public override async Task ExecutingAsync(IDynamicContext context, CancellationToken token)
{
+ if (token.IsCancellationRequested) return null;
// 接收上一节点参数or自定义参数内容
object? parameter;
object? result = null;
diff --git a/NodeFlow/Model/SingleExpOpNode.cs b/NodeFlow/Model/SingleExpOpNode.cs
index c7844e4..8935cbf 100644
--- a/NodeFlow/Model/SingleExpOpNode.cs
+++ b/NodeFlow/Model/SingleExpOpNode.cs
@@ -1,4 +1,5 @@
-using Serein.Library;
+using Newtonsoft.Json.Linq;
+using Serein.Library;
using Serein.Library.Api;
using Serein.Library.Utils;
using Serein.Library.Utils.SereinExpression;
@@ -91,8 +92,10 @@ namespace Serein.NodeFlow.Model
}
- public override async Task ExecutingAsync(IDynamicContext context)
+ public override async Task ExecutingAsync(IDynamicContext context, CancellationToken token)
{
+ if(token.IsCancellationRequested) return null;
+
object? parameter = null;// context.TransmissionData(this); // 表达式节点使用上一节点数据
var pd = MethodDetails.ParameterDetailss[0];
diff --git a/NodeFlow/Model/SingleFlipflopNode.cs b/NodeFlow/Model/SingleFlipflopNode.cs
index a8cc1ff..e68d5aa 100644
--- a/NodeFlow/Model/SingleFlipflopNode.cs
+++ b/NodeFlow/Model/SingleFlipflopNode.cs
@@ -1,6 +1,7 @@
using Serein.Library.Api;
using Serein.Library;
using Serein.Library.Utils;
+using System;
namespace Serein.NodeFlow.Model
{
@@ -21,7 +22,7 @@ namespace Serein.NodeFlow.Model
///
///
///
- public override async Task ExecutingAsync(IDynamicContext context)
+ public override async Task ExecutingAsync(IDynamicContext context, CancellationToken token)
{
#region 执行前中断
if (DebugSetting.IsInterrupt) // 执行触发前
@@ -37,13 +38,18 @@ namespace Serein.NodeFlow.Model
{
throw new Exception("不存在对应委托");
}
- object instance = md.ActingInstance;
- var args = await GetParametersAsync(context);
+ var instance = context.Env.IOC.Get(md.ActingInstanceType);
+ await dd.InvokeAsync(instance, [context]);
+ var args = await GetParametersAsync(context, token);
// 因为这里会返回不确定的泛型 IFlipflopContext
// 而我们只需要获取到 State 和 Value(返回的数据)
// 所以使用 dynamic 类型接收
- dynamic dynamicFlipflopContext = await dd.InvokeAsync(md.ActingInstance, args);
+ if (token.IsCancellationRequested)
+ {
+ return null;
+ }
+ dynamic dynamicFlipflopContext = await dd.InvokeAsync(instance, args);
FlipflopStateType flipflopStateType = dynamicFlipflopContext.State;
context.NextOrientation = flipflopStateType.ToContentType();
diff --git a/NodeFlow/Model/SingleGlobalDataNode.cs b/NodeFlow/Model/SingleGlobalDataNode.cs
index 56db45f..2e3f063 100644
--- a/NodeFlow/Model/SingleGlobalDataNode.cs
+++ b/NodeFlow/Model/SingleGlobalDataNode.cs
@@ -115,8 +115,9 @@ namespace Serein.NodeFlow.Model
///
///
///
- public override async Task ExecutingAsync(IDynamicContext context)
+ public override async Task ExecutingAsync(IDynamicContext context, CancellationToken token)
{
+ if (token.IsCancellationRequested) return null;
if (string.IsNullOrEmpty(KeyName))
{
context.NextOrientation = ConnectionInvokeType.IsError;
diff --git a/NodeFlow/Model/SingleScriptNode.cs b/NodeFlow/Model/SingleScriptNode.cs
index fda4f1f..a0f6129 100644
--- a/NodeFlow/Model/SingleScriptNode.cs
+++ b/NodeFlow/Model/SingleScriptNode.cs
@@ -165,13 +165,15 @@ namespace Serein.NodeFlow.Model
///
///
///
- public override async Task ExecutingAsync(IDynamicContext context)
+ public override async Task ExecutingAsync(IDynamicContext context, CancellationToken token)
{
- var @params = await GetParametersAsync(context);
-
+ if(token.IsCancellationRequested) return null;
+ var @params = await GetParametersAsync(context, token);
+ if(token.IsCancellationRequested) return null;
+
//context.AddOrUpdate($"{context.Guid}_{this.Guid}_Params", @params[0]); // 后面再改
- ReloadScript();// 每次都重新解析
+ ReloadScript();// 每次都重新解析
IScriptInvokeContext scriptContext = new ScriptInvokeContext(context);
@@ -193,6 +195,9 @@ namespace Serein.NodeFlow.Model
var envEvent = (IFlowEnvironmentEvent)context.Env;
envEvent.OnFlowRunComplete += onFlowStop; // 防止运行后台流程
+
+ if (token.IsCancellationRequested) return null;
+
var result = await ScriptInterpreter.InterpretAsync(scriptContext, mainNode); // 从入口节点执行
envEvent.OnFlowRunComplete -= onFlowStop;
//SereinEnv.WriteLine(InfoType.INFO, "FlowContext Guid : " + context.Guid);
diff --git a/NodeFlow/Model/SingleUINode.cs b/NodeFlow/Model/SingleUINode.cs
index a438f42..bbf7955 100644
--- a/NodeFlow/Model/SingleUINode.cs
+++ b/NodeFlow/Model/SingleUINode.cs
@@ -15,12 +15,13 @@ namespace Serein.NodeFlow.Model
{
}
- public override async Task ExecutingAsync(IDynamicContext context)
+ public override async Task ExecutingAsync(IDynamicContext context, CancellationToken token)
{
+ if (token.IsCancellationRequested) return null;
if(Adapter is null)
{
- var result = await base.ExecutingAsync(context);
+ var result = await base.ExecutingAsync(context, token);
if (result is IEmbeddedContent adapter)
{
this.Adapter = adapter;
@@ -39,7 +40,7 @@ namespace Serein.NodeFlow.Model
iflowContorl.OnExecuting(data);
}
- return Task.FromResult(null);
+ return null;
}
}
}
diff --git a/Workbench/App.xaml b/Workbench/App.xaml
index c5398c3..44bc631 100644
--- a/Workbench/App.xaml
+++ b/Workbench/App.xaml
@@ -3,8 +3,10 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Serein.Workbench"
xmlns:view="clr-namespace:Serein.Workbench.Views"
- StartupUri="Views/FlowWorkbenchView.xaml"
+ StartupUri="MainWindow.xaml"
Startup="Application_Startup">
+
+
diff --git a/Workbench/App.xaml.cs b/Workbench/App.xaml.cs
index 99fb86a..2b6f435 100644
--- a/Workbench/App.xaml.cs
+++ b/Workbench/App.xaml.cs
@@ -90,17 +90,19 @@ namespace Serein.Workbench
public App()
{
+ _ = Task.Run(async () =>
+ {
+ await Task.Delay(500);
+ await this.LoadLocalProjectAsync();
+ });
+ return;
var collection = new ServiceCollection();
collection.AddWorkbenchServices();
collection.AddFlowServices();
collection.AddViewModelServices();
var services = collection.BuildServiceProvider(); // 绑定并返回获取实例的服务接口
App.ServiceProvider = services;
- _ = Task.Run(async () =>
- {
- await Task.Delay(500);
- await this.LoadLocalProjectAsync();
- });
+
}
@@ -115,14 +117,14 @@ namespace Serein.Workbench
filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\Release\net8.0\PLCproject.dnf";
filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\Release\banyunqi\project.dnf";
filePath = @"F:\临时\project\project.dnf";
- filePath = @"F:\临时\flow\qrcode\project.dnf";
+ filePath = @"F:\TempFile\flow\qrcode\project.dnf";
//filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\debug\net8.0\test.dnf";
string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
App.FlowProjectData = JsonConvert.DeserializeObject(content);
App.FileDataPath = System.IO.Path.GetDirectoryName(filePath)!; // filePath;//
var dir = Path.GetDirectoryName(filePath);
- App.GetService().LoadProject(new FlowEnvInfo { Project = App.FlowProjectData },App.FileDataPath);
+ //App.GetService().LoadProject(new FlowEnvInfo { Project = App.FlowProjectData },App.FileDataPath);
}
#endif
}
diff --git a/Workbench/Node/ViewModel/ScriptNodeControlViewModel.cs b/Workbench/Node/ViewModel/ScriptNodeControlViewModel.cs
index 9783c0c..bac4fa8 100644
--- a/Workbench/Node/ViewModel/ScriptNodeControlViewModel.cs
+++ b/Workbench/Node/ViewModel/ScriptNodeControlViewModel.cs
@@ -29,7 +29,9 @@ namespace Serein.Workbench.Node.ViewModel
{
try
{
- var result = await NodeModel.ExecutingAsync(new Library.DynamicContext(nodeModel.Env));
+ var cts = new CancellationTokenSource();
+ var result = await NodeModel.ExecutingAsync(new Library.DynamicContext(nodeModel.Env), cts.Token);
+ cts.Cancel();
SereinEnv.WriteLine(InfoType.INFO, result?.ToString());
}
catch (Exception ex)
diff --git a/Workbench/Node/ViewModel/UINodeControlViewModel.cs b/Workbench/Node/ViewModel/UINodeControlViewModel.cs
index b4606d0..40e74cf 100644
--- a/Workbench/Node/ViewModel/UINodeControlViewModel.cs
+++ b/Workbench/Node/ViewModel/UINodeControlViewModel.cs
@@ -25,7 +25,9 @@ namespace Serein.Workbench.Node.ViewModel
Task.Factory.StartNew(async () =>
{
var context = new DynamicContext(NodeModel.Env);
- await NodeModel.ExecutingAsync(context);
+ var cts = new CancellationTokenSource();
+ await NodeModel.ExecutingAsync(context, cts.Token);
+ cts?.Dispose();
if (context.NextOrientation == ConnectionInvokeType.IsSucceed
&& NodeModel.Adapter.GetUserControl() is UserControl userControl)
{