Files
serein-flow/NodeFlow/Base/NodeModelBaseFunc.cs
2024-09-17 14:30:19 +08:00

523 lines
20 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 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.Text;
using System.Threading.Tasks;
namespace Serein.NodeFlow.Base
{
/// <summary>
/// 节点基类(数据):条件控件,动作控件,条件区域,动作区域
/// </summary>
public abstract partial class NodeModelBase : IDynamicFlowNode
{
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;
}
}
//if (control is ConditionNodeControl conditionNodeControl)
//{
// conditionNodeControl.ViewModel.IsCustomData = pd.state;
// conditionNodeControl.ViewModel.CustomData = pd.value;
// conditionNodeControl.ViewModel.Expression = pd.expression;
//}
//else if (control is ExpOpNodeControl expOpNodeControl)
//{
// expOpNodeControl.ViewModel.Expression = pd.expression;
//}
//else
//{
// node.MethodDetails.ExplicitDatas[i].IsExplicitData = pd.state;
// node.MethodDetails.ExplicitDatas[i].DataValue = pd.value;
//}
return this;
}
/// <summary>
/// 开始执行
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public async Task StartExecution(IDynamicContext context)
{
var cts = context.SereinIoc.GetOrRegisterInstantiate<CancellationTokenSource>();
Stack<NodeModelBase> stack = [];
stack.Push(this);
while (stack.Count > 0 && !cts.IsCancellationRequested) // 循环中直到栈为空才会退出循环
{
// 从栈中弹出一个节点作为当前节点进行处理
var currentNode = stack.Pop();
// 设置方法执行的对象
if (currentNode.MethodDetails is not null && currentNode.MethodDetails.ActingInstanceType is not null)
{
// currentNode.MethodDetails.ActingInstance ??= context.SereinIoc.GetOrInstantiate(MethodDetails.ActingInstanceType);
// currentNode.MethodDetails.ActingInstance = context.SereinIoc.GetOrInstantiate(MethodDetails.ActingInstanceType);
currentNode.MethodDetails.ActingInstance = context.SereinIoc.GetOrRegisterInstantiate(currentNode.MethodDetails.ActingInstanceType);
}
// 获取上游分支,首先执行一次
var upstreamNodes = currentNode.SuccessorNodes[ConnectionType.Upstream];
for (int i = upstreamNodes.Count - 1; i >= 0; i--)
{
upstreamNodes[i].PreviousNode = currentNode;
await upstreamNodes[i].StartExecution(context);
}
if (currentNode.MethodDetails != null && currentNode.MethodDetails.MethodDynamicType == NodeType.Flipflop)
{
// 触发器节点
currentNode.FlowData = await currentNode.ExecuteAsync(context);
}
else
{
// 动作节点
currentNode.FlowData = currentNode.Execute(context);
}
if(currentNode.NextOrientation == ConnectionType.None)
{
// 不再执行
break;
}
var nextNodes = currentNode.SuccessorNodes[currentNode.NextOrientation];
// 将下一个节点集合中的所有节点逆序推入栈中
for (int i = nextNodes.Count - 1; i >= 0; i--)
{
nextNodes[i].PreviousNode = currentNode;
stack.Push(nextNodes[i]);
}
}
}
/// <summary>
/// 执行节点对应的方法
/// </summary>
/// <param name="context">流程上下文</param>
/// <returns>节点传回数据对象</returns>
public virtual object? Execute(IDynamicContext context)
{
MethodDetails md = MethodDetails;
object? result = null;
var del = md.MethodDelegate;
try
{
if (md.ExplicitDatas.Length == 0)
{
if (md.ReturnType == typeof(void))
{
((Action<object>)del).Invoke(md.ActingInstance);
}
else
{
result = ((Func<object, object>)del).Invoke(md.ActingInstance);
}
}
else
{
object?[]? parameters = GetParameters(context, MethodDetails);
if (md.ReturnType == typeof(void))
{
((Action<object, object[]>)del).Invoke(md.ActingInstance, parameters);
}
else
{
var func = del as Func<object, object[], object>;
//result = ((Func<object, object[], object>)del).Invoke(md.ActingInstance, parameters);
result = func?.Invoke(md.ActingInstance, parameters);
}
}
NextOrientation = ConnectionType.IsSucceed;
return result;
}
catch (Exception ex)
{
NextOrientation = ConnectionType.IsError;
RuningException = ex;
}
return result;
}
/// <summary>
/// 执行等待触发器的方法
/// </summary>
/// <param name="context"></param>
/// <returns>节点传回数据对象</returns>
/// <exception cref="RuningException"></exception>
public virtual async Task<object?> ExecuteAsync(IDynamicContext context)
{
MethodDetails md = MethodDetails;
object? result = null;
IFlipflopContext flipflopContext = null;
try
{
// 调用委托并获取结果
if (md.ExplicitDatas.Length == 0)
{
flipflopContext = await ((Func<object, Task<IFlipflopContext>>)md.MethodDelegate).Invoke(MethodDetails.ActingInstance);
}
else
{
object?[]? parameters = GetParameters(context, MethodDetails);
flipflopContext = await ((Func<object, object[], Task<IFlipflopContext>>)md.MethodDelegate).Invoke(MethodDetails.ActingInstance, parameters);
}
if (flipflopContext == null)
{
throw new FlipflopException("没有返回上下文");
}
NextOrientation = flipflopContext.State.ToContentType();
result = flipflopContext.Data;
}
catch (Exception ex)
{
NextOrientation = ConnectionType.IsError;
RuningException = ex;
}
return result;
}
/// <summary>
/// 获取对应的参数数组
/// </summary>
public object[]? GetParameters(IDynamicContext context, MethodDetails md)
{
// 用正确的大小初始化参数数组
var types = md.ExplicitDatas.Select(it => it.DataType).ToArray();
if (types.Length == 0)
{
return [md.ActingInstance];
}
object[]? parameters = new object[types.Length];
for (int i = 0; i < types.Length; i++)
{
var mdEd = md.ExplicitDatas[i];
Type type = mdEd.DataType;
var f1 = PreviousNode?.FlowData?.GetType();
var f2 = mdEd.DataType;
if (type == typeof(IDynamicContext))
{
parameters[i] = context;
}
else if (type == typeof(MethodDetails))
{
parameters[i] = md;
}
else if (type == typeof(NodeModelBase))
{
parameters[i] = this;
}
else if (mdEd.IsExplicitData) // 显式参数
{
// 判断是否使用表达式解析
if (mdEd.DataValue[0] == '@')
{
var expResult = SerinExpressionEvaluator.Evaluate(mdEd.DataValue, PreviousNode?.FlowData, out bool isChange);
if (mdEd.DataType.IsEnum)
{
var enumValue = Enum.Parse(mdEd.DataType, mdEd.DataValue);
parameters[i] = enumValue;
}
else if (mdEd.ExplicitType == typeof(string))
{
parameters[i] = Convert.ChangeType(expResult, typeof(string));
}
else if (mdEd.ExplicitType == typeof(bool))
{
parameters[i] = Convert.ChangeType(expResult, typeof(bool));
}
else if (mdEd.ExplicitType == typeof(int))
{
parameters[i] = Convert.ChangeType(expResult, typeof(int));
}
else if (mdEd.ExplicitType == typeof(double))
{
parameters[i] = Convert.ChangeType(expResult, typeof(double));
}
else
{
parameters[i] = expResult;
//parameters[i] = ConvertValue(mdEd.DataValue, mdEd.ExplicitType);
}
}
else
{
if (mdEd.DataType.IsEnum)
{
var enumValue = Enum.Parse(mdEd.DataType, mdEd.DataValue);
parameters[i] = enumValue;
}
else if (mdEd.ExplicitType == typeof(string))
{
parameters[i] = mdEd.DataValue;
}
else if (mdEd.ExplicitType == typeof(bool))
{
parameters[i] = bool.Parse(mdEd.DataValue);
}
else if (mdEd.ExplicitType == typeof(int))
{
parameters[i] = int.Parse(mdEd.DataValue);
}
else if (mdEd.ExplicitType == typeof(double))
{
parameters[i] = double.Parse(mdEd.DataValue);
}
else
{
parameters[i] = "";
//parameters[i] = ConvertValue(mdEd.DataValue, mdEd.ExplicitType);
}
}
}
else if (f1 != null && f2 != null)
{
if (f2.IsAssignableFrom(f1) || f2.FullName.Equals(f1.FullName))
{
parameters[i] = PreviousNode?.FlowData;
}
}
else
{
var tmpParameter = PreviousNode?.FlowData?.ToString();
if (mdEd.DataType.IsEnum)
{
var enumValue = Enum.Parse(mdEd.DataType, tmpParameter);
parameters[i] = enumValue;
}
else if (mdEd.DataType == typeof(string))
{
parameters[i] = tmpParameter;
}
else if (mdEd.DataType == typeof(bool))
{
parameters[i] = bool.Parse(tmpParameter);
}
else if (mdEd.DataType == typeof(int))
{
parameters[i] = int.Parse(tmpParameter);
}
else if (mdEd.DataType == typeof(double))
{
parameters[i] = double.Parse(tmpParameter);
}
else
{
if (tmpParameter != null && mdEd.DataType != null)
{
parameters[i] = ConvertValue(tmpParameter, mdEd.DataType);
}
}
}
}
return parameters;
}
/// <summary>
/// json文本反序列化为对象
/// </summary>
/// <param name="value"></param>
/// <param name="targetType"></param>
/// <returns></returns>
private dynamic? ConvertValue(string value, Type targetType)
{
try
{
if (!string.IsNullOrEmpty(value))
{
return JsonConvert.DeserializeObject(value, targetType);
}
else
{
return null;
}
}
catch (JsonReaderException ex)
{
Console.WriteLine(ex);
return value;
}
catch (JsonSerializationException ex)
{
// 如果无法转为对应的JSON对象
int startIndex = ex.Message.IndexOf("to type '") + "to type '".Length; // 查找类型信息开始的索引
int endIndex = ex.Message.IndexOf('\''); // 查找类型信息结束的索引
var typeInfo = ex.Message[startIndex..endIndex]; // 提取出错类型信息,该怎么传出去?
Console.WriteLine("无法转为对应的JSON对象:" + typeInfo);
return null;
}
catch // (Exception ex)
{
return value;
}
}
#region ExecuteAsync调用方法
//public virtual async Task<object?> ExecuteAsync(DynamicContext context)
//{
// MethodDetails md = MethodDetails;
// object? result = null;
// if (DelegateCache.GlobalDicDelegates.TryGetValue(md.MethodName, out Delegate del))
// {
// if (md.ExplicitDatas.Length == 0)
// {
// if (md.ReturnType == typeof(void))
// {
// ((Action<object>)del).Invoke(md.ActingInstance);
// }
// else if (md.ReturnType == typeof(Task<FlipflopContext>))
// {
// // 调用委托并获取结果
// FlipflopContext flipflopContext = await ((Func<object, Task<FlipflopContext>>)del).Invoke(MethodDetails.ActingInstance);
// if (flipflopContext != null)
// {
// if (flipflopContext.State == FfState.Cancel)
// {
// throw new Exception("this async task is cancel.");
// }
// else
// {
// if (flipflopContext.State == FfState.Succeed)
// {
// CurrentState = true;
// result = flipflopContext.Data;
// }
// else
// {
// CurrentState = false;
// }
// }
// }
// }
// else
// {
// result = ((Func<object, object>)del).Invoke(md.ActingInstance);
// }
// }
// else
// {
// object?[]? parameters = GetParameters(context, MethodDetails);
// if (md.ReturnType == typeof(void))
// {
// ((Action<object, object[]>)del).Invoke(md.ActingInstance, parameters);
// }
// else if (md.ReturnType == typeof(Task<FlipflopContext>))
// {
// // 调用委托并获取结果
// FlipflopContext flipflopContext = await ((Func<object, object[], Task<FlipflopContext>>)del).Invoke(MethodDetails.ActingInstance, parameters);
// if (flipflopContext != null)
// {
// if (flipflopContext.State == FfState.Cancel)
// {
// throw new Exception("取消此异步");
// }
// else
// {
// CurrentState = flipflopContext.State == FfState.Succeed;
// result = flipflopContext.Data;
// }
// }
// }
// else
// {
// result = ((Func<object, object[], object>)del).Invoke(md.ActingInstance, parameters);
// }
// }
// context.SetFlowData(result);
// }
// return result;
//}
#endregion
}
}