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)!; + } } }