mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-03 00:00:49 +08:00
尝试将节点流导出为c#代码文件
This commit is contained in:
@@ -20,7 +20,7 @@ namespace Serein.FlowStartTool
|
|||||||
SynchronizationContext? uiContext = SynchronizationContext.Current; // 在UI线程上获取UI线程上下文信息
|
SynchronizationContext? uiContext = SynchronizationContext.Current; // 在UI线程上获取UI线程上下文信息
|
||||||
var uIContextOperation = new UIContextOperation(uiContext); // 封装一个调用UI线程的工具类
|
var uIContextOperation = new UIContextOperation(uiContext); // 封装一个调用UI线程的工具类
|
||||||
flowEnvironment.SetUIContextOperation(uIContextOperation);
|
flowEnvironment.SetUIContextOperation(uIContextOperation);
|
||||||
flowEnvironment.LoadProject(new FlowEnvInfo { Project = flowProjectData }, fileDataPath); // 加载项目
|
flowEnvironment.LoadProject(fileDataPath); // 加载项目
|
||||||
|
|
||||||
flowEnvironment.Event.EnvOutput += (infoType, value) =>
|
flowEnvironment.Event.EnvOutput += (infoType, value) =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -37,22 +37,23 @@ namespace Serein.Library.Api
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
Exception ExceptionOfRuning { get; set; }
|
Exception ExceptionOfRuning { get; set; }
|
||||||
|
|
||||||
/* /// <summary>
|
|
||||||
/// 忽略处理该节点流程
|
|
||||||
/// </summary>
|
|
||||||
void IgnoreFlowHandle(NodeModelBase node);
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取此次流程处理状态
|
/// 获取节点的运行时参数数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="node"></param>
|
/// <param name="nodeModel">节点</param>
|
||||||
/// <returns></returns>
|
/// <param name="index">第几个参数</param>
|
||||||
bool GetIgnodeFlowStateUpload(NodeModelBase node);
|
/// <param name="data">数据</param>
|
||||||
|
void SetParamsTempData(string nodeModel, int index, object data);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 恢复流程处理状态
|
/// 获取节点的运行时参数数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="node"></param>
|
/// <param name="nodeModel">节点</param>
|
||||||
/// <returns></returns>
|
/// <param name="index">第几个参数</param>
|
||||||
void RecoverIgnodeFlowStateUpload(NodeModelBase node);*/
|
/// <param name="data">获取到的参数</param>
|
||||||
|
bool TryGetParamsTempData(string nodeModel, int index, out object data);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -60,33 +61,33 @@ namespace Serein.Library.Api
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="currentNodeModel">当前节点</param>
|
/// <param name="currentNodeModel">当前节点</param>
|
||||||
/// <param name="PreviousNode">运行时上一节点</param>
|
/// <param name="PreviousNode">运行时上一节点</param>
|
||||||
void SetPreviousNode(IFlowNode currentNodeModel, IFlowNode PreviousNode);
|
void SetPreviousNode(string currentNodeModel, string PreviousNode);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取当前节点的运行时上一节点,用以流程中获取数据
|
/// 获取当前节点的运行时上一节点,用以流程中获取数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="currentNodeModel"></param>
|
/// <param name="currentNodeModel"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
IFlowNode GetPreviousNode(IFlowNode currentNodeModel);
|
string GetPreviousNode(string currentNodeModel);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取节点的数据(当前节点需要获取上一节点数据时,需要从 运行时上一节点 的Guid 通过这个方法进行获取
|
/// 获取节点的数据(当前节点需要获取上一节点数据时,需要从 运行时上一节点 的Guid 通过这个方法进行获取
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="nodeModel"></param>
|
/// <param name="nodeModel"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
FlowResult GetFlowData(IFlowNode nodeModel);
|
FlowResult GetFlowData(string nodeModel);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 上一节点数据透传到下一节点
|
/// 上一节点数据透传到下一节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="nodeModel"></param>
|
/// <param name="nodeModel"></param>
|
||||||
FlowResult TransmissionData(IFlowNode nodeModel);
|
FlowResult TransmissionData(string nodeModel);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 添加或更新当前节点的数据
|
/// 添加或更新当前节点的数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="nodeModel"></param>
|
/// <param name="nodeModel"></param>
|
||||||
/// <param name="flowData"></param>
|
/// <param name="flowData"></param>
|
||||||
void AddOrUpdate(IFlowNode nodeModel, FlowResult flowData);
|
void AddOrUpdate(string nodeModel, FlowResult flowData);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 重置流程状态(用于对象池回收)
|
/// 重置流程状态(用于对象池回收)
|
||||||
@@ -97,14 +98,5 @@ namespace Serein.Library.Api
|
|||||||
/// 用以提前结束当前上下文流程的运行
|
/// 用以提前结束当前上下文流程的运行
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Exit();
|
void Exit();
|
||||||
|
|
||||||
/*/// <summary>
|
|
||||||
/// 定时循环触发
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="callback"></param>
|
|
||||||
/// <param name="time"></param>
|
|
||||||
/// <param name="count"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
// Task CreateTimingTask(Action callback, int time = 100, int count = -1);*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Serein.Library.Api
|
namespace Serein.Library.Api
|
||||||
{
|
{
|
||||||
@@ -62,6 +63,27 @@ namespace Serein.Library.Api
|
|||||||
/// <param name="expression">被触发的表达式</param>
|
/// <param name="expression">被触发的表达式</param>
|
||||||
/// <param name="type">中断类型。0主动监视,1表达式</param>
|
/// <param name="type">中断类型。0主动监视,1表达式</param>
|
||||||
void TriggerInterrupt(string nodeGuid, string expression, InterruptTriggerEventArgs.InterruptTriggerType type);
|
void TriggerInterrupt(string nodeGuid, string expression, InterruptTriggerEventArgs.InterruptTriggerType type);
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 调用流程接口,将返回 FlowResult.Value。如果需要 FlowResult 对象,请使用该方法的泛型版本。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="apiGuid">流程接口节点Guid</param>
|
||||||
|
/// <param name="dict">调用时入参参数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<object> InvokeAsync(string apiGuid, Dictionary<string, object> dict);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 调用流程接口,将返回 FlowResult.Value。如果需要 FlowResult 对象,请使用该方法的泛型版本。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="apiGuid">流程接口节点Guid</param>
|
||||||
|
/// <param name="dict">调用时入参参数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<TResult> InvokeAsync<TResult>(string apiGuid, Dictionary<string, object> dict);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -846,9 +846,14 @@ namespace Serein.Library.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 加载项目文件
|
/// 加载项目文件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="flowEnvInfo">包含项目信息的远程环境</param>
|
|
||||||
/// <param name="filePath"></param>
|
/// <param name="filePath"></param>
|
||||||
void LoadProject(FlowEnvInfo flowEnvInfo, string filePath);
|
void LoadProject(string filePath);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 加载项目文件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filePath"></param>
|
||||||
|
Task LoadProjetAsync(string filePath);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 保存项目
|
/// 保存项目
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ namespace Serein.Library
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 表示了两个节点之间的连接关系,同时表示节点运行完成后,所会执行的下一个节点类型。
|
/// 表示了两个节点之间的连接关系,同时表示节点运行完成后,所会执行的下一个节点类型。
|
||||||
/// </summary>
|
/// </summary
|
||||||
public enum ConnectionInvokeType
|
public enum ConnectionInvokeType
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -192,7 +192,6 @@ namespace Serein.Library
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 开始执行
|
/// 开始执行
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -229,7 +228,7 @@ namespace Serein.Library
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
flowResult = new FlowResult(currentNode, context);
|
flowResult = new FlowResult(currentNode.Guid, context);
|
||||||
context.Env.WriteLine(InfoType.ERROR, $"节点[{currentNode.Guid}]异常:" + ex);
|
context.Env.WriteLine(InfoType.ERROR, $"节点[{currentNode.Guid}]异常:" + ex);
|
||||||
context.NextOrientation = ConnectionInvokeType.IsError;
|
context.NextOrientation = ConnectionInvokeType.IsError;
|
||||||
context.ExceptionOfRuning = ex;
|
context.ExceptionOfRuning = ex;
|
||||||
@@ -237,7 +236,7 @@ namespace Serein.Library
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 执行完成时更新栈
|
#region 执行完成时更新栈
|
||||||
context.AddOrUpdate(currentNode, flowResult); // 上下文中更新数据
|
context.AddOrUpdate(currentNode.Guid, flowResult); // 上下文中更新数据
|
||||||
|
|
||||||
// 首先将指定类别后继分支的所有节点逆序推入栈中
|
// 首先将指定类别后继分支的所有节点逆序推入栈中
|
||||||
var nextNodes = currentNode.SuccessorNodes[context.NextOrientation];
|
var nextNodes = currentNode.SuccessorNodes[context.NextOrientation];
|
||||||
@@ -247,7 +246,7 @@ namespace Serein.Library
|
|||||||
if (nextNodes[index].DebugSetting.IsEnable)
|
if (nextNodes[index].DebugSetting.IsEnable)
|
||||||
{
|
{
|
||||||
//if (!ignodeState)
|
//if (!ignodeState)
|
||||||
context.SetPreviousNode(nextNodes[index], currentNode);
|
context.SetPreviousNode(nextNodes[index].Guid, currentNode.Guid);
|
||||||
stack.Push(nextNodes[index]);
|
stack.Push(nextNodes[index]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -259,7 +258,7 @@ namespace Serein.Library
|
|||||||
// 筛选出启用的节点的节点
|
// 筛选出启用的节点的节点
|
||||||
if (upstreamNodes[index].DebugSetting.IsEnable)
|
if (upstreamNodes[index].DebugSetting.IsEnable)
|
||||||
{
|
{
|
||||||
context.SetPreviousNode(upstreamNodes[index], currentNode);
|
context.SetPreviousNode(upstreamNodes[index].Guid, currentNode.Guid);
|
||||||
stack.Push(upstreamNodes[index]);
|
stack.Push(upstreamNodes[index]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -289,18 +288,88 @@ namespace Serein.Library
|
|||||||
await Task.Delay(1);
|
await Task.Delay(1);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
public static async Task<object[]> GetParametersAsync(this IFlowNode nodeModel, IDynamicContext context, CancellationToken token)
|
||||||
|
{
|
||||||
|
var md = nodeModel.MethodDetails;
|
||||||
|
var pds = md.ParameterDetailss;
|
||||||
|
|
||||||
|
if (pds.Length == 0)
|
||||||
|
return [];
|
||||||
|
|
||||||
|
object[] args;
|
||||||
|
object[] paramsArgs = null; // 改为强类型数组 object[]
|
||||||
|
|
||||||
|
int paramsArgIndex = md.ParamsArgIndex;
|
||||||
|
|
||||||
|
if (paramsArgIndex >= 0)
|
||||||
|
{
|
||||||
|
// 可变参数数量
|
||||||
|
int paramsLength = pds.Length - paramsArgIndex;
|
||||||
|
|
||||||
|
// 用 object[] 表示可变参数数组(如果类型固定也可以用 int[] 等)
|
||||||
|
paramsArgs = new object[paramsLength];
|
||||||
|
|
||||||
|
// 方法参数中占位,最后一项是 object[]
|
||||||
|
args = new object[paramsArgIndex + 1];
|
||||||
|
args[paramsArgIndex] = paramsArgs;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
args = new object[pds.Length];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 并发处理常规参数
|
||||||
|
Task<object>[] mainArgTasks = new Task<object>[paramsArgIndex >= 0 ? paramsArgIndex : pds.Length];
|
||||||
|
|
||||||
|
for (int i = 0; i < mainArgTasks.Length; i++)
|
||||||
|
{
|
||||||
|
var pd = pds[i];
|
||||||
|
mainArgTasks[i] = pd.ToMethodArgData(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.WhenAll(mainArgTasks);
|
||||||
|
|
||||||
|
for (int i = 0; i < mainArgTasks.Length; i++)
|
||||||
|
{
|
||||||
|
args[i] = mainArgTasks[i].Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 并发处理 params 参数
|
||||||
|
if (paramsArgs != null)
|
||||||
|
{
|
||||||
|
int paramsLength = paramsArgs.Length;
|
||||||
|
Task<object>[] paramTasks = new Task<object>[paramsLength];
|
||||||
|
|
||||||
|
for (int i = 0; i < paramsLength; i++)
|
||||||
|
{
|
||||||
|
var pd = pds[paramsArgIndex + i];
|
||||||
|
paramTasks[i] = pd.ToMethodArgData(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.WhenAll(paramTasks);
|
||||||
|
|
||||||
|
for (int i = 0; i < paramsLength; i++)
|
||||||
|
{
|
||||||
|
paramsArgs[i] = paramTasks[i].Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
args[args.Length - 1] = paramsArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取对应的参数数组
|
/// 获取对应的参数数组
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static async Task<object[]> GetParametersAsync(this IFlowNode nodeModel, IDynamicContext context, CancellationToken token)
|
public static async Task<object[]> GetParametersAsync2(this IFlowNode nodeModel, IDynamicContext context, CancellationToken token)
|
||||||
{
|
{
|
||||||
if (nodeModel.MethodDetails.ParameterDetailss.Length == 0)
|
if (nodeModel.MethodDetails.ParameterDetailss.Length == 0)
|
||||||
{
|
{
|
||||||
return Array.Empty<object>(); // 无参数
|
return []; // 无参数
|
||||||
}
|
}
|
||||||
var md = nodeModel.MethodDetails;
|
var md = nodeModel.MethodDetails;
|
||||||
var pds = md.ParameterDetailss;
|
var pds = md.ParameterDetailss;
|
||||||
@@ -347,6 +416,50 @@ namespace Serein.Library
|
|||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 视为流程接口调用
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="flowCallNode"></param>
|
||||||
|
/// <param name="param"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task<TResult> ApiInvokeAsync<TResult>(this IFlowNode flowCallNode, Dictionary<string,object> param)
|
||||||
|
{
|
||||||
|
var pds = flowCallNode.MethodDetails.ParameterDetailss;
|
||||||
|
if (param.Keys.Count != pds.Length)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException($"参数数量不一致。传入参数数量:{param.Keys.Count}。接口入参数量:{pds.Length}。");
|
||||||
|
}
|
||||||
|
|
||||||
|
var context = new DynamicContext(flowCallNode.Env);
|
||||||
|
for (int index = 0; index < pds.Length; index++)
|
||||||
|
{
|
||||||
|
ParameterDetails pd = pds[index];
|
||||||
|
if (param.TryGetValue(pd.Name, out var value))
|
||||||
|
{
|
||||||
|
context.SetParamsTempData(flowCallNode.Guid, index, value); // 设置入参参数
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var cts = new CancellationTokenSource();
|
||||||
|
var flowResult = await flowCallNode.StartFlowAsync(context, cts.Token);
|
||||||
|
cts?.Cancel();
|
||||||
|
cts?.Dispose();
|
||||||
|
context.Exit();
|
||||||
|
if (flowResult.Value is TResult result)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else if (flowResult is FlowResult && flowResult is TResult result2)
|
||||||
|
{
|
||||||
|
return result2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException($"类型转换失败,流程返回数据与泛型不匹配,当前返回类型为[{flowResult.Value.GetType().FullName}]。");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 检查监视表达式是否生效
|
/// 检查监视表达式是否生效
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -46,6 +46,26 @@ namespace Serein.Library
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Exception ExceptionOfRuning { get; set; }
|
public Exception ExceptionOfRuning { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 每个流程上下文分别存放节点的当前数据
|
||||||
|
/// </summary>
|
||||||
|
private readonly ConcurrentDictionary<string, FlowResult> dictNodeFlowData = new ConcurrentDictionary<string, FlowResult>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 每个流程上下文存储运行时节点的调用关系
|
||||||
|
/// </summary>
|
||||||
|
private readonly ConcurrentDictionary<string, string> dictPreviousNodes = new ConcurrentDictionary<string, string>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 记录忽略处理的流程
|
||||||
|
/// </summary>
|
||||||
|
private readonly ConcurrentDictionary<string, bool> dictIgnoreNodeFlow = new ConcurrentDictionary<string, bool>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 记录节点的运行时参数数据
|
||||||
|
/// </summary>
|
||||||
|
private readonly ConcurrentDictionary<string, ConcurrentDictionary<int, object>> dictNodeParams = new ConcurrentDictionary<string, ConcurrentDictionary<int, object>>();
|
||||||
|
/*
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 每个流程上下文分别存放节点的当前数据
|
/// 每个流程上下文分别存放节点的当前数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -61,12 +81,70 @@ namespace Serein.Library
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ConcurrentDictionary<IFlowNode, bool> dictIgnoreNodeFlow = new ConcurrentDictionary<IFlowNode, bool>();
|
private readonly ConcurrentDictionary<IFlowNode, bool> dictIgnoreNodeFlow = new ConcurrentDictionary<IFlowNode, bool>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 记录节点的运行时参数数据
|
||||||
|
/// </summary>
|
||||||
|
private readonly ConcurrentDictionary<IFlowNode, ConcurrentDictionary<int, object>> dictNodeParams = new ConcurrentDictionary<IFlowNode, ConcurrentDictionary<int, object>>();*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置节点的运行时参数数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nodeModel">节点</param>
|
||||||
|
/// <param name="index">第几个参数</param>
|
||||||
|
/// <param name="data">数据</param>
|
||||||
|
public void SetParamsTempData(string nodeModel, int index, object data)
|
||||||
|
{
|
||||||
|
if(!dictNodeParams.TryGetValue(nodeModel,out var dict))
|
||||||
|
{
|
||||||
|
dict = new ConcurrentDictionary<int, object>();
|
||||||
|
dictNodeParams[nodeModel] = dict;
|
||||||
|
}
|
||||||
|
if (dict.TryGetValue(index, out var oldData))
|
||||||
|
{
|
||||||
|
dict[index] = data; // 更新数据
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dict.TryAdd(index, data); // 添加新数据
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取节点的运行时参数数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nodeModel">节点</param>
|
||||||
|
/// <param name="index">第几个参数</param>
|
||||||
|
public bool TryGetParamsTempData(string nodeModel, int index, out object data )
|
||||||
|
{
|
||||||
|
if (dictNodeParams.TryGetValue(nodeModel, out var dict))
|
||||||
|
{
|
||||||
|
if (dict.TryGetValue(index, out data))
|
||||||
|
{
|
||||||
|
return true; // 返回数据
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//throw new KeyNotFoundException($"节点 {nodeModel.Guid} 的参数索引 {index} 不存在。");
|
||||||
|
data = null; // 返回空数据
|
||||||
|
return false; // 返回未找到
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//throw new KeyNotFoundException($"节点 {nodeModel.Guid} 的参数数据不存在。");
|
||||||
|
data = null; // 返回空数据
|
||||||
|
return false; // 返回未找到
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置运行时上一节点
|
/// 设置运行时上一节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="currentNodeModel">当前节点</param>
|
/// <param name="currentNodeModel">当前节点</param>
|
||||||
/// <param name="PreviousNode">上一节点</param>
|
/// <param name="PreviousNode">上一节点</param>
|
||||||
public void SetPreviousNode(IFlowNode currentNodeModel, IFlowNode PreviousNode)
|
public void SetPreviousNode(string currentNodeModel, string PreviousNode)
|
||||||
{
|
{
|
||||||
dictPreviousNodes.AddOrUpdate(currentNodeModel, (_) => PreviousNode, (o, n) => PreviousNode);
|
dictPreviousNodes.AddOrUpdate(currentNodeModel, (_) => PreviousNode, (o, n) => PreviousNode);
|
||||||
}
|
}
|
||||||
@@ -75,7 +153,7 @@ namespace Serein.Library
|
|||||||
/// 忽略处理该节点流程
|
/// 忽略处理该节点流程
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="node"></param>
|
/// <param name="node"></param>
|
||||||
public void IgnoreFlowHandle(IFlowNode node)
|
public void IgnoreFlowHandle(string node)
|
||||||
{
|
{
|
||||||
dictIgnoreNodeFlow.AddOrUpdate(node, (o) => true, (o, n) => true);
|
dictIgnoreNodeFlow.AddOrUpdate(node, (o) => true, (o, n) => true);
|
||||||
}
|
}
|
||||||
@@ -85,7 +163,7 @@ namespace Serein.Library
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="node"></param>
|
/// <param name="node"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public bool GetIgnodeFlowStateUpload(IFlowNode node)
|
public bool GetIgnodeFlowStateUpload(string node)
|
||||||
{
|
{
|
||||||
return dictIgnoreNodeFlow.TryGetValue(node, out var state) ? state : false;
|
return dictIgnoreNodeFlow.TryGetValue(node, out var state) ? state : false;
|
||||||
}
|
}
|
||||||
@@ -94,7 +172,7 @@ namespace Serein.Library
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="node"></param>
|
/// <param name="node"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public void RecoverIgnodeFlowStateUpload(IFlowNode node)
|
public void RecoverIgnodeFlowStateUpload(string node)
|
||||||
{
|
{
|
||||||
dictIgnoreNodeFlow.AddOrUpdate(node, (o) => false, (o, n) => false);
|
dictIgnoreNodeFlow.AddOrUpdate(node, (o) => false, (o, n) => false);
|
||||||
}
|
}
|
||||||
@@ -105,7 +183,7 @@ namespace Serein.Library
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="currentNodeModel"></param>
|
/// <param name="currentNodeModel"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public IFlowNode GetPreviousNode(IFlowNode currentNodeModel)
|
public string GetPreviousNode(string currentNodeModel)
|
||||||
{
|
{
|
||||||
if (dictPreviousNodes.TryGetValue(currentNodeModel, out var node))
|
if (dictPreviousNodes.TryGetValue(currentNodeModel, out var node))
|
||||||
{
|
{
|
||||||
@@ -122,7 +200,7 @@ namespace Serein.Library
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="nodeGuid">节点</param>
|
/// <param name="nodeGuid">节点</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public FlowResult GetFlowData(IFlowNode nodeGuid)
|
public FlowResult GetFlowData(string nodeGuid)
|
||||||
{
|
{
|
||||||
if (dictNodeFlowData.TryGetValue(nodeGuid, out var data))
|
if (dictNodeFlowData.TryGetValue(nodeGuid, out var data))
|
||||||
{
|
{
|
||||||
@@ -139,7 +217,7 @@ namespace Serein.Library
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="nodeModel">节点</param>
|
/// <param name="nodeModel">节点</param>
|
||||||
/// <param name="flowData">新的数据</param>
|
/// <param name="flowData">新的数据</param>
|
||||||
public void AddOrUpdate(IFlowNode nodeModel, FlowResult flowData)
|
public void AddOrUpdate(string nodeModel, FlowResult flowData)
|
||||||
{
|
{
|
||||||
// this.dictNodeFlowData.TryGetValue(nodeGuid, out var oldFlowData);
|
// this.dictNodeFlowData.TryGetValue(nodeGuid, out var oldFlowData);
|
||||||
dictNodeFlowData.AddOrUpdate(nodeModel, _ => flowData, (o,n ) => flowData);
|
dictNodeFlowData.AddOrUpdate(nodeModel, _ => flowData, (o,n ) => flowData);
|
||||||
@@ -149,7 +227,7 @@ namespace Serein.Library
|
|||||||
/// 上一节点数据透传到下一节点
|
/// 上一节点数据透传到下一节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="nodeModel"></param>
|
/// <param name="nodeModel"></param>
|
||||||
public FlowResult TransmissionData(IFlowNode nodeModel)
|
public FlowResult TransmissionData(string nodeModel)
|
||||||
{
|
{
|
||||||
if (dictPreviousNodes.TryGetValue(nodeModel, out var previousNode)) // 首先获取当前节点的上一节点
|
if (dictPreviousNodes.TryGetValue(nodeModel, out var previousNode)) // 首先获取当前节点的上一节点
|
||||||
{
|
{
|
||||||
@@ -159,7 +237,7 @@ namespace Serein.Library
|
|||||||
//AddOrUpdate(nodeModel.Guid, data); // 然后作为当前节点的数据记录在上下文中
|
//AddOrUpdate(nodeModel.Guid, data); // 然后作为当前节点的数据记录在上下文中
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new InvalidOperationException($"透传{nodeModel.Guid}节点数据时发生异常:上一节点不存在数据");
|
throw new InvalidOperationException($"透传{nodeModel}节点数据时发生异常:上一节点不存在数据");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -280,6 +358,7 @@ namespace Serein.Library
|
|||||||
|
|
||||||
list.Clear();
|
list.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Dispose(ref IList<object> list)
|
private void Dispose(ref IList<object> list)
|
||||||
{
|
{
|
||||||
foreach (var nodeObj in list)
|
foreach (var nodeObj in list)
|
||||||
|
|||||||
@@ -29,14 +29,15 @@ namespace Serein.Library
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 画布拥有的节点
|
/// 画布拥有的节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PropertyInfo(IsProtection = true)]
|
[PropertyInfo(IsProtection = false)]
|
||||||
private System.Collections.ObjectModel.ObservableCollection<IFlowNode> _nodes = [];
|
private List<IFlowNode> _nodes = [];
|
||||||
|
//private System.Collections.ObjectModel.ObservableCollection<IFlowNode> _nodes = [];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 画布公开的节点
|
/// 画布公开的节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PropertyInfo(IsProtection = true)]
|
[PropertyInfo(IsProtection = false)]
|
||||||
private System.Collections.ObjectModel.ObservableCollection<IFlowNode> _publicNodes = [];
|
private List<IFlowNode> _publicNodes = [];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 标识画布ID
|
/// 标识画布ID
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ namespace Serein.Library
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 实例化返回值
|
/// 实例化返回值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="nodeModel"></param>
|
/// <param name="nodeGuid"></param>
|
||||||
/// <param name="context"></param>
|
/// <param name="context"></param>
|
||||||
public FlowResult(IFlowNode nodeModel, IDynamicContext context, object value)
|
public FlowResult(string nodeGuid, IDynamicContext context, object value)
|
||||||
{
|
{
|
||||||
this.Source = nodeModel;
|
this.SourceNodeGuid = nodeGuid;
|
||||||
this.ContextGuid = context.Guid;
|
this.ContextGuid = context.Guid;
|
||||||
this.Value = value;
|
this.Value = value;
|
||||||
}
|
}
|
||||||
@@ -40,11 +40,11 @@ namespace Serein.Library
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 空返回值
|
/// 空返回值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="nodeModel"></param>
|
/// <param name="nodeGuid"></param>
|
||||||
/// <param name="context"></param>
|
/// <param name="context"></param>
|
||||||
public FlowResult(IFlowNode nodeModel, IDynamicContext context)
|
public FlowResult(string nodeGuid, IDynamicContext context)
|
||||||
{
|
{
|
||||||
this.Source = nodeModel;
|
this.SourceNodeGuid = nodeGuid;
|
||||||
this.ContextGuid = context.Guid;
|
this.ContextGuid = context.Guid;
|
||||||
this.Value = Unit.Default;
|
this.Value = Unit.Default;
|
||||||
}
|
}
|
||||||
@@ -76,7 +76,7 @@ namespace Serein.Library
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 来源节点Guid
|
/// 来源节点Guid
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IFlowNode Source{ get; }
|
public string SourceNodeGuid{ get; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 来源上下文Guid
|
/// 来源上下文Guid
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
625
Library/FlowNode/LightweightFlowEnvironment.cs
Normal file
625
Library/FlowNode/LightweightFlowEnvironment.cs
Normal file
@@ -0,0 +1,625 @@
|
|||||||
|
using Microsoft.VisualBasic;
|
||||||
|
using Serein.Library.Api;
|
||||||
|
using Serein.Library.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Serein.Library.FlowNode
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
/*public class FlowControl
|
||||||
|
{
|
||||||
|
private DynamicFlowTemplate dynamicFlowTemplate;
|
||||||
|
private LightweightEnvironment environment;
|
||||||
|
public FlowControl(DynamicFlowTemplate dynamicFlowTemplate,
|
||||||
|
LightweightEnvironment environment)
|
||||||
|
{
|
||||||
|
var callTree = new CallTree()
|
||||||
|
callTree.SetMainNode("node1_guid");
|
||||||
|
|
||||||
|
callTree.AddCallNode("node1_guid", (context) => DynamicFlowTemplate.Method(context, ...));
|
||||||
|
callTree.AddCallNode("node2_guid", (context) => DynamicFlowTemplate.Method(context, ...));
|
||||||
|
callTree.AddCallNode("node3_guid", (context) => DynamicFlowTemplate.Method(context, ...));
|
||||||
|
callTree.AddCallNode("node4_guid", (context) => DynamicFlowTemplate.Method(context, ...));
|
||||||
|
|
||||||
|
callTree["node1_guid"].AddFlowUpstream("node2_guid");
|
||||||
|
callTree["node1_guid"].AddFlowSucceed("node2_guid");
|
||||||
|
callTree["node2_guid"].AddFlowSucceed("node3_guid");
|
||||||
|
callTree["node2_guid"].AddFlowError("node4_guid");
|
||||||
|
|
||||||
|
LightweightEnvironment.LoadProject(callTree);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
/*public class DynamicFlowTemplate
|
||||||
|
{
|
||||||
|
private readonly class1_type class1_instance;
|
||||||
|
|
||||||
|
public DynamicFlowTemplate(class1_type class_instance){
|
||||||
|
this.class1_instance = class1_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Description("node1_guid")]
|
||||||
|
[Description("assembly_name.class_name.method_name")]
|
||||||
|
private [methodReturnType / void] NodeMethod_[method_name](IDynamicContext context, type1 param1, type2 param2)
|
||||||
|
{
|
||||||
|
class1_instance.method(params);
|
||||||
|
context.SetData("node_guid", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Description("node2_guid")]
|
||||||
|
[Description("assembly_name.class_name.method_name")]
|
||||||
|
private [methodReturnType] NodeMethod_[method_name](IDynamicContext context, type1 param1)
|
||||||
|
{
|
||||||
|
param1 = context.GetData("node1_guid") as type1;
|
||||||
|
var result = class1_instance.method(params, param1);
|
||||||
|
context.SetData("node2_guid", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Description("node3_guid")]
|
||||||
|
public [methodReturnType] FlowCall_[method_name](IDynamicContext context, type1 param1, type2 param2)
|
||||||
|
{
|
||||||
|
param1 = context.GetData("node3_guid") as type1;
|
||||||
|
var result = class1_instance.method(params, param1);
|
||||||
|
context.SetData("node3_guid", result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class CallTree
|
||||||
|
{
|
||||||
|
public CallTree(string canvasGuid, string startNodeGuid)
|
||||||
|
{
|
||||||
|
_canvas_guid = canvasGuid;
|
||||||
|
_start_node_guid = startNodeGuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private readonly ConcurrentDictionary<string, CallNode> _callNodes = new ConcurrentDictionary<string,CallNode>();
|
||||||
|
private readonly string _start_node_guid;
|
||||||
|
private readonly string _canvas_guid ;
|
||||||
|
public CallNode this[string index]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
_callNodes.TryGetValue(index, out CallNode callNode);
|
||||||
|
return callNode;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
// 设置指定索引的值
|
||||||
|
_callNodes.AddOrUpdate(index, value, (key, oldValue) => value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddCallNode(string nodeGuid, Action<IDynamicContext> action)
|
||||||
|
{
|
||||||
|
var node = new CallNode(this, nodeGuid, action);
|
||||||
|
_callNodes[nodeGuid] = node;
|
||||||
|
}
|
||||||
|
public void AddCallNode(string nodeGuid, Func<IDynamicContext, Task> func)
|
||||||
|
{
|
||||||
|
var node = new CallNode(this, nodeGuid, func);
|
||||||
|
_callNodes[nodeGuid] = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class CallNode
|
||||||
|
{
|
||||||
|
|
||||||
|
private readonly Func<IDynamicContext, Task> func;
|
||||||
|
private readonly CallTree callTree;
|
||||||
|
private readonly Action<IDynamicContext> action;
|
||||||
|
|
||||||
|
public CallNode(CallTree callTree, string nodeGuid, Action<IDynamicContext> action)
|
||||||
|
{
|
||||||
|
this.callTree = callTree;
|
||||||
|
Guid = nodeGuid;
|
||||||
|
this.action = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CallNode(CallTree callTree, string nodeGuid, Func<IDynamicContext, Task> func)
|
||||||
|
{
|
||||||
|
Guid = nodeGuid;
|
||||||
|
this.func = func;
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Init()
|
||||||
|
{
|
||||||
|
PreviousNodes = new Dictionary<ConnectionInvokeType, List<CallNode>>();
|
||||||
|
SuccessorNodes = new Dictionary<ConnectionInvokeType, List<CallNode>>();
|
||||||
|
foreach (ConnectionInvokeType ctType in NodeStaticConfig.ConnectionTypes)
|
||||||
|
{
|
||||||
|
PreviousNodes[ctType] = new List<CallNode>();
|
||||||
|
SuccessorNodes[ctType] = new List<CallNode>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 对应的节点
|
||||||
|
/// </summary>
|
||||||
|
public string Guid { get; }
|
||||||
|
/// <summary>
|
||||||
|
/// 不同分支的父节点(流程调用)
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<ConnectionInvokeType, List<CallNode>> PreviousNodes { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 不同分支的子节点(流程调用)
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<ConnectionInvokeType, List<CallNode>> SuccessorNodes { get; private set; }
|
||||||
|
|
||||||
|
|
||||||
|
public CallNode AddChildNodeUpstream(string nodeGuid)
|
||||||
|
{
|
||||||
|
var connectionInvokeType = ConnectionInvokeType.Upstream;
|
||||||
|
PreviousNodes[connectionInvokeType].Add(callTree[nodeGuid]);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public CallNode AddChildNodeSucceed(string nodeGuid)
|
||||||
|
{
|
||||||
|
var connectionInvokeType = ConnectionInvokeType.IsSucceed;
|
||||||
|
PreviousNodes[connectionInvokeType].Add(callTree[nodeGuid]);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public CallNode AddChildNodeFail(string nodeGuid)
|
||||||
|
{
|
||||||
|
var connectionInvokeType = ConnectionInvokeType.IsFail;
|
||||||
|
PreviousNodes[connectionInvokeType].Add(callTree[nodeGuid]);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public CallNode AddChildNodeError(string nodeGuid)
|
||||||
|
{
|
||||||
|
var connectionInvokeType = ConnectionInvokeType.IsError;
|
||||||
|
PreviousNodes[connectionInvokeType].Add(callTree[nodeGuid]);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 调用
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="InvalidOperationException"></exception>
|
||||||
|
public async Task InvokeAsync(IDynamicContext context, CancellationToken token)
|
||||||
|
{
|
||||||
|
if (token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (action is not null)
|
||||||
|
{
|
||||||
|
action(context);
|
||||||
|
}
|
||||||
|
else if (func is not null)
|
||||||
|
{
|
||||||
|
await func(context);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"生成了错误的CallNode。【{Guid}】");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 开始执行
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <param name="token">流程运行</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<FlowResult> StartFlowAsync(IDynamicContext context, CancellationToken token)
|
||||||
|
{
|
||||||
|
Stack<CallNode> stack = new Stack<CallNode>();
|
||||||
|
HashSet<CallNode> processedNodes = new HashSet<CallNode>(); // 用于记录已处理上游节点的节点
|
||||||
|
stack.Push(this);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
throw new Exception($"流程执行被取消,未能获取到流程结果。");
|
||||||
|
}
|
||||||
|
|
||||||
|
#region 执行相关
|
||||||
|
// 从栈中弹出一个节点作为当前节点进行处理
|
||||||
|
var currentNode = stack.Pop();
|
||||||
|
context.NextOrientation = ConnectionInvokeType.None; // 重置上下文状态
|
||||||
|
FlowResult flowResult = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await currentNode.InvokeAsync(context, token);
|
||||||
|
|
||||||
|
if (context.NextOrientation == ConnectionInvokeType.None) // 没有手动设置时,进行自动设置
|
||||||
|
{
|
||||||
|
context.NextOrientation = ConnectionInvokeType.IsSucceed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
flowResult = new FlowResult(currentNode.Guid, context);
|
||||||
|
context.Env.WriteLine(InfoType.ERROR, $"节点[{currentNode}]异常:" + ex);
|
||||||
|
context.NextOrientation = ConnectionInvokeType.IsError;
|
||||||
|
context.ExceptionOfRuning = ex;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 执行完成时更新栈
|
||||||
|
context.AddOrUpdate(currentNode.Guid, flowResult); // 上下文中更新数据
|
||||||
|
|
||||||
|
// 首先将指定类别后继分支的所有节点逆序推入栈中
|
||||||
|
var nextNodes = currentNode.SuccessorNodes[context.NextOrientation];
|
||||||
|
for (int index = nextNodes.Count - 1; index >= 0; index--)
|
||||||
|
{
|
||||||
|
//if (!ignodeState)
|
||||||
|
context.SetPreviousNode(nextNodes[index].Guid, currentNode.Guid);
|
||||||
|
stack.Push(nextNodes[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 然后将指上游分支的所有节点逆序推入栈中
|
||||||
|
var upstreamNodes = currentNode.SuccessorNodes[ConnectionInvokeType.Upstream];
|
||||||
|
for (int index = upstreamNodes.Count - 1; index >= 0; index--)
|
||||||
|
{
|
||||||
|
context.SetPreviousNode(upstreamNodes[index].Guid, currentNode.Guid);
|
||||||
|
stack.Push(upstreamNodes[index]);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 执行完成后检查
|
||||||
|
|
||||||
|
if (stack.Count == 0)
|
||||||
|
{
|
||||||
|
return flowResult; // 说明流程到了终点
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.RunState == RunState.Completion)
|
||||||
|
{
|
||||||
|
context.Env.WriteLine(InfoType.INFO, $"流程执行到节点[{currentNode.Guid}]时提前结束,将返回当前执行结果。");
|
||||||
|
return flowResult; // 流程执行完成,返回结果
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
throw new Exception($"流程执行到节点[{currentNode.Guid}]时被取消,未能获取到流程结果。");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 轻量级流程控制器
|
||||||
|
/// </summary>
|
||||||
|
public class LightweightFlowControl : IFlowControl
|
||||||
|
{
|
||||||
|
private readonly Dictionary<string, CallTree> callTree = new Dictionary<string, CallTree>();
|
||||||
|
|
||||||
|
public LightweightFlowControl()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<object> InvokeAsync(string apiGuid, Dictionary<string, object> dict)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<TResult> InvokeAsync<TResult>(string apiGuid, Dictionary<string, object> dict)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<bool> StartFlowFromSelectNodeAsync(string startNodeGuid)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
public async Task<bool> StartFlowAsync(string[] canvasGuids)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<bool> ExitFlowAsync()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region 无须实现
|
||||||
|
|
||||||
|
public void ActivateFlipflopNode(string nodeGuid)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MonitorObjectNotification(string nodeGuid, object monitorData, MonitorObjectEventArgs.ObjSourceType sourceType)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void TerminateFlipflopNode(string nodeGuid)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void TriggerInterrupt(string nodeGuid, string expression, InterruptTriggerEventArgs.InterruptTriggerType type)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UseExternalIOC(ISereinIOC ioc)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 轻量级流程环境事件实现
|
||||||
|
/// </summary>
|
||||||
|
public class LightweightFlowEnvironmentEvent : IFlowEnvironmentEvent
|
||||||
|
{
|
||||||
|
public event LoadDllHandler DllLoad;
|
||||||
|
public event ProjectLoadedHandler ProjectLoaded;
|
||||||
|
public event ProjectSavingHandler ProjectSaving;
|
||||||
|
public event NodeConnectChangeHandler NodeConnectChanged;
|
||||||
|
public event CanvasCreateHandler CanvasCreated;
|
||||||
|
public event CanvasRemoveHandler CanvasRemoved;
|
||||||
|
public event NodeCreateHandler NodeCreated;
|
||||||
|
public event NodeRemoveHandler NodeRemoved;
|
||||||
|
public event NodePlaceHandler NodePlace;
|
||||||
|
public event NodeTakeOutHandler NodeTakeOut;
|
||||||
|
public event StartNodeChangeHandler StartNodeChanged;
|
||||||
|
public event FlowRunCompleteHandler FlowRunComplete;
|
||||||
|
public event MonitorObjectChangeHandler MonitorObjectChanged;
|
||||||
|
public event NodeInterruptStateChangeHandler NodeInterruptStateChanged;
|
||||||
|
public event ExpInterruptTriggerHandler InterruptTriggered;
|
||||||
|
public event IOCMembersChangedHandler IOCMembersChanged;
|
||||||
|
public event NodeLocatedHandler NodeLocated;
|
||||||
|
public event EnvOutHandler EnvOutput;
|
||||||
|
|
||||||
|
public void OnDllLoad(LoadDllEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
DllLoad?.Invoke(eventArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnProjectLoaded(ProjectLoadedEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
ProjectLoaded?.Invoke(eventArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnProjectSaving(ProjectSavingEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
ProjectSaving?.Invoke(eventArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnNodeConnectChanged(NodeConnectChangeEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
NodeConnectChanged?.Invoke(eventArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCanvasCreated(CanvasCreateEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
CanvasCreated?.Invoke(eventArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCanvasRemoved(CanvasRemoveEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
CanvasRemoved?.Invoke(eventArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnNodeCreated(NodeCreateEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
NodeCreated?.Invoke(eventArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnNodeRemoved(NodeRemoveEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
NodeRemoved?.Invoke(eventArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnNodePlace(NodePlaceEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
NodePlace?.Invoke(eventArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnNodeTakeOut(NodeTakeOutEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
NodeTakeOut?.Invoke(eventArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnStartNodeChanged(StartNodeChangeEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
StartNodeChanged?.Invoke(eventArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnFlowRunComplete(FlowEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
FlowRunComplete?.Invoke(eventArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnMonitorObjectChanged(MonitorObjectEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
MonitorObjectChanged?.Invoke(eventArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnNodeInterruptStateChanged(NodeInterruptStateChangeEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
NodeInterruptStateChanged?.Invoke(eventArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnInterruptTriggered(InterruptTriggerEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
InterruptTriggered?.Invoke(eventArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnIOCMembersChanged(IOCMembersChangedEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
IOCMembersChanged?.Invoke(eventArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnNodeLocated(NodeLocatedEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
NodeLocated?.Invoke(eventArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnEnvOutput(InfoType type, string value)
|
||||||
|
{
|
||||||
|
EnvOutput?.Invoke(type, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 轻量级流程环境实现
|
||||||
|
/// </summary>
|
||||||
|
public class LightweightFlowEnvironment : IFlowEnvironment
|
||||||
|
{
|
||||||
|
public void WriteLine(InfoType type, string message, InfoClass @class = InfoClass.Trivial)
|
||||||
|
{
|
||||||
|
Console.WriteLine(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ISereinIOC IOC => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public IFlowEdit FlowEdit => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public IFlowControl FlowControl => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public IFlowEnvironmentEvent Event => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public string EnvName => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public string ProjectFileLocation => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public bool IsGlobalInterrupt => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public bool IsControlRemoteEnv => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public InfoClass InfoClass { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||||
|
public RunState FlowState { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||||
|
|
||||||
|
public IFlowEnvironment CurrentEnv => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public UIContextOperation UIContextOperation => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres, int port, string token)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ExitRemoteEnv()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<FlowEnvInfo> GetEnvInfoAsync()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<SereinProjectData> GetProjectInfoAsync()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadAllNativeLibraryOfRuning(string path, bool isRecurrence = true)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadLibrary(string dllPath)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool LoadNativeLibraryOfRuning(string file)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadProject(string filePath)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task LoadProjetAsync(string filePath)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task NotificationNodeValueChangeAsync(string nodeGuid, string path, object value)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveProject()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetUIContextOperation(UIContextOperation uiContextOperation)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task StartRemoteServerAsync(int port = 7525)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StopRemoteServer()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetDelegateDetails(string assemblyName, string methodName, out DelegateDetails del)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetMethodDetailsInfo(string assemblyName, string methodName, out MethodDetailsInfo mdInfo)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetNodeModel(string nodeGuid, out IFlowNode nodeModel)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryUnloadLibrary(string assemblyFullName)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -208,14 +208,106 @@ namespace Serein.Library
|
|||||||
return pd;
|
return pd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<object> ToMethodArgData(IDynamicContext context)
|
||||||
|
{
|
||||||
|
// 1. 从缓存获取
|
||||||
|
if (context.TryGetParamsTempData(NodeModel.Guid, Index, out var data))
|
||||||
|
return data;
|
||||||
|
|
||||||
|
// 2. 特定快捷类型
|
||||||
|
if (typeof(IFlowEnvironment).IsAssignableFrom(DataType)) return NodeModel.Env;
|
||||||
|
if (typeof(IDynamicContext).IsAssignableFrom(DataType)) return context;
|
||||||
|
if (typeof(IFlowNode).IsAssignableFrom(DataType)) return NodeModel;
|
||||||
|
|
||||||
|
// 3. 显式常量参数
|
||||||
|
if (IsExplicitData && !DataValue.StartsWith("@", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return DataValue.ToConvert(DataType);
|
||||||
|
|
||||||
|
/* // 4. 枚举绑定类型
|
||||||
|
if (ExplicitType is not null && ExplicitType.IsEnum && DataType != ExplicitType)
|
||||||
|
{
|
||||||
|
var resultEnum = Enum.Parse(ExplicitType, DataValue);
|
||||||
|
var boundType = EnumHelper.GetBoundValue(ExplicitType, resultEnum, attr => attr.Value) as Type;
|
||||||
|
if (boundType != null)
|
||||||
|
return NodeModel.Env.IOC.CreateObject(boundType);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// 5. 来自其他节点
|
||||||
|
object inputParameter = null;
|
||||||
|
var env = NodeModel.Env;
|
||||||
|
|
||||||
|
if (ArgDataSourceType == ConnectionArgSourceType.GetPreviousNodeData)
|
||||||
|
{
|
||||||
|
var prevNode = context.GetPreviousNode(NodeModel.Guid);
|
||||||
|
inputParameter = prevNode != null ? context.GetFlowData(prevNode)?.Value : null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
var prevNodeGuid = context.GetPreviousNode(NodeModel.Guid);
|
||||||
|
|
||||||
|
if (!env.TryGetNodeModel(ArgDataSourceNodeGuid, out var sourceNode))
|
||||||
|
throw new Exception($"[arg{Index}] 节点[{ArgDataSourceNodeGuid}]不存在");
|
||||||
|
|
||||||
|
if (sourceNode.IsPublic
|
||||||
|
&& env.TryGetNodeModel(prevNodeGuid, out var prevNode)
|
||||||
|
&& prevNode.ControlType == NodeControlType.FlowCall
|
||||||
|
&& env.TryGetNodeModel(context.GetPreviousNode(NodeModel.Guid), out var sourceNodeTemp)
|
||||||
|
)
|
||||||
|
sourceNode = sourceNodeTemp;
|
||||||
|
|
||||||
|
if (ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
|
||||||
|
inputParameter = context.GetFlowData(sourceNode.Guid)?.Value;
|
||||||
|
else if (ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke)
|
||||||
|
inputParameter = (await sourceNode.ExecutingAsync(context, CancellationToken.None)).Value;
|
||||||
|
else
|
||||||
|
throw new Exception("无效的 ArgDataSourceType");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 表达式处理
|
||||||
|
if (IsExplicitData && DataValue.StartsWith("@", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var lower = DataValue.ToLowerInvariant();
|
||||||
|
if (lower.StartsWith("@get") || lower.StartsWith("@dtc") || lower.StartsWith("@data"))
|
||||||
|
{
|
||||||
|
inputParameter = SerinExpressionEvaluator.Evaluate(DataValue, inputParameter, out _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. 类型转换
|
||||||
|
if (!DataType.IsValueType && inputParameter is null)
|
||||||
|
throw new Exception($"[arg{Index}] 参数不能为null");
|
||||||
|
|
||||||
|
if (DataType == typeof(string))
|
||||||
|
return inputParameter.ToString();
|
||||||
|
|
||||||
|
var actualType = inputParameter.GetType();
|
||||||
|
if (DataType.IsAssignableFrom(actualType))
|
||||||
|
return inputParameter;
|
||||||
|
|
||||||
|
if (DataType.IsSubclassOf(actualType))
|
||||||
|
return ObjectConvertHelper.ConvertParentToChild(inputParameter, DataType);
|
||||||
|
|
||||||
|
throw new Exception($"[arg{Index}] 类型不匹配:目标类型为 {DataType},实际类型为 {actualType}");
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 转为方法入参数据
|
/// 转为方法入参数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async ValueTask<object> ToMethodArgData(IDynamicContext context)
|
public async Task<object> ToMethodArgData2(IDynamicContext context)
|
||||||
{
|
{
|
||||||
|
|
||||||
var nodeModel = NodeModel;
|
var nodeModel = NodeModel;
|
||||||
var env = nodeModel.Env;
|
var env = nodeModel.Env;
|
||||||
|
|
||||||
|
#region 流程运行上下文预设的参数
|
||||||
|
if (context.TryGetParamsTempData(NodeModel.Guid, Index, out var data))
|
||||||
|
{
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region 显然的流程基本类型
|
#region 显然的流程基本类型
|
||||||
// 返回运行环境
|
// 返回运行环境
|
||||||
if (typeof(IFlowEnvironment).IsAssignableFrom(DataType))
|
if (typeof(IFlowEnvironment).IsAssignableFrom(DataType))
|
||||||
@@ -236,8 +328,13 @@ namespace Serein.Library
|
|||||||
if (IsExplicitData && !DataValue.StartsWith("@", StringComparison.OrdinalIgnoreCase))
|
if (IsExplicitData && !DataValue.StartsWith("@", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return DataValue.ToConvert(DataType); // 并非表达式,同时是显式设置的参数
|
return DataValue.ToConvert(DataType); // 并非表达式,同时是显式设置的参数
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region “枚举-类型”转换器
|
#region “枚举-类型”转换器
|
||||||
if (ExplicitType is not null && ExplicitType.IsEnum && DataType != ExplicitType)
|
if (ExplicitType is not null && ExplicitType.IsEnum && DataType != ExplicitType)
|
||||||
{
|
{
|
||||||
@@ -258,7 +355,7 @@ namespace Serein.Library
|
|||||||
|
|
||||||
if (ArgDataSourceType == ConnectionArgSourceType.GetPreviousNodeData)
|
if (ArgDataSourceType == ConnectionArgSourceType.GetPreviousNodeData)
|
||||||
{
|
{
|
||||||
var previousNode = context.GetPreviousNode(nodeModel);
|
var previousNode = context.GetPreviousNode(nodeModel.Guid);
|
||||||
if (previousNode is null)
|
if (previousNode is null)
|
||||||
{
|
{
|
||||||
inputParameter = null;
|
inputParameter = null;
|
||||||
@@ -281,8 +378,9 @@ namespace Serein.Library
|
|||||||
// 如果是公开的节点,需要判断上下文调用中是否存在流程接口节点
|
// 如果是公开的节点,需要判断上下文调用中是否存在流程接口节点
|
||||||
if (argSourceNodeModel.IsPublic)
|
if (argSourceNodeModel.IsPublic)
|
||||||
{
|
{
|
||||||
var pn = context.GetPreviousNode(NodeModel);
|
var pnGuid = context.GetPreviousNode(NodeModel.Guid);
|
||||||
if(pn.ControlType == NodeControlType.FlowCall)
|
var pn = env.TryGetNodeModel(pnGuid, out var tmpNode) ? tmpNode : null;
|
||||||
|
if (pn.ControlType == NodeControlType.FlowCall)
|
||||||
{
|
{
|
||||||
argSourceNodeModel = pn;
|
argSourceNodeModel = pn;
|
||||||
}
|
}
|
||||||
@@ -290,7 +388,7 @@ namespace Serein.Library
|
|||||||
|
|
||||||
if (ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
|
if (ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
|
||||||
{
|
{
|
||||||
var flowData = context.GetFlowData(argSourceNodeModel);
|
var flowData = context.GetFlowData(argSourceNodeModel.Guid);
|
||||||
if(flowData is null)
|
if(flowData is null)
|
||||||
{
|
{
|
||||||
inputParameter = null;
|
inputParameter = null;
|
||||||
|
|||||||
@@ -72,7 +72,8 @@ namespace Serein.Library.Utils
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
if(onException != null) onException(ex);
|
if(onException != null)
|
||||||
|
onException(ex);
|
||||||
Debug.WriteLine(ex);
|
Debug.WriteLine(ex);
|
||||||
}
|
}
|
||||||
}, null);
|
}, null);
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using static Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser;
|
|
||||||
|
|
||||||
namespace Serein.NodeFlow.Env
|
namespace Serein.NodeFlow.Env
|
||||||
{
|
{
|
||||||
@@ -25,11 +24,11 @@ namespace Serein.NodeFlow.Env
|
|||||||
private readonly UIContextOperation UIContextOperation;
|
private readonly UIContextOperation UIContextOperation;
|
||||||
|
|
||||||
public FlowControl(IFlowEnvironment flowEnvironment,
|
public FlowControl(IFlowEnvironment flowEnvironment,
|
||||||
IFlowEnvironmentEvent flowEnvironmentEvent,
|
IFlowEnvironmentEvent flowEnvironmentEvent,
|
||||||
FlowLibraryService flowLibraryService,
|
FlowLibraryService flowLibraryService,
|
||||||
FlowOperationService flowOperationService,
|
FlowOperationService flowOperationService,
|
||||||
FlowModelService flowModelService,
|
FlowModelService flowModelService,
|
||||||
UIContextOperation UIContextOperation)
|
UIContextOperation UIContextOperation)
|
||||||
{
|
{
|
||||||
this.flowEnvironment = flowEnvironment;
|
this.flowEnvironment = flowEnvironment;
|
||||||
this.flowEnvironmentEvent = flowEnvironmentEvent;
|
this.flowEnvironmentEvent = flowEnvironmentEvent;
|
||||||
@@ -285,38 +284,24 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// 调用流程接口,将返回 FlowResult.Value。如果需要 FlowResult 对象,请使用该方法的泛型版本。
|
/// 调用流程接口,将返回 FlowResult.Value。如果需要 FlowResult 对象,请使用该方法的泛型版本。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="apiGuid">流程接口节点Guid</param>
|
/// <param name="apiGuid">流程接口节点Guid</param>
|
||||||
/// <param name="param">调用时入参参数</param>
|
/// <param name="dict">调用时入参参数</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="ArgumentNullException"></exception>
|
public async Task<object> InvokeAsync(string apiGuid, Dictionary<string, object> dict)
|
||||||
public async Task<object> ApiInvokeAsync(string apiGuid, object[] param)
|
|
||||||
{
|
{
|
||||||
if (sereinIOC is null)
|
var result = await InvokeAsync<object>(apiGuid, dict);
|
||||||
{
|
return result;
|
||||||
sereinIOC = flowEnvironment.IOC;
|
|
||||||
}
|
|
||||||
if (!flowModelService.TryGetNodeModel(apiGuid, out var nodeModel))
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException($"不存在流程接口:{apiGuid}");
|
|
||||||
}
|
|
||||||
if (nodeModel is not SingleFlowCallNode flowCallNode)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException($"目标节点并非流程接口:{apiGuid}");
|
|
||||||
}
|
|
||||||
var context = contexts.Allocate();
|
|
||||||
CancellationTokenSource cts = new CancellationTokenSource();
|
|
||||||
var flowResult = await flowCallNode.StartFlowAsync(context, cts.Token);
|
|
||||||
return flowResult.Value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 调用流程接口,泛型类型为 FlowResult 时,将返回 FlowResult 对象。
|
/// 调用流程接口,泛型类型为 FlowResult 时,将返回 FlowResult 对象。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TResult"></typeparam>
|
/// <typeparam name="TResult"></typeparam>
|
||||||
/// <param name="apiGuid">流程接口节点Guid</param>
|
/// <param name="apiGuid">流程接口节点Guid</param>
|
||||||
/// <param name="param">调用时入参参数</param>
|
/// <param name="dict">调用时入参参数</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="ArgumentNullException"></exception>
|
/// <exception cref="ArgumentNullException"></exception>
|
||||||
public async Task<TResult> ApiInvokeAsync<TResult>(string apiGuid, object[] param)
|
public async Task<TResult> InvokeAsync<TResult>(string apiGuid, Dictionary<string, object> dict)
|
||||||
{
|
{
|
||||||
if (sereinIOC is null)
|
if (sereinIOC is null)
|
||||||
{
|
{
|
||||||
@@ -330,10 +315,25 @@ namespace Serein.NodeFlow.Env
|
|||||||
{
|
{
|
||||||
throw new ArgumentNullException($"目标节点并非流程接口:{apiGuid}");
|
throw new ArgumentNullException($"目标节点并非流程接口:{apiGuid}");
|
||||||
}
|
}
|
||||||
var context = contexts.Allocate();
|
var pds = flowCallNode.MethodDetails.ParameterDetailss;
|
||||||
|
if (dict.Keys.Count != pds.Length)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException($"参数数量不一致。传入参数数量:{dict.Keys.Count}。接口入参数量:{pds.Length}。");
|
||||||
|
}
|
||||||
|
|
||||||
|
IDynamicContext context = contexts.Allocate();
|
||||||
|
for (int index = 0; index < pds.Length; index++)
|
||||||
|
{
|
||||||
|
ParameterDetails pd = pds[index];
|
||||||
|
if (dict.TryGetValue(pd.Name, out var value))
|
||||||
|
{
|
||||||
|
context.SetParamsTempData(flowCallNode.Guid, index, value); // 设置入参参数
|
||||||
|
}
|
||||||
|
}
|
||||||
CancellationTokenSource cts = new CancellationTokenSource();
|
CancellationTokenSource cts = new CancellationTokenSource();
|
||||||
var flowResult = await flowCallNode.StartFlowAsync(context, cts.Token);
|
var flowResult = await flowCallNode.StartFlowAsync(context, cts.Token);
|
||||||
|
cts?.Cancel();
|
||||||
|
cts?.Dispose();
|
||||||
if (flowResult.Value is TResult result)
|
if (flowResult.Value is TResult result)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
using Serein.Library;
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Serein.Library;
|
||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
using Serein.Library.Utils;
|
using Serein.Library.Utils;
|
||||||
using Serein.NodeFlow.Model;
|
using Serein.NodeFlow.Model;
|
||||||
using Serein.NodeFlow.Model.Operation;
|
using Serein.NodeFlow.Model.Operation;
|
||||||
using Serein.NodeFlow.Services;
|
using Serein.NodeFlow.Services;
|
||||||
using Serein.NodeFlow.Tool;
|
using Serein.NodeFlow.Tool;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using static Serein.Library.Api.IFlowEnvironment;
|
using static Serein.Library.Api.IFlowEnvironment;
|
||||||
|
using IOperation = Serein.NodeFlow.Model.Operation.IOperation;
|
||||||
|
|
||||||
namespace Serein.NodeFlow.Env
|
namespace Serein.NodeFlow.Env
|
||||||
{
|
{
|
||||||
@@ -107,11 +111,13 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// 从节点信息创建节点,并返回状态指示是否创建成功
|
/// 从节点信息创建节点,并返回状态指示是否创建成功
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="nodeInfo"></param>
|
/// <param name="nodeInfo"></param>
|
||||||
|
/// <param name="nodeModel"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private bool CreateNodeFromNodeInfo(NodeInfo nodeInfo)
|
private bool CreateNodeFromNodeInfo(NodeInfo nodeInfo, out IFlowNode? nodeModel)
|
||||||
{
|
{
|
||||||
if (!EnumHelper.TryConvertEnum<NodeControlType>(nodeInfo.Type, out var controlType))
|
if (!EnumHelper.TryConvertEnum<NodeControlType>(nodeInfo.Type, out var controlType))
|
||||||
{
|
{
|
||||||
|
nodeModel = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,37 +152,22 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(nodeInfo.MethodName)) return false;
|
if (string.IsNullOrEmpty(nodeInfo.MethodName))
|
||||||
|
{
|
||||||
|
nodeModel = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// 加载方法节点
|
// 加载方法节点
|
||||||
flowLibraryManagement.TryGetMethodDetails(nodeInfo.AssemblyName, nodeInfo.MethodName, out methodDetails); // 加载项目时尝试获取方法信息
|
flowLibraryManagement.TryGetMethodDetails(nodeInfo.AssemblyName, nodeInfo.MethodName, out methodDetails); // 加载项目时尝试获取方法信息
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
var nodeModel = FlowNodeExtension.CreateNode(flowEnvironment, controlType, methodDetails); // 加载项目时创建节点
|
nodeModel = FlowNodeExtension.CreateNode(flowEnvironment, controlType, methodDetails); // 加载项目时创建节点
|
||||||
if (nodeModel is null)
|
if (nodeModel is null)
|
||||||
{
|
{
|
||||||
nodeInfo.Guid = string.Empty;
|
nodeInfo.Guid = string.Empty;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (TryGetCanvasModel(nodeInfo.CanvasGuid, out var canvasModel))
|
|
||||||
{
|
|
||||||
|
|
||||||
// 节点与画布互相绑定
|
|
||||||
// 需要在UI线程上进行添加,否则会报 “不支持从调度程序线程以外的线程对其 SourceCollection 进行的更改”异常
|
|
||||||
nodeModel.CanvasDetails = canvasModel;
|
|
||||||
UIContextOperation?.Invoke(() => canvasModel.Nodes.Add(nodeModel));
|
|
||||||
|
|
||||||
nodeModel.LoadInfo(nodeInfo); // 创建节点model
|
|
||||||
TryAddNode(nodeModel); // 加载项目时将节点加载到环境中
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SereinEnv.WriteLine(InfoType.ERROR, $"加载节点[{nodeInfo.Guid}]时发生异常,画布[{nodeInfo.CanvasGuid}]不存在");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
UIContextOperation?.Invoke(() =>
|
|
||||||
flowEnvironmentEvent.OnNodeCreated(new NodeCreateEventArgs(nodeInfo.CanvasGuid, nodeModel, nodeInfo.Position))); // 添加到UI上
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,7 +346,10 @@ namespace Serein.NodeFlow.Env
|
|||||||
}*/
|
}*/
|
||||||
canvasModel.StartNode = newStartNodeModel;
|
canvasModel.StartNode = newStartNodeModel;
|
||||||
//newStartNode.IsStart = true;
|
//newStartNode.IsStart = true;
|
||||||
UIContextOperation?.Invoke(() => flowEnvironmentEvent.OnStartNodeChanged(new StartNodeChangeEventArgs(canvasGuid, oldNodeGuid, newStartNodeModel.Guid)));
|
_ = TriggerEvent(() =>
|
||||||
|
flowEnvironmentEvent.OnStartNodeChanged(
|
||||||
|
new StartNodeChangeEventArgs(canvasGuid, oldNodeGuid, newStartNodeModel.Guid)
|
||||||
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,6 +389,46 @@ namespace Serein.NodeFlow.Env
|
|||||||
#region 从NodeInfo创建NodeModel
|
#region 从NodeInfo创建NodeModel
|
||||||
// 流程接口节点最后才创建
|
// 流程接口节点最后才创建
|
||||||
|
|
||||||
|
async Task AddNodeAsync(NodeInfo nodeInfo, IFlowNode nodeModel)
|
||||||
|
{
|
||||||
|
if (!TryGetCanvasModel(nodeInfo.CanvasGuid, out var canvasModel))
|
||||||
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.ERROR, $"加载节点[{nodeInfo.Guid}]时发生异常,画布[{nodeInfo.CanvasGuid}]不存在");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 节点与画布互相绑定
|
||||||
|
// 需要在UI线程上进行添加,否则会报 “不支持从调度程序线程以外的线程对其 SourceCollection 进行的更改”异常
|
||||||
|
nodeModel.CanvasDetails = canvasModel;
|
||||||
|
await TriggerEvent(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var nodes = canvasModel.Nodes.ToList();
|
||||||
|
nodes.Add(nodeModel);
|
||||||
|
canvasModel.Nodes = nodes;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.WriteLine(ex.Message);
|
||||||
|
}
|
||||||
|
}); // 添加到画布节点集合中
|
||||||
|
nodeModel.LoadInfo(nodeInfo); // 创建节点model
|
||||||
|
nodeModel.Guid ??= Guid.NewGuid().ToString();
|
||||||
|
flowModelService.AddNodeModel(nodeModel);
|
||||||
|
|
||||||
|
await TriggerEvent(() =>
|
||||||
|
flowEnvironmentEvent.OnNodeCreated(
|
||||||
|
new NodeCreateEventArgs(nodeInfo.CanvasGuid, nodeModel, nodeInfo.Position)
|
||||||
|
)
|
||||||
|
); // 创建节点事件
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
List<NodeInfo> flowCallNodeInfos = [];
|
List<NodeInfo> flowCallNodeInfos = [];
|
||||||
foreach (NodeInfo? nodeInfo in nodeInfos)
|
foreach (NodeInfo? nodeInfo in nodeInfos)
|
||||||
{
|
{
|
||||||
@@ -404,10 +438,13 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!CreateNodeFromNodeInfo(nodeInfo))
|
if (CreateNodeFromNodeInfo(nodeInfo, out var nodeModel) && nodeModel is not null)
|
||||||
|
{
|
||||||
|
await AddNodeAsync(nodeInfo, nodeModel);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
SereinEnv.WriteLine(InfoType.WARN, $"节点创建失败。{Environment.NewLine}{nodeInfo}");
|
SereinEnv.WriteLine(InfoType.WARN, $"节点创建失败。{Environment.NewLine}{nodeInfo}");
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -415,10 +452,13 @@ namespace Serein.NodeFlow.Env
|
|||||||
// 创建流程接口节点
|
// 创建流程接口节点
|
||||||
foreach (NodeInfo? nodeInfo in flowCallNodeInfos)
|
foreach (NodeInfo? nodeInfo in flowCallNodeInfos)
|
||||||
{
|
{
|
||||||
if (!CreateNodeFromNodeInfo(nodeInfo))
|
if (CreateNodeFromNodeInfo(nodeInfo, out var nodeModel) && nodeModel is not null)
|
||||||
|
{
|
||||||
|
await AddNodeAsync(nodeInfo, nodeModel);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
SereinEnv.WriteLine(InfoType.WARN, $"节点创建失败。{Environment.NewLine}{nodeInfo}");
|
SereinEnv.WriteLine(InfoType.WARN, $"节点创建失败。{Environment.NewLine}{nodeInfo}");
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
@@ -444,8 +484,10 @@ namespace Serein.NodeFlow.Env
|
|||||||
var result = nodeContainer.PlaceNode(nodeModel);
|
var result = nodeContainer.PlaceNode(nodeModel);
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
UIContextOperation?.Invoke(() => flowEnvironmentEvent.OnNodePlace(
|
await TriggerEvent(() =>
|
||||||
new NodePlaceEventArgs(nodeInfo.CanvasGuid, nodeModel.Guid, containerNode.Guid)));
|
flowEnvironmentEvent.OnNodePlace(
|
||||||
|
new NodePlaceEventArgs(nodeInfo.CanvasGuid, nodeModel.Guid, containerNode.Guid)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -484,30 +526,9 @@ namespace Serein.NodeFlow.Env
|
|||||||
|
|
||||||
ConnectInvokeNode(canvasGuid, fromNodeModel.Guid, toNodeModel.Guid, JunctionType.NextStep, JunctionType.Execute, item.connectionType);
|
ConnectInvokeNode(canvasGuid, fromNodeModel.Guid, toNodeModel.Guid, JunctionType.NextStep, JunctionType.Execute, item.connectionType);
|
||||||
|
|
||||||
//var isSuccessful = ConnectInvokeOfNode(canvasGuid, fromNodeModel, toNodeModel, item.connectionType); // 加载时确定节点间的连接关系
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//List<(ConnectionInvokeType connectionType, string[] guids)> allToNodes = [(ConnectionInvokeType.IsSucceed,nodeInfo.TrueNodes),
|
|
||||||
// (ConnectionInvokeType.IsFail, nodeInfo.FalseNodes),
|
|
||||||
// (ConnectionInvokeType.IsError, nodeInfo.ErrorNodes),
|
|
||||||
// (ConnectionInvokeType.Upstream, nodeInfo.UpstreamNodes)];
|
|
||||||
|
|
||||||
//List<(ConnectionInvokeType, NodeModelBase[])> fromNodes = allToNodes.Where(info => info.guids.Length > 0)
|
|
||||||
// .Select(info => (info.connectionType,
|
|
||||||
// info.guids.Where(guid => NodeModels.ContainsKey(guid)).Select(guid => NodeModels[guid])
|
|
||||||
// .ToArray()))
|
|
||||||
// .ToList();
|
|
||||||
// 遍历每种类型的节点分支(四种)
|
|
||||||
//foreach ((ConnectionInvokeType connectionType, NodeModelBase[] toNodes) item in nodeInfo)
|
|
||||||
//{
|
|
||||||
// // 遍历当前类型分支的节点(确认连接关系)
|
|
||||||
// foreach (var toNode in item.toNodes)
|
|
||||||
// {
|
|
||||||
// _ = ConnectInvokeOfNode(fromNode, toNode, item.connectionType); // 加载时确定节点间的连接关系
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -526,20 +547,13 @@ namespace Serein.NodeFlow.Env
|
|||||||
if (!string.IsNullOrEmpty(pd.ArgDataSourceNodeGuid)
|
if (!string.IsNullOrEmpty(pd.ArgDataSourceNodeGuid)
|
||||||
&& TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var fromNode))
|
&& TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var fromNode))
|
||||||
{
|
{
|
||||||
|
|
||||||
ConnectArgSourceNode(canvasGuid, fromNode.Guid, toNode.Guid, JunctionType.ReturnData, JunctionType.ArgData, pd.ArgDataSourceType, pd.Index);
|
ConnectArgSourceNode(canvasGuid, fromNode.Guid, toNode.Guid, JunctionType.ReturnData, JunctionType.ArgData, pd.ArgDataSourceType, pd.Index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
UIContextOperation?.Invoke(() =>
|
|
||||||
{
|
|
||||||
flowEnvironmentEvent.OnProjectLoaded(new ProjectLoadedEventArgs());
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -561,8 +575,27 @@ namespace Serein.NodeFlow.Env
|
|||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private async Task TriggerEvent(Action action)
|
||||||
|
{
|
||||||
|
if(UIContextOperation is null)
|
||||||
|
{
|
||||||
|
action?.Invoke();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await UIContextOperation.InvokeAsync(() =>
|
||||||
|
{
|
||||||
|
action?.Invoke();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,8 +51,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
public FlowEnvironment()
|
public FlowEnvironment()
|
||||||
{
|
{
|
||||||
ISereinIOC ioc = new SereinIOC();
|
ISereinIOC ioc = new SereinIOC();
|
||||||
ioc.Reset()
|
ioc.Register<ISereinIOC>(()=> ioc) // 注册IOC
|
||||||
.Register<ISereinIOC>(()=> ioc) // 注册IOC
|
|
||||||
.Register<IFlowEnvironment>(() => this)
|
.Register<IFlowEnvironment>(() => this)
|
||||||
.Register<IFlowEnvironmentEvent, FlowEnvironmentEvent>()
|
.Register<IFlowEnvironmentEvent, FlowEnvironmentEvent>()
|
||||||
.Register<IFlowEdit, FlowEdit>()
|
.Register<IFlowEdit, FlowEdit>()
|
||||||
@@ -205,11 +204,20 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void LoadProject(FlowEnvInfo flowEnvInfo, string filePath)
|
public void LoadProject(string filePath)
|
||||||
{
|
{
|
||||||
if (flowEnvInfo is null) return;
|
//if (flowEnvInfo is null) return;
|
||||||
SetProjectLoadingFlag(false);
|
SetProjectLoadingFlag(false);
|
||||||
currentFlowEnvironment.LoadProject(flowEnvInfo, filePath);
|
currentFlowEnvironment.LoadProject(filePath);
|
||||||
|
SetProjectLoadingFlag(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task LoadProjetAsync(string filePath)
|
||||||
|
{
|
||||||
|
//if (flowEnvInfo is null) return;
|
||||||
|
SetProjectLoadingFlag(false);
|
||||||
|
await currentFlowEnvironment.LoadProjetAsync(filePath);
|
||||||
SetProjectLoadingFlag(true);
|
SetProjectLoadingFlag(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,11 +315,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void SetUIContextOperation(UIContextOperation uiContextOperation)
|
public void SetUIContextOperation(UIContextOperation uiContextOperation)
|
||||||
{
|
{
|
||||||
if(uiContextOperation is null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
IOC.Register<UIContextOperation>(() => uiContextOperation).Build();
|
|
||||||
currentFlowEnvironment.SetUIContextOperation(uiContextOperation);
|
currentFlowEnvironment.SetUIContextOperation(uiContextOperation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using Serein.Library;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Serein.Library;
|
||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
using Serein.Library.FlowNode;
|
using Serein.Library.FlowNode;
|
||||||
using Serein.Library.Utils;
|
using Serein.Library.Utils;
|
||||||
@@ -15,6 +17,8 @@ using System.Reactive;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Security.AccessControl;
|
using System.Security.AccessControl;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Timers;
|
||||||
using static Serein.Library.Api.IFlowEnvironment;
|
using static Serein.Library.Api.IFlowEnvironment;
|
||||||
|
|
||||||
namespace Serein.NodeFlow.Env
|
namespace Serein.NodeFlow.Env
|
||||||
@@ -288,12 +292,75 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 加载项目文件
|
/// 加载项目文件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="flowEnvInfo">环境信息</param>
|
|
||||||
/// <param name="filePath"></param>
|
/// <param name="filePath"></param>
|
||||||
public void LoadProject(FlowEnvInfo flowEnvInfo, string filePath)
|
public void LoadProject(string filePath)
|
||||||
{
|
{
|
||||||
|
string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
|
||||||
|
var FlowProjectData = JsonConvert.DeserializeObject<SereinProjectData>(content);
|
||||||
|
var FileDataPath = System.IO.Path.GetDirectoryName(filePath)!; // filePath;//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
this.ProjectFileLocation = filePath;
|
this.ProjectFileLocation = filePath;
|
||||||
var projectData = flowEnvInfo.Project;
|
|
||||||
|
var projectData = FlowProjectData;
|
||||||
|
// 加载项目配置文件
|
||||||
|
var dllPaths = projectData.Librarys.Select(it => it.FilePath).ToList();
|
||||||
|
List<MethodDetails> methodDetailss = [];
|
||||||
|
|
||||||
|
// 遍历依赖项中的特性注解,生成方法详情
|
||||||
|
foreach (var dllPath in dllPaths)
|
||||||
|
{
|
||||||
|
string cleanedRelativePath = dllPath.TrimStart('.', '\\');
|
||||||
|
var tmpPath = Path.Combine(FileDataPath, cleanedRelativePath);
|
||||||
|
var dllFilePath = Path.GetFullPath(tmpPath);
|
||||||
|
LoadLibrary(dllFilePath); // 加载项目文件时加载对应的程序集
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
// 加载画布
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (var canvasInfo in projectData.Canvass)
|
||||||
|
{
|
||||||
|
await LoadCanvasAsync(canvasInfo);
|
||||||
|
}
|
||||||
|
var nodeInfos = projectData.Nodes.ToList();
|
||||||
|
await FlowEdit.LoadNodeInfosAsync(nodeInfos); // 加载节点信息
|
||||||
|
// 加载画布
|
||||||
|
foreach (var canvasInfo in projectData.Canvass)
|
||||||
|
{
|
||||||
|
FlowEdit.SetStartNode(canvasInfo.Guid, canvasInfo.StartNode); // 设置起始节点
|
||||||
|
}
|
||||||
|
|
||||||
|
Event.OnProjectLoaded(new ProjectLoadedEventArgs());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
//await SetStartNodeAsync("", projectData.StartNode); // 设置起始节点
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task LoadProjetAsync(string filePath)
|
||||||
|
{
|
||||||
|
string content = await System.IO.File.ReadAllTextAsync(filePath); // 读取整个文件内容
|
||||||
|
var FlowProjectData = JsonConvert.DeserializeObject<SereinProjectData>(content);
|
||||||
|
var FileDataPath = System.IO.Path.GetDirectoryName(filePath)!; // filePath;//
|
||||||
|
if(FlowProjectData is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ProjectFileLocation = filePath;
|
||||||
|
var projectData = FlowProjectData;
|
||||||
|
|
||||||
// 加载项目配置文件
|
// 加载项目配置文件
|
||||||
var dllPaths = projectData.Librarys.Select(it => it.FilePath).ToList();
|
var dllPaths = projectData.Librarys.Select(it => it.FilePath).ToList();
|
||||||
List<MethodDetails> methodDetailss = [];
|
List<MethodDetails> methodDetailss = [];
|
||||||
@@ -309,23 +376,18 @@ namespace Serein.NodeFlow.Env
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
_ = Task.Run(async () =>
|
// 加载画布
|
||||||
|
foreach (var canvasInfo in projectData.Canvass)
|
||||||
{
|
{
|
||||||
// 加载画布
|
await LoadCanvasAsync(canvasInfo);
|
||||||
foreach (var canvasInfo in projectData.Canvass)
|
}
|
||||||
{
|
await FlowEdit.LoadNodeInfosAsync(projectData.Nodes.ToList()); // 加载节点信息
|
||||||
LoadCanvas(canvasInfo);
|
// 加载画布
|
||||||
}
|
foreach (var canvasInfo in projectData.Canvass)
|
||||||
await FlowEdit.LoadNodeInfosAsync(projectData.Nodes.ToList()); // 加载节点信息
|
{
|
||||||
|
FlowEdit.SetStartNode(canvasInfo.Guid, canvasInfo.StartNode); // 设置起始节点
|
||||||
// 加载画布
|
}
|
||||||
foreach (var canvasInfo in projectData.Canvass)
|
Event.OnProjectLoaded(new ProjectLoadedEventArgs());
|
||||||
{
|
|
||||||
FlowEdit.SetStartNode(canvasInfo.Guid, canvasInfo.StartNode); // 设置起始节点
|
|
||||||
}
|
|
||||||
//await SetStartNodeAsync("", projectData.StartNode); // 设置起始节点
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -532,15 +594,24 @@ namespace Serein.NodeFlow.Env
|
|||||||
private int _addCanvasCount = 0;
|
private int _addCanvasCount = 0;
|
||||||
|
|
||||||
|
|
||||||
private FlowCanvasDetails LoadCanvas(FlowCanvasDetailsInfo info)
|
private async Task<FlowCanvasDetails> LoadCanvasAsync(FlowCanvasDetailsInfo info)
|
||||||
{
|
{
|
||||||
var model = new FlowCanvasDetails(this);
|
var model = new FlowCanvasDetails(this);
|
||||||
model.LoadInfo(info);
|
model.LoadInfo(info);
|
||||||
flowModelService.AddCanvasModel(model);
|
flowModelService.AddCanvasModel(model);
|
||||||
UIContextOperation?.Invoke(() =>
|
|
||||||
|
if(UIContextOperation is null)
|
||||||
{
|
{
|
||||||
Event.OnCanvasCreated(new CanvasCreateEventArgs(model));
|
Event.OnCanvasCreated(new CanvasCreateEventArgs(model));
|
||||||
});
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await UIContextOperation.InvokeAsync(() =>
|
||||||
|
{
|
||||||
|
Event.OnCanvasCreated(new CanvasCreateEventArgs(model));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -585,12 +656,12 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <param name="uiContextOperation"></param>
|
/// <param name="uiContextOperation"></param>
|
||||||
public void SetUIContextOperation(UIContextOperation uiContextOperation)
|
public void SetUIContextOperation(UIContextOperation uiContextOperation)
|
||||||
{
|
{
|
||||||
if (uiContextOperation is not null)
|
if (uiContextOperation is null)
|
||||||
{
|
{
|
||||||
this.UIContextOperation = uiContextOperation;
|
return;
|
||||||
//PersistennceInstance[typeof(UIContextOperation)] = uiContextOperation; // 缓存封装好的UI线程上下文
|
|
||||||
}
|
}
|
||||||
|
this.UIContextOperation = uiContextOperation;
|
||||||
|
IOC.Register<UIContextOperation>(() => uiContextOperation).Build();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Serein.NodeFlow.Model;
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace Serein.NodeFlow
|
namespace Serein.NodeFlow
|
||||||
{
|
{
|
||||||
@@ -128,6 +129,32 @@ namespace Serein.NodeFlow
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加代码
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sb">字符串构建器</param>
|
||||||
|
/// <param name="retractCount">缩进次数(4个空格)</param>
|
||||||
|
/// <param name="code">要添加的代码</param>
|
||||||
|
/// <returns>字符串构建器本身</returns>
|
||||||
|
public static StringBuilder AddCode(this StringBuilder sb,
|
||||||
|
int retractCount = 0,
|
||||||
|
string code = null)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(code))
|
||||||
|
{
|
||||||
|
var retract = new string(' ', retractCount * 4);
|
||||||
|
sb.AppendLine(retract + code);
|
||||||
|
}
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///// <summary>
|
///// <summary>
|
||||||
///// 从节点类型枚举中转为对应的 Model 类型
|
///// 从节点类型枚举中转为对应的 Model 类型
|
||||||
///// </summary>
|
///// </summary>
|
||||||
@@ -165,4 +192,6 @@ namespace Serein.NodeFlow
|
|||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
}
|
}
|
||||||
object[] args = await this.GetParametersAsync(context, token);
|
object[] args = await this.GetParametersAsync(context, token);
|
||||||
var result = await dd.InvokeAsync(instance, args);
|
var result = await dd.InvokeAsync(instance, args);
|
||||||
var flowReslt = new FlowResult(this, context, result);
|
var flowReslt = new FlowResult(this.Guid, context, result);
|
||||||
return flowReslt;
|
return flowReslt;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
{
|
{
|
||||||
if (token.IsCancellationRequested)
|
if (token.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
return new FlowResult(this, context);
|
return new FlowResult(this.Guid, context);
|
||||||
}
|
}
|
||||||
// 接收上一节点参数or自定义参数内容
|
// 接收上一节点参数or自定义参数内容
|
||||||
object? parameter;
|
object? parameter;
|
||||||
@@ -128,15 +128,15 @@ namespace Serein.NodeFlow.Model
|
|||||||
if (hasNode)
|
if (hasNode)
|
||||||
{
|
{
|
||||||
context.NextOrientation = ConnectionInvokeType.IsError;
|
context.NextOrientation = ConnectionInvokeType.IsError;
|
||||||
return new FlowResult(this, context);
|
return new FlowResult(this.Guid, context);
|
||||||
}
|
}
|
||||||
if (hasNode)
|
if (hasNode)
|
||||||
{
|
{
|
||||||
return new FlowResult(this, context);
|
return new FlowResult(this.Guid, context);
|
||||||
}
|
}
|
||||||
if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
|
if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
|
||||||
{
|
{
|
||||||
result = context.GetFlowData(argSourceNode).Value; // 使用自定义节点的参数
|
result = context.GetFlowData(argSourceNode.Guid).Value; // 使用自定义节点的参数
|
||||||
}
|
}
|
||||||
else if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke)
|
else if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke)
|
||||||
{
|
{
|
||||||
@@ -148,7 +148,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = context.TransmissionData(this).Value; // 条件节点透传上一节点的数据
|
result = context.TransmissionData(this.Guid).Value; // 条件节点透传上一节点的数据
|
||||||
}
|
}
|
||||||
parameter = result; // 使用上一节点的参数
|
parameter = result; // 使用上一节点的参数
|
||||||
|
|
||||||
@@ -184,7 +184,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
|
|
||||||
SereinEnv.WriteLine(InfoType.INFO, $"{result} {Expression} -> " + context.NextOrientation);
|
SereinEnv.WriteLine(InfoType.INFO, $"{result} {Expression} -> " + context.NextOrientation);
|
||||||
//return result;
|
//return result;
|
||||||
return new FlowResult(this, context, judgmentResult);
|
return new FlowResult(this.Guid, context, judgmentResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
|
|
||||||
public override async Task<FlowResult> ExecutingAsync(IDynamicContext context, CancellationToken token)
|
public override async Task<FlowResult> ExecutingAsync(IDynamicContext context, CancellationToken token)
|
||||||
{
|
{
|
||||||
if(token.IsCancellationRequested) return new FlowResult(this, context);
|
if(token.IsCancellationRequested) return new FlowResult(this.Guid, context);
|
||||||
|
|
||||||
object? parameter = null;// context.TransmissionData(this); // 表达式节点使用上一节点数据
|
object? parameter = null;// context.TransmissionData(this); // 表达式节点使用上一节点数据
|
||||||
var pd = MethodDetails.ParameterDetailss[0];
|
var pd = MethodDetails.ParameterDetailss[0];
|
||||||
@@ -103,12 +103,12 @@ namespace Serein.NodeFlow.Model
|
|||||||
if (hasNode)
|
if (hasNode)
|
||||||
{
|
{
|
||||||
context.NextOrientation = ConnectionInvokeType.IsError;
|
context.NextOrientation = ConnectionInvokeType.IsError;
|
||||||
return new FlowResult(this, context);
|
return new FlowResult(this.Guid, context);
|
||||||
}
|
}
|
||||||
if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
|
if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
|
||||||
{
|
{
|
||||||
// 使用自定义节点的参数
|
// 使用自定义节点的参数
|
||||||
parameter = context.GetFlowData(argSourceNode).Value;
|
parameter = context.GetFlowData(argSourceNode.Guid).Value;
|
||||||
}
|
}
|
||||||
else if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke)
|
else if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke)
|
||||||
{
|
{
|
||||||
@@ -122,7 +122,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 条件节点透传上一节点的数据
|
// 条件节点透传上一节点的数据
|
||||||
parameter = context.TransmissionData(this);
|
parameter = context.TransmissionData(this.Guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -139,13 +139,13 @@ namespace Serein.NodeFlow.Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
context.NextOrientation = ConnectionInvokeType.IsSucceed;
|
context.NextOrientation = ConnectionInvokeType.IsSucceed;
|
||||||
return new FlowResult(this,context, result);
|
return new FlowResult(this.Guid, context, result);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
context.NextOrientation = ConnectionInvokeType.IsError;
|
context.NextOrientation = ConnectionInvokeType.IsError;
|
||||||
context.ExceptionOfRuning = ex;
|
context.ExceptionOfRuning = ex;
|
||||||
return new FlowResult(this, context);
|
return new FlowResult(this.Guid, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
throw new FlipflopException(MethodDetails.MethodName + "触发器超时触发。Guid" + Guid);
|
throw new FlipflopException(MethodDetails.MethodName + "触发器超时触发。Guid" + Guid);
|
||||||
}
|
}
|
||||||
object result = dynamicFlipflopContext.Value;
|
object result = dynamicFlipflopContext.Value;
|
||||||
var flowReslt = new FlowResult(this, context, result);
|
var flowReslt = new FlowResult(this.Guid, context, result);
|
||||||
return flowReslt;
|
return flowReslt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -208,6 +208,14 @@ namespace Serein.NodeFlow.Model
|
|||||||
{
|
{
|
||||||
TargetNodeGuid = targetNode.Guid;
|
TargetNodeGuid = targetNode.Guid;
|
||||||
this.targetNode = targetNode;
|
this.targetNode = targetNode;
|
||||||
|
|
||||||
|
if(this.IsShareParam == false)
|
||||||
|
{
|
||||||
|
foreach (var item in nodeInfo.ParameterData)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -258,7 +266,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
// 此处代码与SereinFlow.Library.FlowNode.ParameterDetails
|
// 此处代码与SereinFlow.Library.FlowNode.ParameterDetails
|
||||||
// ToMethodArgData()方法中判断流程接口节点分支逻辑耦合
|
// ToMethodArgData()方法中判断流程接口节点分支逻辑耦合
|
||||||
// 不要轻易修改
|
// 不要轻易修改
|
||||||
context.AddOrUpdate(targetNode, flowData);
|
context.AddOrUpdate(targetNode.Guid, flowData);
|
||||||
foreach (ConnectionInvokeType ctType in NodeStaticConfig.ConnectionTypes)
|
foreach (ConnectionInvokeType ctType in NodeStaticConfig.ConnectionTypes)
|
||||||
{
|
{
|
||||||
if (this.SuccessorNodes[ctType] == null) continue;
|
if (this.SuccessorNodes[ctType] == null) continue;
|
||||||
@@ -267,7 +275,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
if (node.DebugSetting.IsEnable)
|
if (node.DebugSetting.IsEnable)
|
||||||
{
|
{
|
||||||
|
|
||||||
context.SetPreviousNode(node, this);
|
context.SetPreviousNode(node.Guid, this.Guid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,18 +110,18 @@ namespace Serein.NodeFlow.Model
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public override async Task<FlowResult> ExecutingAsync(IDynamicContext context, CancellationToken token)
|
public override async Task<FlowResult> ExecutingAsync(IDynamicContext context, CancellationToken token)
|
||||||
{
|
{
|
||||||
if (token.IsCancellationRequested) return new FlowResult(this, context);
|
if (token.IsCancellationRequested) return new FlowResult(this.Guid, context);
|
||||||
if (string.IsNullOrEmpty(KeyName))
|
if (string.IsNullOrEmpty(KeyName))
|
||||||
{
|
{
|
||||||
context.NextOrientation = ConnectionInvokeType.IsError;
|
context.NextOrientation = ConnectionInvokeType.IsError;
|
||||||
SereinEnv.WriteLine(InfoType.ERROR, $"全局数据的KeyName不能为空[{this.Guid}]");
|
SereinEnv.WriteLine(InfoType.ERROR, $"全局数据的KeyName不能为空[{this.Guid}]");
|
||||||
return new FlowResult(this, context);
|
return new FlowResult(this.Guid, context);
|
||||||
}
|
}
|
||||||
if (DataNode is null)
|
if (DataNode is null)
|
||||||
{
|
{
|
||||||
context.NextOrientation = ConnectionInvokeType.IsError;
|
context.NextOrientation = ConnectionInvokeType.IsError;
|
||||||
SereinEnv.WriteLine(InfoType.ERROR, $"全局数据节点没有设置数据来源[{this.Guid}]");
|
SereinEnv.WriteLine(InfoType.ERROR, $"全局数据节点没有设置数据来源[{this.Guid}]");
|
||||||
return new FlowResult(this, context);
|
return new FlowResult(this.Guid, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -135,7 +135,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
{
|
{
|
||||||
context.NextOrientation = ConnectionInvokeType.IsError;
|
context.NextOrientation = ConnectionInvokeType.IsError;
|
||||||
context.ExceptionOfRuning = ex;
|
context.ExceptionOfRuning = ex;
|
||||||
return new FlowResult(this, context);
|
return new FlowResult(this.Guid, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -136,6 +136,8 @@ namespace Serein.NodeFlow.Model
|
|||||||
this.MethodDetails.ParameterDetailss[i].Name = nodeInfo.ParameterData[i].ArgName;
|
this.MethodDetails.ParameterDetailss[i].Name = nodeInfo.ParameterData[i].ArgName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReloadScript();// 加载时重新解析
|
||||||
|
IsScriptChanged = false; // 重置脚本改变标志
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,6 +167,8 @@ namespace Serein.NodeFlow.Model
|
|||||||
var p = new SereinScriptParser(sb.ToString());
|
var p = new SereinScriptParser(sb.ToString());
|
||||||
//var p = new SereinScriptParser(Script);
|
//var p = new SereinScriptParser(Script);
|
||||||
mainNode = p.Parse(); // 开始解析
|
mainNode = p.Parse(); // 开始解析
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -192,9 +196,9 @@ namespace Serein.NodeFlow.Model
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<FlowResult> ExecutingAsync(NodeModelBase flowCallNode, IDynamicContext context, CancellationToken token)
|
public async Task<FlowResult> ExecutingAsync(NodeModelBase flowCallNode, IDynamicContext context, CancellationToken token)
|
||||||
{
|
{
|
||||||
if (token.IsCancellationRequested) return new FlowResult(this, context);
|
if (token.IsCancellationRequested) return new FlowResult(this.Guid, context);
|
||||||
var @params = await flowCallNode.GetParametersAsync(context, token);
|
var @params = await flowCallNode.GetParametersAsync(context, token);
|
||||||
if (token.IsCancellationRequested) return new FlowResult(this, context);
|
if (token.IsCancellationRequested) return new FlowResult(this.Guid, context);
|
||||||
|
|
||||||
//context.AddOrUpdate($"{context.Guid}_{this.Guid}_Params", @params[0]); // 后面再改
|
//context.AddOrUpdate($"{context.Guid}_{this.Guid}_Params", @params[0]); // 后面再改
|
||||||
|
|
||||||
@@ -204,7 +208,8 @@ namespace Serein.NodeFlow.Model
|
|||||||
if (IsScriptChanged)
|
if (IsScriptChanged)
|
||||||
{
|
{
|
||||||
ReloadScript();// 每次都重新解析
|
ReloadScript();// 每次都重新解析
|
||||||
IsScriptChanged = false;
|
IsScriptChanged = false;
|
||||||
|
context.Env.WriteLine(InfoType.INFO, $"[{Guid}]脚本解析完成");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -233,7 +238,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
|
|
||||||
var result = await ScriptInterpreter.InterpretAsync(scriptContext, mainNode); // 从入口节点执行
|
var result = await ScriptInterpreter.InterpretAsync(scriptContext, mainNode); // 从入口节点执行
|
||||||
envEvent.FlowRunComplete -= onFlowStop;
|
envEvent.FlowRunComplete -= onFlowStop;
|
||||||
return new FlowResult(this, context, result);
|
return new FlowResult(this.Guid, context, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#region 挂载的方法
|
#region 挂载的方法
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
|
|
||||||
public override async Task<FlowResult> ExecutingAsync(IDynamicContext context, CancellationToken token)
|
public override async Task<FlowResult> ExecutingAsync(IDynamicContext context, CancellationToken token)
|
||||||
{
|
{
|
||||||
if (token.IsCancellationRequested) return new FlowResult(this,context);
|
if (token.IsCancellationRequested) return new FlowResult(this.Guid, context);
|
||||||
if(Adapter is null)
|
if(Adapter is null)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -34,13 +34,13 @@ namespace Serein.NodeFlow.Model
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var p = context.GetPreviousNode(this);
|
var p = context.GetPreviousNode(this.Guid);
|
||||||
var data = context.GetFlowData(p).Value;
|
var data = context.GetFlowData(p).Value;
|
||||||
var iflowContorl = Adapter.GetFlowControl();
|
var iflowContorl = Adapter.GetFlowControl();
|
||||||
iflowContorl.OnExecuting(data);
|
iflowContorl.OnExecuting(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new FlowResult(this, context);
|
return new FlowResult(this.Guid, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Execute()
|
public override async Task<bool> ExecuteAsync()
|
||||||
{
|
{
|
||||||
if (!ValidationParameter()) return false;
|
if (!ValidationParameter()) return false;
|
||||||
if (!flowModelService.TryGetCanvasModel(CanvasGuid, out FlowCanvas) // 不存在画布
|
if (!flowModelService.TryGetCanvasModel(CanvasGuid, out FlowCanvas) // 不存在画布
|
||||||
@@ -132,12 +132,12 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
// flowTaskManagement?.TerminateGlobalFlipflopRuning(flipflopNode); // 假设被连接的是全局触发器,尝试移除
|
// flowTaskManagement?.TerminateGlobalFlipflopRuning(flipflopNode); // 假设被连接的是全局触发器,尝试移除
|
||||||
//}
|
//}
|
||||||
|
|
||||||
var state = (JunctionOfConnectionType, ChangeType) switch
|
var state = (JunctionOfConnectionType, ChangeType) switch
|
||||||
{
|
{
|
||||||
(JunctionOfConnectionType.Invoke, NodeConnectChangeEventArgs.ConnectChangeType.Create) => CreateInvokeConnection(), // 创建节点之间的调用关系
|
(JunctionOfConnectionType.Invoke, NodeConnectChangeEventArgs.ConnectChangeType.Create) => await CreateInvokeConnection(), // 创建节点之间的调用关系
|
||||||
(JunctionOfConnectionType.Invoke, NodeConnectChangeEventArgs.ConnectChangeType.Remove) => RemoveInvokeConnection(), // 移除节点之间的调用关系
|
(JunctionOfConnectionType.Invoke, NodeConnectChangeEventArgs.ConnectChangeType.Remove) => await RemoveInvokeConnection(), // 移除节点之间的调用关系
|
||||||
(JunctionOfConnectionType.Arg, NodeConnectChangeEventArgs.ConnectChangeType.Create) => CreateArgConnection(), // 创建节点之间的参数传递关系
|
(JunctionOfConnectionType.Arg, NodeConnectChangeEventArgs.ConnectChangeType.Create) => await CreateArgConnection(), // 创建节点之间的参数传递关系
|
||||||
(JunctionOfConnectionType.Arg, NodeConnectChangeEventArgs.ConnectChangeType.Remove) => RemoveArgConnection(), // 移除节点之间的参数传递关系
|
(JunctionOfConnectionType.Arg, NodeConnectChangeEventArgs.ConnectChangeType.Remove) => await RemoveArgConnection(), // 移除节点之间的参数传递关系
|
||||||
_ => false
|
_ => false
|
||||||
};
|
};
|
||||||
return state;
|
return state;
|
||||||
@@ -151,7 +151,7 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建方法调用关系
|
/// 创建方法调用关系
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private bool CreateInvokeConnection()
|
private async Task<bool> CreateInvokeConnection()
|
||||||
{
|
{
|
||||||
IFlowNode fromNode = FromNode ;
|
IFlowNode fromNode = FromNode ;
|
||||||
IFlowNode toNode = ToNode;
|
IFlowNode toNode = ToNode;
|
||||||
@@ -224,15 +224,20 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
}
|
}
|
||||||
fromNode.SuccessorNodes[invokeType].Add(toNode); // 添加到起始节点新类别的子分支
|
fromNode.SuccessorNodes[invokeType].Add(toNode); // 添加到起始节点新类别的子分支
|
||||||
toNode.PreviousNodes[invokeType].Add(fromNode); // 添加到目标节点新类别的父分支
|
toNode.PreviousNodes[invokeType].Add(fromNode); // 添加到目标节点新类别的父分支
|
||||||
flowEnvironmentEvent.OnNodeConnectChanged(
|
|
||||||
new NodeConnectChangeEventArgs(
|
await TriggerEvent(() =>
|
||||||
FlowCanvas.Guid,
|
{
|
||||||
fromNode.Guid, // 从哪个节点开始
|
flowEnvironmentEvent.OnNodeConnectChanged(
|
||||||
toNode.Guid, // 连接到那个节点
|
new NodeConnectChangeEventArgs(
|
||||||
JunctionOfConnectionType.Invoke,
|
FlowCanvas.Guid,
|
||||||
invokeType, // 连接线的样式类型
|
fromNode.Guid, // 从哪个节点开始
|
||||||
NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接
|
toNode.Guid, // 连接到那个节点
|
||||||
));
|
JunctionOfConnectionType.Invoke,
|
||||||
|
invokeType, // 连接线的样式类型
|
||||||
|
NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
// Invoke
|
// Invoke
|
||||||
// GetResult
|
// GetResult
|
||||||
return true;
|
return true;
|
||||||
@@ -248,19 +253,22 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 移除方法调用关系
|
/// 移除方法调用关系
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private bool RemoveInvokeConnection()
|
private async Task<bool> RemoveInvokeConnection()
|
||||||
{
|
{
|
||||||
FromNode.SuccessorNodes[ConnectionInvokeType].Remove(ToNode);
|
FromNode.SuccessorNodes[ConnectionInvokeType].Remove(ToNode);
|
||||||
ToNode.PreviousNodes[ConnectionInvokeType].Remove(FromNode);
|
ToNode.PreviousNodes[ConnectionInvokeType].Remove(FromNode);
|
||||||
|
|
||||||
flowEnvironmentEvent.OnNodeConnectChanged(
|
await TriggerEvent(() =>
|
||||||
new NodeConnectChangeEventArgs(
|
{
|
||||||
FlowCanvas.Guid,
|
flowEnvironmentEvent.OnNodeConnectChanged(
|
||||||
FromNode.Guid,
|
new NodeConnectChangeEventArgs(
|
||||||
ToNode.Guid,
|
FlowCanvas.Guid,
|
||||||
JunctionOfConnectionType.Invoke,
|
FromNode.Guid,
|
||||||
ConnectionInvokeType,
|
ToNode.Guid,
|
||||||
NodeConnectChangeEventArgs.ConnectChangeType.Remove));
|
JunctionOfConnectionType.Invoke,
|
||||||
|
ConnectionInvokeType,
|
||||||
|
NodeConnectChangeEventArgs.ConnectChangeType.Remove));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
/* if (string.IsNullOrEmpty(ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid))
|
/* if (string.IsNullOrEmpty(ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid))
|
||||||
@@ -289,7 +297,7 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
/// 创建参数连接关系
|
/// 创建参数连接关系
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <exception cref="Exception"></exception>
|
/// <exception cref="Exception"></exception>
|
||||||
private bool CreateArgConnection()
|
private async Task<bool> CreateArgConnection()
|
||||||
{
|
{
|
||||||
IFlowNode fromNodeControl = ToNode;
|
IFlowNode fromNodeControl = ToNode;
|
||||||
IFlowNode toNodeControl = ToNode;
|
IFlowNode toNodeControl = ToNode;
|
||||||
@@ -304,43 +312,27 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
if (FromNode.Guid == toNodeArgSourceGuid
|
if (FromNode.Guid == toNodeArgSourceGuid
|
||||||
&& toNodeArgSourceType == ConnectionArgSourceType)
|
&& toNodeArgSourceType == ConnectionArgSourceType)
|
||||||
{
|
{
|
||||||
SereinEnv.WriteLine(InfoType.INFO, $"节点之间已建立过连接关系,此次操作将不会执行" +
|
SereinEnv.WriteLine(InfoType.INFO, $"节点之间已建立过连接关系" +
|
||||||
$"起始节点:{FromNode.Guid}" +
|
$"起始节点:{FromNode.Guid}" +
|
||||||
$"目标节点:{ToNode.Guid}" +
|
$"目标节点:{ToNode.Guid}" +
|
||||||
$"参数索引:{ArgIndex}" +
|
$"参数索引:{ArgIndex}" +
|
||||||
$"参数类型:{ConnectionArgSourceType}");
|
$"参数类型:{ConnectionArgSourceType}");
|
||||||
/*flowEnvironmentEvent.OnNodeConnectChanged(
|
await TriggerEvent(() =>
|
||||||
new NodeConnectChangeEventArgs(
|
{
|
||||||
FlowCanvas.Guid,
|
flowEnvironmentEvent.OnNodeConnectChanged(
|
||||||
FromNode.Guid, // 从哪个节点开始
|
new NodeConnectChangeEventArgs(
|
||||||
ToNode.Guid, // 连接到那个节点
|
FlowCanvas.Guid,
|
||||||
ArgIndex, // 连接线的样式类型
|
FromNode.Guid, // 从哪个节点开始
|
||||||
JunctionOfConnectionType.Arg,
|
ToNode.Guid, // 连接到那个节点
|
||||||
ConnectionArgSourceType,
|
ArgIndex, // 连接线的样式类型
|
||||||
NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接
|
JunctionOfConnectionType.Arg,
|
||||||
)); // 通知UI */
|
ConnectionArgSourceType,
|
||||||
return true;
|
NodeConnectChangeEventArgs.ConnectChangeType.Remove // 是创建连接还是删除连接
|
||||||
}
|
)); // 通知UI
|
||||||
|
});
|
||||||
if (!string.IsNullOrEmpty(toNodeArgSourceGuid)) // 更改关系获取
|
await TriggerEvent(() =>
|
||||||
{
|
{
|
||||||
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid = null;
|
flowEnvironmentEvent.OnNodeConnectChanged(
|
||||||
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData; // 恢复默认值
|
|
||||||
flowEnvironmentEvent.OnNodeConnectChanged(
|
|
||||||
new NodeConnectChangeEventArgs(
|
|
||||||
FlowCanvas.Guid,
|
|
||||||
FromNode.Guid,
|
|
||||||
ToNode.Guid,
|
|
||||||
ArgIndex,
|
|
||||||
JunctionOfConnectionType.Arg,
|
|
||||||
ConnectionArgSourceType.GetPreviousNodeData,
|
|
||||||
NodeConnectChangeEventArgs.ConnectChangeType.Remove));
|
|
||||||
}
|
|
||||||
|
|
||||||
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid = FromNode.Guid; // 设置
|
|
||||||
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType = ConnectionArgSourceType;
|
|
||||||
|
|
||||||
flowEnvironmentEvent.OnNodeConnectChanged(
|
|
||||||
new NodeConnectChangeEventArgs(
|
new NodeConnectChangeEventArgs(
|
||||||
FlowCanvas.Guid,
|
FlowCanvas.Guid,
|
||||||
FromNode.Guid, // 从哪个节点开始
|
FromNode.Guid, // 从哪个节点开始
|
||||||
@@ -350,6 +342,47 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
ConnectionArgSourceType,
|
ConnectionArgSourceType,
|
||||||
NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接
|
NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接
|
||||||
)); // 通知UI
|
)); // 通知UI
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(toNodeArgSourceGuid)) // 更改关系获取
|
||||||
|
{
|
||||||
|
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid = null;
|
||||||
|
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData; // 恢复默认值
|
||||||
|
|
||||||
|
await TriggerEvent(() =>
|
||||||
|
{
|
||||||
|
flowEnvironmentEvent.OnNodeConnectChanged(
|
||||||
|
new NodeConnectChangeEventArgs(
|
||||||
|
FlowCanvas.Guid,
|
||||||
|
FromNode.Guid,
|
||||||
|
ToNode.Guid,
|
||||||
|
ArgIndex,
|
||||||
|
JunctionOfConnectionType.Arg,
|
||||||
|
ConnectionArgSourceType.GetPreviousNodeData,
|
||||||
|
NodeConnectChangeEventArgs.ConnectChangeType.Remove));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid = FromNode.Guid; // 设置
|
||||||
|
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType = ConnectionArgSourceType;
|
||||||
|
|
||||||
|
await TriggerEvent(() =>
|
||||||
|
{
|
||||||
|
flowEnvironmentEvent.OnNodeConnectChanged(
|
||||||
|
new NodeConnectChangeEventArgs(
|
||||||
|
FlowCanvas.Guid,
|
||||||
|
FromNode.Guid, // 从哪个节点开始
|
||||||
|
ToNode.Guid, // 连接到那个节点
|
||||||
|
ArgIndex, // 连接线的样式类型
|
||||||
|
JunctionOfConnectionType.Arg,
|
||||||
|
ConnectionArgSourceType,
|
||||||
|
NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接
|
||||||
|
)); // 通知UI
|
||||||
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -360,14 +393,15 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
/// <param name="fromNodeControl"></param>
|
/// <param name="fromNodeControl"></param>
|
||||||
/// <param name="toNodeControl"></param>
|
/// <param name="toNodeControl"></param>
|
||||||
/// <param name="index"></param>
|
/// <param name="index"></param>
|
||||||
private bool RemoveArgConnection()
|
private async Task<bool> RemoveArgConnection()
|
||||||
{
|
{
|
||||||
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid = null;
|
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid = null;
|
||||||
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData; // 恢复默认值
|
ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData; // 恢复默认值
|
||||||
|
|
||||||
if (OperatingSystem.IsWindows())
|
|
||||||
|
await TriggerEvent(() =>
|
||||||
{
|
{
|
||||||
flowEnvironmentEvent.OnNodeConnectChanged(
|
flowEnvironmentEvent.OnNodeConnectChanged(
|
||||||
new NodeConnectChangeEventArgs(
|
new NodeConnectChangeEventArgs(
|
||||||
FlowCanvas.Guid,
|
FlowCanvas.Guid,
|
||||||
FromNode.Guid,
|
FromNode.Guid,
|
||||||
@@ -376,7 +410,8 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
JunctionOfConnectionType.Arg,
|
JunctionOfConnectionType.Arg,
|
||||||
ConnectionArgSourceType.GetPreviousNodeData,
|
ConnectionArgSourceType.GetPreviousNodeData,
|
||||||
NodeConnectChangeEventArgs.ConnectChangeType.Remove));
|
NodeConnectChangeEventArgs.ConnectChangeType.Remove));
|
||||||
}
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,30 +52,31 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override bool Execute()
|
public override Task<bool> ExecuteAsync()
|
||||||
{
|
{
|
||||||
if (!ValidationParameter()) return false;
|
|
||||||
|
if (!ValidationParameter()) return Task.FromResult(false);
|
||||||
|
|
||||||
if (IsAdd)
|
if (IsAdd)
|
||||||
{
|
{
|
||||||
if (nodeModel.MethodDetails.AddParamsArg(ParamIndex))
|
if (nodeModel.MethodDetails.AddParamsArg(ParamIndex))
|
||||||
{
|
{
|
||||||
return true;
|
return Task.FromResult(true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return false;
|
return Task.FromResult(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (nodeModel.MethodDetails.RemoveParamsArg(ParamIndex))
|
if (nodeModel.MethodDetails.RemoveParamsArg(ParamIndex))
|
||||||
{
|
{
|
||||||
return true;
|
return Task.FromResult(true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return true;
|
return Task.FromResult(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
using Serein.Library.Api;
|
using Microsoft.VisualBasic.FileIO;
|
||||||
|
using Serein.Library.Api;
|
||||||
|
using Serein.Library.Utils;
|
||||||
using Serein.NodeFlow.Services;
|
using Serein.NodeFlow.Services;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net.Mime;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@@ -72,12 +75,16 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Execute()
|
public override async Task<bool> ExecuteAsync()
|
||||||
{
|
{
|
||||||
if (!ValidationParameter()) return false;
|
if (!ValidationParameter()) return false;
|
||||||
|
|
||||||
ContainerNode.PlaceNode(Node);
|
ContainerNode.PlaceNode(Node);
|
||||||
flowEnvironmentEvent.OnNodePlace(new NodePlaceEventArgs(CanvasGuid, NodeGuid, ContainerNodeGuid)); // 通知UI更改节点放置位置
|
|
||||||
|
await TriggerEvent(() =>
|
||||||
|
{
|
||||||
|
flowEnvironmentEvent.OnNodePlace(new NodePlaceEventArgs(CanvasGuid, NodeGuid, ContainerNodeGuid)); // 通知UI更改节点放置位置
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,12 +61,15 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Execute()
|
public override async Task<bool> ExecuteAsync()
|
||||||
{
|
{
|
||||||
if (!ValidationParameter()) return false;
|
if (!ValidationParameter()) return false;
|
||||||
|
|
||||||
ContainerNode.TakeOutNode(Node);
|
ContainerNode.TakeOutNode(Node);
|
||||||
flowEnvironmentEvent.OnNodeTakeOut(new NodeTakeOutEventArgs(CanvasGuid, NodeGuid)); // 重新放置在画布上
|
await TriggerEvent(() =>
|
||||||
|
{
|
||||||
|
flowEnvironmentEvent.OnNodeTakeOut(new NodeTakeOutEventArgs(CanvasGuid, NodeGuid)); // 重新放置在画布上
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Execute()
|
public override async Task<bool> ExecuteAsync()
|
||||||
{
|
{
|
||||||
if(!ValidationParameter()) return false;
|
if(!ValidationParameter()) return false;
|
||||||
|
|
||||||
@@ -38,7 +38,11 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
cavasnModel.LoadInfo(CanvasInfo);
|
cavasnModel.LoadInfo(CanvasInfo);
|
||||||
flowModelService.AddCanvasModel(cavasnModel);
|
flowModelService.AddCanvasModel(cavasnModel);
|
||||||
this.flowCanvasDetails = cavasnModel; ;
|
this.flowCanvasDetails = cavasnModel; ;
|
||||||
flowEnvironmentEvent.OnCanvasCreated(new CanvasCreateEventArgs(cavasnModel));
|
|
||||||
|
await TriggerEvent(() =>
|
||||||
|
{
|
||||||
|
flowEnvironmentEvent.OnCanvasCreated(new CanvasCreateEventArgs(cavasnModel));
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Execute()
|
public override async Task<bool> ExecuteAsync()
|
||||||
{
|
{
|
||||||
if (!ValidationParameter()) return false; // 执行时验证
|
if (!ValidationParameter()) return false; // 执行时验证
|
||||||
|
|
||||||
@@ -101,7 +101,11 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
|
|
||||||
flowModelService.AddNodeModel(nodeModel);
|
flowModelService.AddNodeModel(nodeModel);
|
||||||
this.flowNode = nodeModel;
|
this.flowNode = nodeModel;
|
||||||
flowEnvironmentEvent.OnNodeCreated(new NodeCreateEventArgs(flowCanvasDetails.Guid, nodeModel, Position));
|
|
||||||
|
await TriggerEvent(() =>
|
||||||
|
{
|
||||||
|
flowEnvironmentEvent.OnNodeCreated(new NodeCreateEventArgs(flowCanvasDetails.Guid, nodeModel, Position));
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Serein.Library;
|
using Serein.Library;
|
||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
|
using Serein.Library.Utils;
|
||||||
using Serein.NodeFlow.Services;
|
using Serein.NodeFlow.Services;
|
||||||
using Serein.NodeFlow.Tool;
|
using Serein.NodeFlow.Tool;
|
||||||
using System;
|
using System;
|
||||||
@@ -25,7 +26,7 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 执行操作
|
/// 执行操作
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool Execute();
|
Task<bool> ExecuteAsync();
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 撤销操作
|
/// 撤销操作
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -46,6 +47,12 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
[AutoInjection]
|
[AutoInjection]
|
||||||
protected FlowModelService flowModelService;
|
protected FlowModelService flowModelService;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 节点管理服务
|
||||||
|
/// </summary>
|
||||||
|
[AutoInjection]
|
||||||
|
protected UIContextOperation uiContextOperation;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 流程依赖服务
|
/// 流程依赖服务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -75,7 +82,7 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 执行
|
/// 执行
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract bool Execute();
|
public abstract Task<bool> ExecuteAsync();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 撤销
|
/// 撤销
|
||||||
@@ -96,6 +103,23 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
public abstract void ToInfo();
|
public abstract void ToInfo();
|
||||||
|
|
||||||
|
|
||||||
|
protected async Task TriggerEvent(Action action)
|
||||||
|
{
|
||||||
|
/* if (OperatingSystem.IsWindows())
|
||||||
|
{
|
||||||
|
}*/
|
||||||
|
if (uiContextOperation is null)
|
||||||
|
{
|
||||||
|
action?.Invoke();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await uiContextOperation.InvokeAsync(() =>
|
||||||
|
{
|
||||||
|
action?.Invoke();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Execute()
|
public override async Task<bool> ExecuteAsync()
|
||||||
{
|
{
|
||||||
if (!ValidationParameter()) return false;
|
if (!ValidationParameter()) return false;
|
||||||
|
|
||||||
@@ -46,7 +46,11 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
|
|
||||||
flowModelService.RemoveCanvasModel(flowCanvasDetails);
|
flowModelService.RemoveCanvasModel(flowCanvasDetails);
|
||||||
flowCanvasDetailsInfo = flowCanvasDetails.ToInfo();
|
flowCanvasDetailsInfo = flowCanvasDetails.ToInfo();
|
||||||
flowEnvironmentEvent.OnCanvasRemoved(new CanvasRemoveEventArgs(flowCanvasDetails.Guid));
|
|
||||||
|
await TriggerEvent(() =>
|
||||||
|
{
|
||||||
|
flowEnvironmentEvent.OnCanvasRemoved(new CanvasRemoveEventArgs(flowCanvasDetails.Guid));
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Execute()
|
public override async Task<bool> ExecuteAsync()
|
||||||
{
|
{
|
||||||
if (!ValidationParameter()) return false;
|
if (!ValidationParameter()) return false;
|
||||||
|
|
||||||
@@ -74,8 +74,10 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
connectionType, // 对应的连接关系
|
connectionType, // 对应的连接关系
|
||||||
NodeConnectChangeEventArgs.ConnectChangeType.Remove); // 移除连线
|
NodeConnectChangeEventArgs.ConnectChangeType.Remove); // 移除连线
|
||||||
EventArgs.Add(e); // 缓存事件参数
|
EventArgs.Add(e); // 缓存事件参数
|
||||||
flowEnvironmentEvent.OnNodeConnectChanged(e);
|
await TriggerEvent(() =>
|
||||||
|
{
|
||||||
|
flowEnvironmentEvent.OnNodeConnectChanged(e);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +104,10 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
connectionType, // 对应的连接关系
|
connectionType, // 对应的连接关系
|
||||||
NodeConnectChangeEventArgs.ConnectChangeType.Remove); // 移除连线
|
NodeConnectChangeEventArgs.ConnectChangeType.Remove); // 移除连线
|
||||||
EventArgs.Add(e); // 缓存事件参数
|
EventArgs.Add(e); // 缓存事件参数
|
||||||
flowEnvironmentEvent.OnNodeConnectChanged(e);
|
await TriggerEvent(() =>
|
||||||
|
{
|
||||||
|
flowEnvironmentEvent.OnNodeConnectChanged(e);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,7 +141,10 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
connectionType, // 对应的连接关系
|
connectionType, // 对应的连接关系
|
||||||
NodeConnectChangeEventArgs.ConnectChangeType.Remove); // 移除连线
|
NodeConnectChangeEventArgs.ConnectChangeType.Remove); // 移除连线
|
||||||
EventArgs.Add(e); // 缓存事件参数
|
EventArgs.Add(e); // 缓存事件参数
|
||||||
flowEnvironmentEvent.OnNodeConnectChanged(e);
|
await TriggerEvent(() =>
|
||||||
|
{
|
||||||
|
flowEnvironmentEvent.OnNodeConnectChanged(e);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,12 +161,16 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
{
|
{
|
||||||
// 存在UI上下文操作,当前运行环境极有可能运行在有UI线程的平台上
|
// 存在UI上下文操作,当前运行环境极有可能运行在有UI线程的平台上
|
||||||
// 为了避免直接修改 ObservableCollection 集合导致异常产生,故而使用UI线程上下文操作运行
|
// 为了避免直接修改 ObservableCollection 集合导致异常产生,故而使用UI线程上下文操作运行
|
||||||
flowEnvironment.UIContextOperation?.Invoke(() =>
|
await TriggerEvent(() =>
|
||||||
{
|
{
|
||||||
flowCanvasDetails?.Nodes.Remove(flowNode);
|
flowCanvasDetails?.Nodes.Remove(flowNode);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
flowEnvironmentEvent.OnNodeRemoved(new NodeRemoveEventArgs(CanvasGuid, NodeGuid));
|
|
||||||
|
await TriggerEvent(() =>
|
||||||
|
{
|
||||||
|
flowEnvironmentEvent.OnNodeRemoved(new NodeRemoveEventArgs(CanvasGuid, NodeGuid));
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,9 +46,9 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 成为首项
|
/// 成为首项
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public override bool Execute()
|
public override Task<bool> ExecuteAsync()
|
||||||
{
|
{
|
||||||
if(!ValidationParameter()) return false;
|
if(!ValidationParameter()) return Task.FromResult(false);
|
||||||
|
|
||||||
if (FromNode.SuccessorNodes.TryGetValue(ConnectionType, out var nodes))
|
if (FromNode.SuccessorNodes.TryGetValue(ConnectionType, out var nodes))
|
||||||
{
|
{
|
||||||
@@ -60,7 +60,7 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
nodes.Insert(0, ToNode);
|
nodes.Insert(0, ToNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public override bool Execute()
|
public override async Task<bool> ExecuteAsync()
|
||||||
{
|
{
|
||||||
if (!ValidationParameter()) return false;
|
if (!ValidationParameter()) return false;
|
||||||
|
|
||||||
@@ -45,7 +45,11 @@ namespace Serein.NodeFlow.Model.Operation
|
|||||||
}
|
}
|
||||||
|
|
||||||
CanvasModel.StartNode = NewStartNodeModel;
|
CanvasModel.StartNode = NewStartNodeModel;
|
||||||
flowEnvironmentEvent.OnStartNodeChanged(new StartNodeChangeEventArgs(CanvasModel.Guid, OldStartNodeModel?.Guid, NewStartNodeModel.Guid));
|
|
||||||
|
await TriggerEvent(() =>
|
||||||
|
{
|
||||||
|
flowEnvironmentEvent.OnStartNodeChanged(new StartNodeChangeEventArgs(CanvasModel.Guid, OldStartNodeModel?.Guid, NewStartNodeModel.Guid));
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,10 @@
|
|||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.6" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Serein.Library.MyGenerator\Serein.Library.NodeGenerator.csproj" OutputItemType="Analyzer" />
|
<ProjectReference Include="..\Serein.Library.MyGenerator\Serein.Library.NodeGenerator.csproj" OutputItemType="Analyzer" />
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Serein.NodeFlow.Services
|
namespace Serein.NodeFlow.Services
|
||||||
{
|
{
|
||||||
@@ -113,5 +114,53 @@ namespace Serein.NodeFlow.Services
|
|||||||
return flowCanvasDetails.Nodes.Count > 0;
|
return flowCanvasDetails.Nodes.Count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void ToCsharpCoreFile()
|
||||||
|
{
|
||||||
|
// TODO: 实现将流程模型转换为C# Core文件的逻辑
|
||||||
|
// 遍历每个画布
|
||||||
|
int canvas_index = 0;
|
||||||
|
|
||||||
|
HashSet<Type> assemblyFlowClasss = new HashSet<Type>(); // 用于创建依赖注入项
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
|
||||||
|
foreach (var canvas in FlowCanvass.Values)
|
||||||
|
{
|
||||||
|
int flowTemplateId = canvas_index++;
|
||||||
|
string flowTemplateClassName = $"FlowTemplate{flowTemplateId}";
|
||||||
|
|
||||||
|
HashSet<Type> flowClasss = new HashSet<Type>();
|
||||||
|
|
||||||
|
// 收集程序集信息
|
||||||
|
foreach (var node in canvas.Nodes)
|
||||||
|
{
|
||||||
|
var instanceType = node.MethodDetails.ActingInstanceType;
|
||||||
|
if(instanceType is not null)
|
||||||
|
{
|
||||||
|
flowClasss.Add(instanceType);
|
||||||
|
assemblyFlowClasss.Add(instanceType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成方法信息
|
||||||
|
foreach (var node in canvas.Nodes)
|
||||||
|
{
|
||||||
|
var instanceType = node.MethodDetails.ActingInstanceType;
|
||||||
|
var returnType = node.MethodDetails.ReturnType;
|
||||||
|
var methodName = node.MethodDetails.MethodAnotherName;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var instanceTypeFullName = instanceType.FullName;
|
||||||
|
var returnTypeFullName = returnType == typeof(void) ? "void" : returnType.FullName;
|
||||||
|
|
||||||
|
string methodContext = $"private {returnTypeFullName} NodeMethod_{methodName}({nameof(IDynamicContext)} context)";
|
||||||
|
SereinEnv.WriteLine(InfoType.INFO, methodContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,12 +50,12 @@ namespace Serein.NodeFlow.Services
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 重做
|
/// 重做
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Redo()
|
public async Task Redo()
|
||||||
{
|
{
|
||||||
if (redoStack.Count > 0)
|
if (redoStack.Count > 0)
|
||||||
{
|
{
|
||||||
var command = redoStack.Pop();
|
var command = redoStack.Pop();
|
||||||
var state = command.Execute();
|
var state = await command.ExecuteAsync();
|
||||||
if (state)
|
if (state)
|
||||||
{
|
{
|
||||||
undoStack.Push(command); // 将重做的命令推入撤销栈
|
undoStack.Push(command); // 将重做的命令推入撤销栈
|
||||||
@@ -64,10 +64,10 @@ namespace Serein.NodeFlow.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal void Execute(IOperation operation)
|
internal async Task Execute(IOperation operation)
|
||||||
{
|
{
|
||||||
sereinIOC.InjectDependenciesProperty(operation); // 注入所需要的依赖
|
sereinIOC.InjectDependenciesProperty(operation); // 注入所需要的依赖
|
||||||
var state = operation.Execute();
|
var state = await operation.ExecuteAsync();
|
||||||
if (state)
|
if (state)
|
||||||
{
|
{
|
||||||
// 执行后,推入撤销栈,并清空重做栈
|
// 执行后,推入撤销栈,并清空重做栈
|
||||||
|
|||||||
@@ -273,14 +273,11 @@ namespace Serein.NodeFlow.Services
|
|||||||
var pool = WorkOptions.FlowContextPool;
|
var pool = WorkOptions.FlowContextPool;
|
||||||
var context = pool.Allocate();
|
var context = pool.Allocate();
|
||||||
var token = WorkOptions.CancellationTokenSource.Token;
|
var token = WorkOptions.CancellationTokenSource.Token;
|
||||||
await startNode.StartFlowAsync(context, token); // 开始运行时从选定节点开始运行
|
var result = await startNode.StartFlowAsync(context, token); // 开始运行时从选定节点开始运行
|
||||||
context.Reset();
|
context.Reset();
|
||||||
pool.Free(context);
|
pool.Free(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 尝试添加全局触发器
|
/// 尝试添加全局触发器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -295,6 +292,7 @@ namespace Serein.NodeFlow.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 尝试移除全局触发器
|
/// 尝试移除全局触发器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -344,7 +342,7 @@ namespace Serein.NodeFlow.Services
|
|||||||
{
|
{
|
||||||
var context = pool.Allocate(); // 启动全局触发器时新建上下文
|
var context = pool.Allocate(); // 启动全局触发器时新建上下文
|
||||||
var newFlowData = await singleFlipFlopNode.ExecutingAsync(context, singleToken); // 获取触发器等待Task
|
var newFlowData = await singleFlipFlopNode.ExecutingAsync(context, singleToken); // 获取触发器等待Task
|
||||||
context.AddOrUpdate(singleFlipFlopNode, newFlowData);
|
context.AddOrUpdate(singleFlipFlopNode.Guid, newFlowData);
|
||||||
if (context.NextOrientation == ConnectionInvokeType.None)
|
if (context.NextOrientation == ConnectionInvokeType.None)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -388,7 +386,7 @@ namespace Serein.NodeFlow.Services
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
context.SetPreviousNode(nextNodes[i], singleFlipFlopNode); // 设置调用关系
|
context.SetPreviousNode(nextNodes[i].Guid, singleFlipFlopNode.Guid); // 设置调用关系
|
||||||
|
|
||||||
if (nextNodes[i].DebugSetting.IsInterrupt) // 执行触发前检查终端
|
if (nextNodes[i].DebugSetting.IsInterrupt) // 执行触发前检查终端
|
||||||
{
|
{
|
||||||
@@ -407,7 +405,7 @@ namespace Serein.NodeFlow.Services
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
context.SetPreviousNode(nextNodes[i], singleFlipFlopNode);
|
context.SetPreviousNode(nextNodes[i].Guid, singleFlipFlopNode.Guid);
|
||||||
if (nextNodes[i].DebugSetting.IsInterrupt) // 执行触发前
|
if (nextNodes[i].DebugSetting.IsInterrupt) // 执行触发前
|
||||||
{
|
{
|
||||||
await nextNodes[i].DebugSetting.GetInterruptTask.Invoke();
|
await nextNodes[i].DebugSetting.GetInterruptTask.Invoke();
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ using Serein.Workbench.Services;
|
|||||||
using Serein.Workbench.ViewModels;
|
using Serein.Workbench.ViewModels;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
|
using static System.Net.Mime.MediaTypeNames;
|
||||||
|
|
||||||
namespace Serein.Workbench
|
namespace Serein.Workbench
|
||||||
{
|
{
|
||||||
@@ -20,7 +22,7 @@ namespace Serein.Workbench
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for App.xaml
|
/// Interaction logic for App.xaml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class App : Application
|
public partial class App : System.Windows.Application
|
||||||
{
|
{
|
||||||
private static IServiceProvider? ServiceProvider;
|
private static IServiceProvider? ServiceProvider;
|
||||||
|
|
||||||
@@ -28,12 +30,12 @@ namespace Serein.Workbench
|
|||||||
/// UI线程
|
/// UI线程
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static UIContextOperation UIContextOperation => App.GetService<UIContextOperation>() ?? throw new NullReferenceException();
|
public static UIContextOperation UIContextOperation => App.GetService<UIContextOperation>() ?? throw new NullReferenceException();
|
||||||
|
|
||||||
public static T GetService<T>() where T : class
|
public static T GetService<T>() where T : class
|
||||||
{
|
{
|
||||||
return ServiceProvider?.GetService<T>() ?? throw new NullReferenceException();
|
return ServiceProvider?.GetService<T>() ?? throw new NullReferenceException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public App()
|
public App()
|
||||||
{
|
{
|
||||||
var collection = new ServiceCollection();
|
var collection = new ServiceCollection();
|
||||||
|
|||||||
@@ -75,7 +75,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AvalonEdit" Version="6.3.0.90" />
|
<PackageReference Include="AvalonEdit" Version="6.3.0.90" />
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.3" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.6" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -63,10 +63,12 @@ namespace Serein.Workbench
|
|||||||
getSyncContext = () => uiContext;
|
getSyncContext = () => uiContext;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
UIContextOperation? uIContextOperation = null;
|
UIContextOperation? uIContextOperation = new (getSyncContext); // 封装一个调用UI线程的工具类
|
||||||
uIContextOperation = new UIContextOperation(getSyncContext); // 封装一个调用UI线程的工具类
|
IFlowEnvironment flowEnvironment = new FlowEnvironment();
|
||||||
var flowEnvironment = new FlowEnvironment();
|
|
||||||
flowEnvironment.SetUIContextOperation(uIContextOperation);
|
flowEnvironment.SetUIContextOperation(uIContextOperation);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
collection.AddSingleton<UIContextOperation>(uIContextOperation); // 注册UI线程操作上下文
|
collection.AddSingleton<UIContextOperation>(uIContextOperation); // 注册UI线程操作上下文
|
||||||
collection.AddSingleton<IFlowEnvironment>(flowEnvironment); // 注册运行环境
|
collection.AddSingleton<IFlowEnvironment>(flowEnvironment); // 注册运行环境
|
||||||
collection.AddSingleton<IFlowEnvironmentEvent>(flowEnvironment.Event); // 注册运行环境事件
|
collection.AddSingleton<IFlowEnvironmentEvent>(flowEnvironment.Event); // 注册运行环境事件
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ using Serein.Library.Utils;
|
|||||||
using Serein.Workbench.Avalonia.Api;
|
using Serein.Workbench.Avalonia.Api;
|
||||||
using Serein.Workbench.Api;
|
using Serein.Workbench.Api;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel;
|
||||||
|
|
||||||
namespace Serein.Workbench.Services
|
namespace Serein.Workbench.Services
|
||||||
{
|
{
|
||||||
@@ -184,10 +185,11 @@ namespace Serein.Workbench.Services
|
|||||||
/// <param name="value"></param>
|
/// <param name="value"></param>
|
||||||
private void FlowEnvironment_OnEnvOutEvent(InfoType type, string value)
|
private void FlowEnvironment_OnEnvOutEvent(InfoType type, string value)
|
||||||
{
|
{
|
||||||
uiContextOperation.Invoke(() =>
|
|
||||||
|
System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
|
||||||
{
|
{
|
||||||
EnvOutput?.Invoke(type, value);
|
EnvOutput?.Invoke(type, value);
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -197,7 +199,10 @@ namespace Serein.Workbench.Services
|
|||||||
/// <exception cref="NotImplementedException"></exception>
|
/// <exception cref="NotImplementedException"></exception>
|
||||||
private void FlowEnvironment_OnProjectSaving(ProjectSavingEventArgs eventArgs)
|
private void FlowEnvironment_OnProjectSaving(ProjectSavingEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
ProjectSaving?.Invoke(eventArgs);
|
System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
|
||||||
|
{
|
||||||
|
ProjectSaving?.Invoke(eventArgs);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -206,7 +211,10 @@ namespace Serein.Workbench.Services
|
|||||||
/// <param name="eventArgs"></param>
|
/// <param name="eventArgs"></param>
|
||||||
private void FlowEnvironment_OnProjectLoaded(ProjectLoadedEventArgs eventArgs)
|
private void FlowEnvironment_OnProjectLoaded(ProjectLoadedEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
ProjectLoaded?.Invoke(eventArgs);
|
System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
|
||||||
|
{
|
||||||
|
ProjectLoaded?.Invoke(eventArgs);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -216,8 +224,11 @@ namespace Serein.Workbench.Services
|
|||||||
/// <exception cref="NotImplementedException"></exception>
|
/// <exception cref="NotImplementedException"></exception>
|
||||||
private void FlowEnvironment_OnFlowRunCompleteEvent(FlowEventArgs eventArgs)
|
private void FlowEnvironment_OnFlowRunCompleteEvent(FlowEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
SereinEnv.WriteLine(InfoType.INFO, "-------运行完成---------\r\n");
|
System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
|
||||||
FlowRunComplete?.Invoke(eventArgs);
|
{
|
||||||
|
SereinEnv.WriteLine(InfoType.INFO, "-------运行完成---------\r\n");
|
||||||
|
FlowRunComplete?.Invoke(eventArgs);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -225,7 +236,10 @@ namespace Serein.Workbench.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void FlowEnvironment_DllLoadEvent(LoadDllEventArgs eventArgs)
|
private void FlowEnvironment_DllLoadEvent(LoadDllEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
DllLoad?.Invoke(eventArgs);
|
System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
|
||||||
|
{
|
||||||
|
DllLoad?.Invoke(eventArgs);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -234,11 +248,10 @@ namespace Serein.Workbench.Services
|
|||||||
/// <param name="eventArgs"></param>
|
/// <param name="eventArgs"></param>
|
||||||
private void FlowEnvironment_NodeConnectChangeEvemt(NodeConnectChangeEventArgs eventArgs)
|
private void FlowEnvironment_NodeConnectChangeEvemt(NodeConnectChangeEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
uiContextOperation.Invoke(() =>
|
System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
|
||||||
{
|
{
|
||||||
Debug.WriteLine(DateTime.Now, $"Node Connect Changed");
|
|
||||||
NodeConnectChanged?.Invoke(eventArgs);
|
NodeConnectChanged?.Invoke(eventArgs);
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -249,10 +262,10 @@ namespace Serein.Workbench.Services
|
|||||||
/// <exception cref="NotImplementedException"></exception>
|
/// <exception cref="NotImplementedException"></exception>
|
||||||
private void FlowEnvironmentEvent_OnCanvasCreate(CanvasCreateEventArgs eventArgs)
|
private void FlowEnvironmentEvent_OnCanvasCreate(CanvasCreateEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
uiContextOperation?.Invoke(() =>
|
System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
|
||||||
{
|
{
|
||||||
CanvasCreated?.Invoke(eventArgs);
|
CanvasCreated?.Invoke(eventArgs);
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -262,7 +275,10 @@ namespace Serein.Workbench.Services
|
|||||||
/// <exception cref="NotImplementedException"></exception>
|
/// <exception cref="NotImplementedException"></exception>
|
||||||
private void FlowEnvironmentEvent_OnCanvasRemove(CanvasRemoveEventArgs eventArgs)
|
private void FlowEnvironmentEvent_OnCanvasRemove(CanvasRemoveEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
CanvasRemoved?.Invoke(eventArgs);
|
System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
|
||||||
|
{
|
||||||
|
CanvasRemoved?.Invoke(eventArgs);
|
||||||
|
}));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,7 +288,10 @@ namespace Serein.Workbench.Services
|
|||||||
/// <param name="eventArgs"></param>
|
/// <param name="eventArgs"></param>
|
||||||
private void FlowEnvironment_NodeRemoveEvent(NodeRemoveEventArgs eventArgs)
|
private void FlowEnvironment_NodeRemoveEvent(NodeRemoveEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
NodeRemoved?.Invoke(eventArgs);
|
System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
|
||||||
|
{
|
||||||
|
NodeRemoved?.Invoke(eventArgs);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -282,11 +301,11 @@ namespace Serein.Workbench.Services
|
|||||||
/// <exception cref="NotImplementedException"></exception>
|
/// <exception cref="NotImplementedException"></exception>
|
||||||
private void FlowEnvironment_NodeCreateEvent(NodeCreateEventArgs eventArgs)
|
private void FlowEnvironment_NodeCreateEvent(NodeCreateEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
uiContextOperation.Invoke(() =>
|
System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
|
||||||
{
|
{
|
||||||
Debug.WriteLine(DateTime.Now, $"Create Node {eventArgs.NodeModel.Guid}");
|
Debug.WriteLine(DateTime.Now, $"Create Node {eventArgs.NodeModel.Guid}");
|
||||||
NodeCreated?.Invoke(eventArgs);
|
NodeCreated?.Invoke(eventArgs);
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -296,7 +315,10 @@ namespace Serein.Workbench.Services
|
|||||||
/// <exception cref="NotImplementedException"></exception>
|
/// <exception cref="NotImplementedException"></exception>
|
||||||
private void FlowEnvironment_OnNodePlaceEvent(NodePlaceEventArgs eventArgs)
|
private void FlowEnvironment_OnNodePlaceEvent(NodePlaceEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
NodePlace?.Invoke(eventArgs);
|
System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
|
||||||
|
{
|
||||||
|
NodePlace?.Invoke(eventArgs);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -305,19 +327,23 @@ namespace Serein.Workbench.Services
|
|||||||
/// <param name="eventArgs"></param>
|
/// <param name="eventArgs"></param>
|
||||||
private void FlowEnvironment_OnNodeTakeOutEvent(NodeTakeOutEventArgs eventArgs)
|
private void FlowEnvironment_OnNodeTakeOutEvent(NodeTakeOutEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
NodeTakeOut?.Invoke(eventArgs);
|
System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
|
||||||
|
{
|
||||||
|
NodeTakeOut?.Invoke(eventArgs);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置了流程起始控件
|
/// 设置了流程起始控件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="oldNodeGuid"></param>
|
/// <param name="eventArgs"></param>
|
||||||
/// <param name="newNodeGuid"></param>
|
|
||||||
private void FlowEnvironment_StartNodeChangeEvent(StartNodeChangeEventArgs eventArgs)
|
private void FlowEnvironment_StartNodeChangeEvent(StartNodeChangeEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
|
System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
|
||||||
StartNodeChanged?.Invoke(eventArgs);
|
{
|
||||||
|
StartNodeChanged?.Invoke(eventArgs);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -326,7 +352,10 @@ namespace Serein.Workbench.Services
|
|||||||
/// <param name="eventArgs"></param>
|
/// <param name="eventArgs"></param>
|
||||||
private void FlowEnvironment_OnMonitorObjectChangeEvent(MonitorObjectEventArgs eventArgs)
|
private void FlowEnvironment_OnMonitorObjectChangeEvent(MonitorObjectEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
MonitorObjectChanged?.Invoke(eventArgs);
|
System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
|
||||||
|
{
|
||||||
|
MonitorObjectChanged?.Invoke(eventArgs);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ namespace Serein.Workbench.Services
|
|||||||
{
|
{
|
||||||
private readonly IFlowEnvironment flowEnvironment;
|
private readonly IFlowEnvironment flowEnvironment;
|
||||||
|
|
||||||
public SereinProjectData? FlowProjectData { get; set; }
|
|
||||||
public string FileDataPath { get; set; }
|
|
||||||
|
|
||||||
public FlowProjectService(IFlowEnvironment flowEnvironment)
|
public FlowProjectService(IFlowEnvironment flowEnvironment)
|
||||||
{
|
{
|
||||||
@@ -32,15 +30,13 @@ namespace Serein.Workbench.Services
|
|||||||
{
|
{
|
||||||
if (File.Exists(filePath))
|
if (File.Exists(filePath))
|
||||||
{
|
{
|
||||||
string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
|
/*
|
||||||
this.FlowProjectData = JsonConvert.DeserializeObject<SereinProjectData>(content);
|
|
||||||
this.FileDataPath = System.IO.Path.GetDirectoryName(filePath)!; // filePath;//
|
|
||||||
var dir = Path.GetDirectoryName(filePath);
|
var dir = Path.GetDirectoryName(filePath);
|
||||||
var flowEnvInfo = new FlowEnvInfo
|
var flowEnvInfo = new FlowEnvInfo
|
||||||
{
|
{
|
||||||
Project = FlowProjectData,
|
Project = FlowProjectData,
|
||||||
};
|
};*/
|
||||||
flowEnvironment.LoadProject(flowEnvInfo, FileDataPath);
|
flowEnvironment.LoadProject(filePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user