From 11e4e100f003f21cfa52b82b830eaa78c831052b Mon Sep 17 00:00:00 2001
From: fengjiayi <12821976+ning_xi@user.noreply.gitee.com>
Date: Tue, 17 Sep 2024 21:43:49 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BA=86=E8=BF=90=E8=A1=8C?=
=?UTF-8?q?=E3=80=82=E5=9C=A8=E8=BF=90=E8=A1=8C=E7=8A=B6=E6=80=81=E4=B8=8B?=
=?UTF-8?q?=EF=BC=8C=E5=9C=A8=E7=94=BB=E5=B8=83=E4=B8=8A=E6=B7=BB=E5=8A=A0?=
=?UTF-8?q?=E8=A7=A6=E5=8F=91=E5=99=A8=E3=80=81=E7=A7=BB=E9=99=A4=E8=A7=A6?=
=?UTF-8?q?=E5=8F=91=E5=99=A8=E3=80=81=E6=88=96=E8=80=85=E6=B6=89=E5=8F=8A?=
=?UTF-8?q?=E5=88=B0=E8=A7=A6=E5=8F=91=E5=99=A8=E7=9A=84=E6=93=8D=E4=BD=9C?=
=?UTF-8?q?=E9=83=BD=E4=BC=9A=E5=8F=8A=E6=97=B6/=E5=BB=B6=E6=97=B6?=
=?UTF-8?q?=E7=94=9F=E6=95=88=EF=BC=88=E5=B7=B2=E7=BB=8F=E5=9C=A8=E7=AD=89?=
=?UTF-8?q?=E5=BE=85=E4=BF=A1=E5=8F=B7=E7=9A=84=E8=A7=A6=E5=8F=91=E5=99=A8?=
=?UTF-8?q?=EF=BC=8C=E5=B0=86=E4=BC=9A=E5=9C=A8=E8=A7=A6=E5=8F=91=E4=BF=A1?=
=?UTF-8?q?=E5=8F=B7=E5=90=8E=E6=89=8D=E4=BC=9A=E6=8B=BF=E5=8F=96=E6=96=B0?=
=?UTF-8?q?=E7=9A=84=E4=BF=A1=E5=8F=B7=E7=B1=BB=E5=9E=8B=E5=88=9B=E5=BB=BA?=
=?UTF-8?q?=E8=A7=A6=E5=8F=91=E4=BB=BB=E5=8A=A1=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Library/Utils/SereinIoc.cs | 2 +-
Library/Web/Router.cs | 16 +++++--
NodeFlow/FlowEnvironment.cs | 88 +++++++++++++++++++++++++------------
NodeFlow/FlowStarter.cs | 36 ++++++++++++---
README.md | 3 +-
WorkBench/App.xaml.cs | 16 +++----
6 files changed, 114 insertions(+), 47 deletions(-)
diff --git a/Library/Utils/SereinIoc.cs b/Library/Utils/SereinIoc.cs
index 012c6cf..047d391 100644
--- a/Library/Utils/SereinIoc.cs
+++ b/Library/Utils/SereinIoc.cs
@@ -141,7 +141,7 @@ namespace Serein.Library.Utils
}
///
- /// 根据类型生成对应的实例,并注入其中的依赖项(类型信息不登记到IOC容器中)
+ /// 根据类型生成对应的实例,并注入其中的依赖项(类型信息不登记到IOC容器中),类型创建后自动注入其它需要此类型的对象
///
///
///
diff --git a/Library/Web/Router.cs b/Library/Web/Router.cs
index c5531d8..5708ae3 100644
--- a/Library/Web/Router.cs
+++ b/Library/Web/Router.cs
@@ -399,10 +399,18 @@ namespace Serein.Library.Web
catch (Exception ex)
{
// If serialization fails, use the original message's string representation
- resultData = ex.ToString();
- byte[] buffer = Encoding.UTF8.GetBytes(resultData);
- response.ContentLength64 = buffer.Length;
- response.OutputStream.Write(buffer, 0, buffer.Length);
+ try
+ {
+ resultData = ex.ToString();
+ byte[] buffer = Encoding.UTF8.GetBytes(resultData);
+ response.ContentLength64 = buffer.Length;
+ response.OutputStream.Write(buffer, 0, buffer.Length);
+ }
+ catch (Exception ex1)
+ {
+
+ Console.WriteLine(ex1);
+ }
}
diff --git a/NodeFlow/FlowEnvironment.cs b/NodeFlow/FlowEnvironment.cs
index 6f34881..214d327 100644
--- a/NodeFlow/FlowEnvironment.cs
+++ b/NodeFlow/FlowEnvironment.cs
@@ -81,7 +81,7 @@ namespace Serein.NodeFlow
///
public event FlowRunCompleteHandler OnFlowRunComplete;
- private FlowStarter? nodeFlowStarter = null;
+ private FlowStarter? flowStarter = null;
///
/// 一种轻量的IOC容器
@@ -117,6 +117,7 @@ namespace Serein.NodeFlow
/// 私有属性
///
private NodeModelBase _startNode;
+
///
/// 起始节点
///
@@ -143,7 +144,7 @@ namespace Serein.NodeFlow
///
public async Task StartAsync()
{
- nodeFlowStarter = new FlowStarter();
+ flowStarter = new FlowStarter();
List flipflopNodes = Nodes.Values.Where(it => it.MethodDetails?.MethodDynamicType == NodeType.Flipflop && it.IsStart == false)
.Select(it => (SingleFlipflopNode)it)
.Where(node => node is SingleFlipflopNode flipflopNode && flipflopNode.NotExitPreviousNode())
@@ -154,7 +155,7 @@ namespace Serein.NodeFlow
var exitMethods = MethodDetailss.Where(it => it.MethodDynamicType == NodeType.Exit).ToList();
- await nodeFlowStarter.RunAsync(StartNode,
+ await flowStarter.RunAsync(StartNode,
this,
runMethodDetailess,
initMethods,
@@ -162,15 +163,15 @@ namespace Serein.NodeFlow
exitMethods,
flipflopNodes);
- if(nodeFlowStarter?.FlipFlopState == RunState.NoStart)
+ if(flowStarter?.FlipFlopState == RunState.NoStart)
{
this.Exit(); // 未运行触发器时,才会调用结束方法
}
- nodeFlowStarter = null;
+ flowStarter = null;
}
public void Exit()
{
- nodeFlowStarter?.Exit();
+ flowStarter?.Exit();
OnFlowRunComplete?.Invoke(new FlowEventArgs());
}
@@ -341,9 +342,6 @@ namespace Serein.NodeFlow
OnProjectLoaded?.Invoke(new ProjectLoadedEventArgs());
}
-
-
-
///
/// 保存项目为项目文件
///
@@ -381,6 +379,15 @@ namespace Serein.NodeFlow
{
var nodeModel = CreateNode(nodeControlType, methodDetails);
TryAddNode(nodeModel);
+
+ if(flowStarter?.FlowState != RunState.Completion
+ && nodeControlType == NodeControlType.Flipflop
+ && nodeModel is SingleFlipflopNode flipflopNode)
+ {
+ // 当前添加节点属于触发器,且当前正在运行,则加载到运行环境中
+ flowStarter?.AddFlipflopInRuning(flipflopNode, this);
+ }
+
// 通知UI更改
OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, position));
// 因为需要UI先布置了元素,才能通知UI变更特效
@@ -391,8 +398,6 @@ namespace Serein.NodeFlow
}
}
-
-
///
/// 移除节点
///
@@ -432,15 +437,18 @@ namespace Serein.NodeFlow
// 遍历所有子节点,从那些子节点中的父节点集合移除该节点
foreach (var snc in remoteNode.SuccessorNodes)
{
- var sCType = snc.Key; // 连接类型
+ var connectionType = snc.Key; // 连接类型
for (int i = 0; i < snc.Value.Count; i++)
{
- NodeModelBase? sNode = snc.Value[i];
- remoteNode.SuccessorNodes[sCType].RemoveAt(i);
- OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(remoteNode.Guid,
- sNode.Guid,
- sCType,
- NodeConnectChangeEventArgs.ConnectChangeType.Remote)); // 通知UI
+ NodeModelBase? toNode = snc.Value[i];
+
+ RemoteConnect(remoteNode, toNode, connectionType);
+ //remoteNode.SuccessorNodes[connectionType].RemoveAt(i);
+
+ //OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(remoteNode.Guid,
+ // toNode.Guid,
+ // connectionType,
+ // NodeConnectChangeEventArgs.ConnectChangeType.Remote)); // 通知UI
}
}
@@ -475,9 +483,9 @@ namespace Serein.NodeFlow
///
/// 移除连接关系
///
- ///
- ///
- ///
+ /// 起始节点Guid
+ /// 目标节点Guid
+ /// 连接关系
///
public void RemoteConnect(string fromNodeGuid, string toNodeGuid, ConnectionType connectionType)
{
@@ -490,11 +498,41 @@ namespace Serein.NodeFlow
{
return;
}
+ RemoteConnect(fromNode, toNode, connectionType);
+ //fromNode.SuccessorNodes[connectionType].Remove(toNode);
+ //toNode.PreviousNodes[connectionType].Remove(fromNode);
+ //OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid,
+ // toNodeGuid,
+ // connectionType,
+ // NodeConnectChangeEventArgs.ConnectChangeType.Remote));
+ }
+
+
+ ///
+ /// 移除连接关系
+ ///
+ /// 起始节点Model
+ /// 目标节点Model
+ /// 连接关系
+ ///
+ private void RemoteConnect(NodeModelBase fromNode, NodeModelBase toNode, ConnectionType connectionType)
+ {
fromNode.SuccessorNodes[connectionType].Remove(toNode);
toNode.PreviousNodes[connectionType].Remove(fromNode);
- OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid,
- toNodeGuid,
+ if(toNode is SingleFlipflopNode flipflopNode)
+ {
+ if (flowStarter?.FlowState != RunState.Completion
+ && flipflopNode.NotExitPreviousNode())
+ {
+ // 被父节点移除连接关系的子节点若为触发器,且无上级节点,则当前流程正在运行,则加载到运行环境中
+ flowStarter?.AddFlipflopInRuning(flipflopNode, this);
+ }
+ }
+
+ // 通知UI
+ OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNode.Guid,
+ toNode.Guid,
connectionType,
NodeConnectChangeEventArgs.ConnectChangeType.Remote));
}
@@ -789,10 +827,6 @@ namespace Serein.NodeFlow
return controlType;
}
-
-
-
-
public static bool NotExitPreviousNode(this SingleFlipflopNode node)
{
ConnectionType[] ct = [ConnectionType.IsSucceed,
diff --git a/NodeFlow/FlowStarter.cs b/NodeFlow/FlowStarter.cs
index d68ad31..5b96a10 100644
--- a/NodeFlow/FlowStarter.cs
+++ b/NodeFlow/FlowStarter.cs
@@ -157,7 +157,7 @@ namespace Serein.NodeFlow
}
#endregion
- #region 执行初始化,绑定IOC容器,再执行加载时,设置流程退出时的回调函数
+ #region 执行初始化,绑定IOC容器,再执行加载时
object?[]? args = [Context];
foreach (var md in initMethods) // 初始化
@@ -172,6 +172,9 @@ namespace Serein.NodeFlow
md.MethodDelegate.DynamicInvoke(data);
}
Context.SereinIoc.Build(); // 预防有人在加载时才注册类型,再绑定一次
+ #endregion
+
+ #region 设置流程退出时的回调函数
ExitAction = () =>
{
SereinIOC.Run(web => {
@@ -193,9 +196,6 @@ namespace Serein.NodeFlow
}
FlowState = RunState.Completion;
FlipFlopState = RunState.Completion;
-
-
-
};
#endregion
@@ -233,6 +233,17 @@ namespace Serein.NodeFlow
#endregion
}
+ public void AddFlipflopInRuning(SingleFlipflopNode singleFlipFlopNode, IFlowEnvironment flowEnvironment)
+ {
+ _ = Task.Run(async () =>
+ {
+ // 设置对象
+ singleFlipFlopNode.MethodDetails.ActingInstance = SereinIOC.GetOrRegisterInstantiate(singleFlipFlopNode.MethodDetails.ActingInstanceType);
+ await FlipflopExecute(singleFlipFlopNode, flowEnvironment); // 启动触发器
+ });
+ }
+
+
///
/// 启动触发器
///
@@ -248,26 +259,39 @@ namespace Serein.NodeFlow
while (!FlipFlopCts.IsCancellationRequested) // 循环中直到栈为空才会退出
{
+ if(singleFlipFlopNode.NotExitPreviousNode() == false)
+ {
+ // 存在上级节点时,退出触发器
+ break;
+ }
object?[]? parameters = singleFlipFlopNode.GetParameters(context, md);
// 调用委托并获取结果
-
md.ActingInstance = context.SereinIoc.GetOrRegisterInstantiate(md.ActingInstanceType);
IFlipflopContext flipflopContext = await func.Invoke(md.ActingInstance, parameters);
ConnectionType connection = flipflopContext.State.ToContentType();
+
if (connection != ConnectionType.None)
{
singleFlipFlopNode.NextOrientation = connection;
singleFlipFlopNode.FlowData = flipflopContext.Data;
- var tasks = singleFlipFlopNode.SuccessorNodes[connection].Select(nextNode =>
+ var upstreamNodeTasks = singleFlipFlopNode.SuccessorNodes[ConnectionType.Upstream].Select(nextNode =>
+ {
+ var context = new DynamicContext(SereinIOC, flowEnvironment);
+ nextNode.PreviousNode = singleFlipFlopNode;
+ return nextNode.StartExecution(context);
+ }).ToArray();
+
+ var tmpTasks = singleFlipFlopNode.SuccessorNodes[connection].Select(nextNode =>
{
var context = new DynamicContext(SereinIOC,flowEnvironment);
nextNode.PreviousNode = singleFlipFlopNode;
return nextNode.StartExecution(context);
}).ToArray();
+ Task[] tasks = [..upstreamNodeTasks, .. tmpTasks];
Task.WaitAll(tasks);
}
else
diff --git a/README.md b/README.md
index 80bc230..5844280 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,8 @@
不定期在Bilibili个人空间上更新相关的视频。
https://space.bilibili.com/33526379
-# 当前任务 2024年9月15日22:04:40
+# 计划任务 2024年9月17日更新
+* (重要+优先)实现断点功能,查看运行中节点的数据、ioc容器对象
* 计划新增基础节点“属性包装器”,用来收集各个节点的数据,包装成匿名对象/Json类型
* 计划编写网络方面的通讯,方便传出、传入数据
* 包装数据类型, 优化传递效率(尽可能避免拆箱、装箱)
diff --git a/WorkBench/App.xaml.cs b/WorkBench/App.xaml.cs
index 5b27782..6ee511f 100644
--- a/WorkBench/App.xaml.cs
+++ b/WorkBench/App.xaml.cs
@@ -150,14 +150,14 @@ namespace Serein.WorkBench
Shutdown(); // 关闭应用程序
}
}
- //else if (1 == 1)
- //{
- // string filePath = @"F:\临时\project\new project.dnf";
- // //string filePath = @"D:\Project\C#\DynamicControl\SereinFlow\.Output\Debug\net8.0-windows7.0\U9 project.dnf";
- // string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
- // App.FData = JsonConvert.DeserializeObject(content);
- // App.FileDataPath = filePath;//System.IO.Path.GetDirectoryName(filePath)!;
- //}
+ else if (1 == 1)
+ {
+ string filePath = @"F:\临时\project\new project.dnf";
+ //string filePath = @"D:\Project\C#\DynamicControl\SereinFlow\.Output\Debug\net8.0-windows7.0\U9 project.dnf";
+ string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
+ App.FData = JsonConvert.DeserializeObject(content);
+ App.FileDataPath = filePath;//System.IO.Path.GetDirectoryName(filePath)!;
+ }
}
}