Files
serein-flow/NodeFlow/Base/NodeModelBaseFunc.cs
2024-09-25 22:20:23 +08:00

496 lines
22 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Serein.Library.Api;
using Serein.Library.Entity;
using Serein.Library.Enums;
using Serein.Library.Ex;
using Serein.NodeFlow.Tool.SereinExpression;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using static Serein.Library.Utils.ChannelFlowInterrupt;
namespace Serein.NodeFlow.Base
{
/// <summary>
/// 节点基类(数据):条件控件,动作控件,条件区域,动作区域
/// </summary>
public abstract partial class NodeModelBase : IDynamicFlowNode
{
#region
/// <summary>
/// 不再中断
/// </summary>
public void CancelInterrupt()
{
this.DebugSetting.InterruptClass = InterruptClass.None;
DebugSetting.CancelInterruptCallback?.Invoke();
}
#endregion
#region /
internal abstract Parameterdata[] GetParameterdatas();
internal virtual NodeInfo ToInfo()
{
// if (MethodDetails == null) return null;
var trueNodes = SuccessorNodes[ConnectionType.IsSucceed].Select(item => item.Guid); // 真分支
var falseNodes = SuccessorNodes[ConnectionType.IsFail].Select(item => item.Guid);// 假分支
var errorNodes = SuccessorNodes[ConnectionType.IsError].Select(item => item.Guid);// 异常分支
var upstreamNodes = SuccessorNodes[ConnectionType.Upstream].Select(item => item.Guid);// 上游分支
// 生成参数列表
Parameterdata[] parameterData = GetParameterdatas();
return new NodeInfo
{
Guid = Guid,
MethodName = MethodDetails?.MethodName,
Label = DisplayName ?? "",
Type = this.GetType().ToString(),
TrueNodes = trueNodes.ToArray(),
FalseNodes = falseNodes.ToArray(),
UpstreamNodes = upstreamNodes.ToArray(),
ParameterData = parameterData.ToArray(),
ErrorNodes = errorNodes.ToArray(),
};
}
internal virtual NodeModelBase LoadInfo(NodeInfo nodeInfo)
{
var node = this;
if (node != null)
{
node.Guid = nodeInfo.Guid;
for (int i = 0; i < nodeInfo.ParameterData.Length; i++)
{
Parameterdata? pd = nodeInfo.ParameterData[i];
node.MethodDetails.ExplicitDatas[i].IsExplicitData = pd.State;
node.MethodDetails.ExplicitDatas[i].DataValue = pd.Value;
}
}
return this;
}
#endregion
#region
/// <summary>
/// 开始执行
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public async Task StartExecute(IDynamicContext context)
{
Stack<NodeModelBase> stack = new Stack<NodeModelBase>();
stack.Push(this);
var cts = context.Env.IOC.Get<CancellationTokenSource>(FlowStarter.FlipFlopCtsName);
while (stack.Count > 0 ) // 循环中直到栈为空才会退出循环
{
if(cts is not null)
{
if (cts.IsCancellationRequested)
break;
}
// 节点执行异常时跳过执行
// 从栈中弹出一个节点作为当前节点进行处理
var currentNode = stack.Pop();
// 设置方法执行的对象
if (currentNode.MethodDetails?.ActingInstance is not null && currentNode.MethodDetails?.ActingInstanceType is not null)
{
currentNode.MethodDetails.ActingInstance = context.Env.IOC.GetOrRegisterInstantiate(currentNode.MethodDetails.ActingInstanceType);
}
#region
// 首先执行上游分支
var upstreamNodes = currentNode.SuccessorNodes[ConnectionType.Upstream];
for (int i = upstreamNodes.Count - 1; i >= 0; i--)
{
// 筛选出启用的节点
if (upstreamNodes[i].DebugSetting.IsEnable)
{
if (upstreamNodes[i].DebugSetting.InterruptClass != InterruptClass.None) // 执行触发前
{
var cancelType = await upstreamNodes[i].DebugSetting.GetInterruptTask();
await Console.Out.WriteLineAsync($"[{upstreamNodes[i].MethodDetails.MethodName}]中断已{cancelType},开始执行后继分支");
}
upstreamNodes[i].PreviousNode = currentNode;
await upstreamNodes[i].StartExecute(context); // 执行流程节点的上游分支
}
}
// 执行当前节点
object? newFlowData = await currentNode.ExecutingAsync(context);
if (cts is null || cts.IsCancellationRequested || currentNode.NextOrientation == ConnectionType.None)
{
// 不再执行
break;
}
await RefreshFlowDataAndExpInterrupt(context, currentNode, newFlowData); // 执行当前节点后刷新数据
#endregion
#region
// 选择后继分支
var nextNodes = currentNode.SuccessorNodes[currentNode.NextOrientation];
// 将下一个节点集合中的所有节点逆序推入栈中
for (int i = nextNodes.Count - 1; i >= 0; i--)
{
// 筛选出启用的节点、未被中断的节点
if (nextNodes[i].DebugSetting.IsEnable /*&& nextNodes[i].DebugSetting.InterruptClass == InterruptClass.None*/)
{
if (nextNodes[i].DebugSetting.InterruptClass != InterruptClass.None) // 执行触发前
{
var cancelType = await nextNodes[i].DebugSetting.GetInterruptTask();
await Console.Out.WriteLineAsync($"[{nextNodes[i].MethodDetails.MethodName}]中断已{cancelType},开始执行后继分支");
}
nextNodes[i].PreviousNode = currentNode;
stack.Push(nextNodes[i]);
}
}
#endregion
}
}
/// <summary>
/// 执行节点对应的方法
/// </summary>
/// <param name="context">流程上下文</param>
/// <returns>节点传回数据对象</returns>
public virtual async Task<object?> ExecutingAsync(IDynamicContext context)
{
#region
if (DebugSetting.InterruptClass != InterruptClass.None) // 执行触发前
{
var cancelType = await this.DebugSetting.GetInterruptTask();
//if(cancelType == CancelType.Discard)
//{
// this.NextOrientation = ConnectionType.None;
// return null;
//}
await Console.Out.WriteLineAsync($"[{this.MethodDetails.MethodName}]中断已{cancelType},开始执行后继分支");
}
#endregion
MethodDetails md = MethodDetails;
var del = md.MethodDelegate.Clone();
object instance = md.ActingInstance;
var haveParameter = md.ExplicitDatas.Length > 0;
var haveResult = md.ReturnType != typeof(void);
try
{
// Action/Func([方法作用的实例],[可能的参数值],[可能的返回值])
object?[]? parameters = GetParameters(context, this, md);
object? result = (haveParameter, haveResult) switch
{
(false, false) => Execution((Action<object>)del, instance), // 调用节点方法返回null
(true, false) => Execution((Action<object, object?[]?>)del, instance, parameters), // 调用节点方法返回null
(false, true) => Execution((Func<object, object?>)del, instance), // 调用节点方法,返回方法传回类型
(true, true) => Execution((Func<object, object?[]?, object?>)del, instance, parameters), // 调用节点方法,获取入参参数,返回方法忏悔类型
};
NextOrientation = ConnectionType.IsSucceed;
return result;
}
catch (Exception ex)
{
NextOrientation = ConnectionType.IsError;
RuningException = ex;
return null;
}
}
#region
public static object? Execution(Action<object> del, object instance)
{
del?.Invoke(instance);
return null;
}
public static object? Execution(Action<object, object?[]?> del, object instance, object?[]? parameters)
{
del?.Invoke(instance, parameters);
return null;
}
public static object? Execution(Func<object, object?> del, object instance)
{
return del?.Invoke(instance);
}
public static object? Execution(Func<object, object?[]?, object?> del, object instance, object?[]? parameters)
{
return del?.Invoke(instance, parameters);
}
#endregion
/// <summary>
/// 获取对应的参数数组
/// </summary>
public static object?[]? GetParameters(IDynamicContext context, NodeModelBase nodeModel, MethodDetails md)
{
// 用正确的大小初始化参数数组
if (md.ExplicitDatas.Length == 0)
{
return null;// md.ActingInstance
}
object?[]? parameters = new object[md.ExplicitDatas.Length];
var flowData = nodeModel.PreviousNode?.FlowData; // 当前传递的数据
var previousDataType = flowData?.GetType();
for (int i = 0; i < parameters.Length; i++)
{
object? inputParameter; // 存放解析的临时参数
var ed = md.ExplicitDatas[i]; // 方法入参描述
if (ed.IsExplicitData)
{
if (ed.DataValue.StartsWith("@get", StringComparison.OrdinalIgnoreCase))
{
// 执行表达式从上一节点获取对象
inputParameter = SerinExpressionEvaluator.Evaluate(ed.DataValue, flowData, out _);
}
else
{
// 使用输入的固定值
inputParameter = ed.DataValue;
}
}
else
{
inputParameter = flowData; // 使用上一节点的对象
}
try
{
parameters[i] = ed.DataType switch
{
//Type t when t == previousDataType => inputParameter, // 上下文
Type t when t == typeof(IDynamicContext) => context, // 上下文
Type t when t == typeof(MethodDetails) => md, // 节点方法描述
Type t when t == typeof(NodeModelBase) => nodeModel, // 节点实体类
Type t when t == typeof(Guid) => new Guid(inputParameter?.ToString()),
Type t when t == typeof(DateTime) => DateTime.Parse(inputParameter?.ToString()),
Type t when t == typeof(string) => inputParameter?.ToString(),
Type t when t == typeof(char) => char.Parse(inputParameter?.ToString()),
Type t when t == typeof(bool) => inputParameter is null ? false : bool.Parse(inputParameter?.ToString()),
Type t when t == typeof(float) => inputParameter is null ? 0F : float.Parse(inputParameter?.ToString()),
Type t when t == typeof(decimal) => inputParameter is null ? 0 : decimal.Parse(inputParameter?.ToString()),
Type t when t == typeof(double) => inputParameter is null ? 0 : double.Parse(inputParameter?.ToString()),
Type t when t == typeof(sbyte) => inputParameter is null ? 0 : sbyte.Parse(inputParameter?.ToString()),
Type t when t == typeof(byte) => inputParameter is null ? 0 : byte.Parse(inputParameter?.ToString()),
Type t when t == typeof(short) => inputParameter is null ? 0 : short.Parse(inputParameter?.ToString()),
Type t when t == typeof(ushort) => inputParameter is null ? 0U : ushort.Parse(inputParameter?.ToString()),
Type t when t == typeof(int) => inputParameter is null ? 0 : int.Parse(inputParameter?.ToString()),
Type t when t == typeof(uint) => inputParameter is null ? 0U : uint.Parse(inputParameter?.ToString()),
Type t when t == typeof(long) => inputParameter is null ? 0L : long.Parse(inputParameter?.ToString()),
Type t when t == typeof(ulong) => inputParameter is null ? 0UL : ulong.Parse(inputParameter?.ToString()),
Type t when t == typeof(nint) => inputParameter is null ? 0 : nint.Parse(inputParameter?.ToString()),
Type t when t == typeof(nuint) => inputParameter is null ? 0 : nuint.Parse(inputParameter?.ToString()),
Type t when t.IsEnum => Enum.Parse(ed.DataType, ed.DataValue),// 需要枚举
Type t when t.IsArray => (inputParameter as Array)?.Cast<object>().ToList(),
Type t when t.IsGenericType && t.GetGenericTypeDefinition() == typeof(List<>) => inputParameter,
Type t when Nullable.GetUnderlyingType(t) != null => inputParameter is null ? null : Convert.ChangeType(inputParameter, Nullable.GetUnderlyingType(t)),
_ => inputParameter,
};
}
catch (Exception ex) // 节点参数类型转换异常
{
parameters[i] = null;
Console.WriteLine(ex);
}
}
return parameters;
}
/// <summary>
/// 更新节点数据,并检查监视表达式是否生效
/// </summary>
/// <param name="newData"></param>
public static async Task RefreshFlowDataAndExpInterrupt(IDynamicContext context,NodeModelBase nodeModel, object? newData = null)
{
string guid = nodeModel.Guid;
if(newData is not null)
{
await MonitorObjExpInterrupt(context, nodeModel, newData, 0); // 首先监视对象
await MonitorObjExpInterrupt(context, nodeModel, newData, 1); // 然后监视节点
nodeModel.FlowData = newData; // 替换数据
}
//if(context.Env.CheckObjMonitorState(newData, out List<string> exps)) // 如果新的数据处于查看状态通知UI进行更新交给运行环境判断
//{
// context.Env.MonitorObjectNotification(guid, newData); // 对象处于监视状态通知UI更新数据显示
// if (exps.Count > 0)
// {
// // 表达式环境下判断是否需要执行中断
// bool isExpInterrupt = false;
// string? exp = "";
// // 判断执行监视表达式,直到为 true 时退出
// for (int i = 0; i < exps.Count && !isExpInterrupt; i++)
// {
// exp = exps[i];
// isExpInterrupt = SereinConditionParser.To(newData, exp);
// }
// if (isExpInterrupt) // 触发中断
// {
// InterruptClass interruptClass = InterruptClass.Branch; // 分支中断
// if (context.Env.SetNodeInterrupt(nodeModel.Guid, interruptClass))
// {
// context.Env.TriggerInterrupt(guid, exp, InterruptTriggerEventArgs.InterruptTriggerType.Obj);
// var cancelType = await nodeModel.DebugSetting.GetInterruptTask();
// await Console.Out.WriteLineAsync($"[{newData}]中断已{cancelType},开始执行后继分支");
// }
// }
// }
//}
//if (newData is not null && nodeModel.DebugSetting.InterruptExpressions.Count > 0) // 检查节点是否存在监视表达式
//{
// // 表达式环境下判断是否需要执行中断
// bool isExpInterrupt = false;
// string? exp = "";
// // 判断执行监视表达式,直到为 true 时退出
// for (int i = 0; i < nodeModel.DebugSetting.InterruptExpressions.Count && !isExpInterrupt; i++)
// {
// exp = nodeModel.DebugSetting.InterruptExpressions[i];
// isExpInterrupt = SereinConditionParser.To(newData, exp);
// }
// if (isExpInterrupt) // 触发中断
// {
// InterruptClass interruptClass = InterruptClass.Branch; // 分支中断
// if (context.Env.SetNodeInterrupt(nodeModel.Guid, interruptClass))
// {
// context.Env.TriggerInterrupt(guid, exp, InterruptTriggerEventArgs.InterruptTriggerType.Exp);
// var cancelType = await nodeModel.DebugSetting.GetInterruptTask();
// await Console.Out.WriteLineAsync($"[{nodeModel.MethodDetails.MethodName}]中断已{cancelType},开始执行后继分支");
// }
// }
//}
//else if (nodeModel.DebugSetting.InterruptClass != InterruptClass.None)
//{
// var cancelType = await nodeModel.DebugSetting.InterruptTask;
// await Console.Out.WriteLineAsync($"[{nodeModel.MethodDetails.MethodName}]中断已{(cancelType == CancelType.Manual ? "手动取消" : "自动取消")},开始执行后继分支");
//}
//if (nodeModel.DebugSetting.IsMonitorFlowData)
//{
// // 节点是否监视了数据,如果是,调用环境接口触发其相关事件。
// context.Env.FlowDataNotification(guid, newData);
//}
}
private static async Task MonitorObjExpInterrupt(IDynamicContext context, NodeModelBase nodeModel, object data, int type)
{
MonitorObjectEventArgs.ObjSourceType sourceType;
object key;
if(type == 0)
{
key = data;
sourceType = MonitorObjectEventArgs.ObjSourceType.IOCObj;
}
else
{
key = nodeModel.Guid;
sourceType = MonitorObjectEventArgs.ObjSourceType.IOCObj;
}
if (context.Env.CheckObjMonitorState(key, out List<string> exps)) // 如果新的数据处于查看状态通知UI进行更新交给运行环境判断
{
context.Env.MonitorObjectNotification(nodeModel.Guid, data, sourceType); // 对象处于监视状态通知UI更新数据显示
if (exps.Count > 0)
{
// 表达式环境下判断是否需要执行中断
bool isExpInterrupt = false;
string? exp = "";
// 判断执行监视表达式,直到为 true 时退出
for (int i = 0; i < exps.Count && !isExpInterrupt; i++)
{
exp = exps[i];
isExpInterrupt = SereinConditionParser.To(data, exp);
}
if (isExpInterrupt) // 触发中断
{
InterruptClass interruptClass = InterruptClass.Branch; // 分支中断
if (context.Env.SetNodeInterrupt(nodeModel.Guid, interruptClass))
{
context.Env.TriggerInterrupt(nodeModel.Guid, exp, InterruptTriggerEventArgs.InterruptTriggerType.Obj);
var cancelType = await nodeModel.DebugSetting.GetInterruptTask();
await Console.Out.WriteLineAsync($"[{data}]中断已{cancelType},开始执行后继分支");
}
}
}
}
}
/// <summary>
/// 释放对象
/// </summary>
public void ReleaseFlowData()
{
if (typeof(IDisposable).IsAssignableFrom(FlowData?.GetType()) && FlowData is IDisposable disposable)
{
disposable?.Dispose();
}
this.FlowData = null;
}
/// <summary>
/// 获取节点数据
/// </summary>
/// <returns></returns>
public object? GetFlowData()
{
return this.FlowData;
}
#endregion
}
}