mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-02 15:50:47 +08:00
优化了运行。在运行状态下,在画布上添加触发器、移除触发器、或者涉及到触发器的操作都会及时/延时生效(已经在等待信号的触发器,将会在触发信号后才会拿取新的信号类型创建触发任务)
This commit is contained in:
@@ -141,7 +141,7 @@ namespace Serein.Library.Utils
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据类型生成对应的实例,并注入其中的依赖项(类型信息不登记到IOC容器中)
|
||||
/// 根据类型生成对应的实例,并注入其中的依赖项(类型信息不登记到IOC容器中),类型创建后自动注入其它需要此类型的对象
|
||||
/// </summary>
|
||||
/// <param name="controllerType"></param>
|
||||
/// <param name="parameters"></param>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace Serein.NodeFlow
|
||||
/// </summary>
|
||||
public event FlowRunCompleteHandler OnFlowRunComplete;
|
||||
|
||||
private FlowStarter? nodeFlowStarter = null;
|
||||
private FlowStarter? flowStarter = null;
|
||||
|
||||
/// <summary>
|
||||
/// 一种轻量的IOC容器
|
||||
@@ -117,6 +117,7 @@ namespace Serein.NodeFlow
|
||||
/// 私有属性
|
||||
/// </summary>
|
||||
private NodeModelBase _startNode;
|
||||
|
||||
/// <summary>
|
||||
/// 起始节点
|
||||
/// </summary>
|
||||
@@ -143,7 +144,7 @@ namespace Serein.NodeFlow
|
||||
/// <returns></returns>
|
||||
public async Task StartAsync()
|
||||
{
|
||||
nodeFlowStarter = new FlowStarter();
|
||||
flowStarter = new FlowStarter();
|
||||
List<SingleFlipflopNode> 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());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 保存项目为项目文件
|
||||
/// </summary>
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 移除节点
|
||||
/// </summary>
|
||||
@@ -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
|
||||
/// <summary>
|
||||
/// 移除连接关系
|
||||
/// </summary>
|
||||
/// <param name="fromNodeGuid"></param>
|
||||
/// <param name="toNodeGuid"></param>
|
||||
/// <param name="connectionType"></param>
|
||||
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||
/// <param name="connectionType">连接关系</param>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 移除连接关系
|
||||
/// </summary>
|
||||
/// <param name="fromNodeGuid">起始节点Model</param>
|
||||
/// <param name="toNodeGuid">目标节点Model</param>
|
||||
/// <param name="connectionType">连接关系</param>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
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,
|
||||
|
||||
@@ -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<WebServer>(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); // 启动触发器
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 启动触发器
|
||||
/// </summary>
|
||||
@@ -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
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
不定期在Bilibili个人空间上更新相关的视频。
|
||||
https://space.bilibili.com/33526379
|
||||
|
||||
# 当前任务 2024年9月15日22:04:40
|
||||
* 计划新增基础节点“属性包装器”,用来收集各个节点的数据,包装成匿名对象/Json类型
|
||||
* 计划编写网络方面的通讯,方便传出、传入数据
|
||||
* 包装数据类型, 优化传递效率(尽可能避免拆箱、装箱)
|
||||
# 计划任务 2024年9月17日更新
|
||||
* (重要+优先)正在计划实现断点功能,查看运行中节点的数据、ioc容器对象
|
||||
* 正在计划新增基础节点“属性包装器”,用来收集各个节点的数据,包装成匿名对象/Json类型
|
||||
* 正在计划实现网络方面的通讯,方便传出、传入数据
|
||||
* 正在计划实现对数据传递的包装, 尽可能避免拆箱、装箱,优化传递效率。(可能做不到)
|
||||
|
||||
|
||||
# 如何加载我的DLL?
|
||||
|
||||
@@ -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<SereinProjectData>(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<SereinProjectData>(content);
|
||||
App.FileDataPath = filePath;//System.IO.Path.GetDirectoryName(filePath)!;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user