mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-16 06:26:35 +08:00
修复了全局节点连接异常异常。
This commit is contained in:
353
NodeFlow/Model/Infos/FlowApiMethodInfo.cs
Normal file
353
NodeFlow/Model/Infos/FlowApiMethodInfo.cs
Normal file
@@ -0,0 +1,353 @@
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
using Serein.NodeFlow.Model;
|
||||
using Serein.NodeFlow.Model.Nodes;
|
||||
using Serein.NodeFlow.Services;
|
||||
using System.Text;
|
||||
|
||||
namespace Serein.NodeFlow.Model.Infos
|
||||
{
|
||||
/// <summary>
|
||||
/// 指示流程接口方法需要生成什么代码
|
||||
/// </summary>
|
||||
internal class FlowApiMethodInfo
|
||||
{
|
||||
|
||||
public FlowApiMethodInfo(SingleFlowCallNode singleFlowCallNode)
|
||||
{
|
||||
NodeModel = singleFlowCallNode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对应的流程节点
|
||||
/// </summary>
|
||||
public SingleFlowCallNode NodeModel { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 生成的接口名称
|
||||
/// </summary>
|
||||
public string ApiMethodName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 返回类型
|
||||
/// </summary>
|
||||
public Type ReturnType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 参数实体信息
|
||||
/// </summary>
|
||||
public List<ParamInfo> ParamInfos { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 参数实体类型名称
|
||||
/// </summary>
|
||||
public string ParamTypeName => $"FlowApiInvoke_{ApiMethodName}";
|
||||
|
||||
public class ParamInfo
|
||||
{
|
||||
public ParamInfo(Type type, string paramName)
|
||||
{
|
||||
Type = type;
|
||||
ParamName = paramName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public Type Type { get; set; }
|
||||
/// <summary>
|
||||
/// 参数名称
|
||||
/// </summary>
|
||||
public string ParamName { get; set; }
|
||||
/// <summary>
|
||||
/// 注释备注
|
||||
/// </summary>
|
||||
public string Comments { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public enum ParamType
|
||||
{
|
||||
Defute, // 仅使用方法参数
|
||||
HasToken, // 包含取消令牌和方法参数
|
||||
HasContextAndToken, // 包含上下文、取消令牌和方法参数
|
||||
}
|
||||
|
||||
|
||||
public bool IsVoid => ReturnType == typeof(void);
|
||||
public string ObjPoolName => $"_objPool{ParamTypeName.ToPascalCase()}";
|
||||
/// <summary>
|
||||
/// 生成所需的参数类的签名代码
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string ToParamterClassSignature()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
|
||||
//sb.AppendCode(2, $"private static readonly global::Microsoft.Extensions.ObjectPool.DefaultObjectPool<{ParamTypeName}> {ObjPoolName} = ");
|
||||
//sb.AppendCode(2, $" new global::Microsoft.Extensions.ObjectPool.DefaultObjectPool<{ParamTypeName}>(");
|
||||
//sb.AppendCode(2, $" new global::Microsoft.Extensions.ObjectPool.DefaultPooledObjectPolicy<{ParamTypeName}>()); ");
|
||||
sb.AppendLine();
|
||||
var classXmlComments = $"流程接口[{ApiMethodName}]需要的参数类".ToXmlComments(2);
|
||||
sb.AppendCode(2, classXmlComments);
|
||||
sb.AppendCode(2, $"public class {ParamTypeName}");
|
||||
sb.AppendCode(2, $"{{");
|
||||
for (int index = 0; index < ParamInfos.Count; index++)
|
||||
{
|
||||
ParamInfo? info = ParamInfos[index];
|
||||
var argXmlComments = $"[{index}]流程接口参数{(string.IsNullOrWhiteSpace(info.Comments) ? string.Empty : $",{info.Comments}。")}".ToXmlComments(2);
|
||||
sb.AppendCode(3, argXmlComments);
|
||||
sb.AppendCode(3, $"public global::{info.Type.FullName} {info.ParamName.ToPascalCase()} {{ get; set; }}");
|
||||
}
|
||||
sb.AppendCode(2, $"}}");
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ToObjPoolSignature()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendCode(2, $"private static readonly global::Microsoft.Extensions.ObjectPool.DefaultObjectPool<{ParamTypeName}> {ObjPoolName} = ");
|
||||
sb.AppendCode(4, $"new global::Microsoft.Extensions.ObjectPool.DefaultObjectPool<{ParamTypeName}>(");
|
||||
sb.AppendCode(5, $"new global::Microsoft.Extensions.ObjectPool.DefaultPooledObjectPolicy<{ParamTypeName}>()); ");
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成接口的签名方法
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public string ToInterfaceMethodSignature(ParamType type)
|
||||
{
|
||||
var taskTypeFullName = $"global::System.Threading.Tasks.Task";
|
||||
var contextFullName = $"global::{typeof(IFlowContext).FullName}";
|
||||
var tokenFullName = $"global::{typeof(CancellationToken).FullName}";
|
||||
var returnContext = IsVoid ? taskTypeFullName : $"{taskTypeFullName}<{ReturnType.FullName}>";
|
||||
if (type == ParamType.Defute)
|
||||
{
|
||||
var paramSignature = string.Join(", ", ParamInfos.Select(p => $"global::{p.Type.FullName} {p.ParamName}"));
|
||||
return $"{returnContext} {ApiMethodName}({paramSignature});";
|
||||
}
|
||||
else if (type == ParamType.HasToken)
|
||||
{
|
||||
var paramSignature = string.Join(", ", ParamInfos.Select(p => $"global::{p.Type.FullName} {p.ParamName}"));
|
||||
return $"{returnContext} {ApiMethodName}({tokenFullName} token, {paramSignature});";
|
||||
}
|
||||
else if (type == ParamType.HasContextAndToken)
|
||||
{
|
||||
var paramSignature = string.Join(", ", ParamInfos.Select(p => $"global::{p.Type.FullName} {p.ParamName}"));
|
||||
return $"{returnContext} {ApiMethodName}({contextFullName} flowContext, {tokenFullName} token, {paramSignature});";
|
||||
}
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成实现方法的签名代码
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public string ToImpleMethodSignature(ParamType type)
|
||||
{
|
||||
var taskTypeFullName = $"global::System.Threading.Tasks.Task";
|
||||
var contextApiFullName = $"global::{typeof(IFlowContext).FullName}";
|
||||
var contextImpleFullName = $"global::{typeof(FlowContext).FullName}";
|
||||
var tokenSourceFullName = $"global::{typeof(CancellationTokenSource).FullName}";
|
||||
var tokenFullName = $"global::{typeof(CancellationToken).FullName}";
|
||||
var flowContextPoolName = $"global::{typeof(LightweightFlowControl).FullName}";
|
||||
string flowEnvironment = nameof(flowEnvironment);
|
||||
string flowContext = nameof(flowContext);
|
||||
string token = nameof(token);
|
||||
|
||||
var returnTypeContext = IsVoid ? taskTypeFullName : $"{taskTypeFullName}<{ReturnType.FullName}>";
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (IsVoid)
|
||||
{
|
||||
if (type == ParamType.Defute)
|
||||
{
|
||||
var paramSignature = string.Join(", ", ParamInfos.Select(p => $"global::{{{p.Type.FullName} {p.ParamName}"));
|
||||
var invokeParamSignature = string.Join(", ", ParamInfos.Select(p => p.ParamName));
|
||||
sb.AppendCode(2, $"public async {returnTypeContext} {ApiMethodName}({paramSignature})");
|
||||
sb.AppendCode(2, $"{{");
|
||||
sb.AppendCode(3, $"{contextApiFullName} {flowContext} = {flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Allocate)}(); // 从对象池获取一个上下文");
|
||||
sb.AppendCode(3, $"{tokenSourceFullName} cts = new {tokenSourceFullName}(); // 创建取消令牌");
|
||||
sb.AppendCode(3, $"try");
|
||||
sb.AppendCode(3, $"{{");
|
||||
sb.AppendCode(4, $"await {ApiMethodName}({flowContext}, cts.Token, {invokeParamSignature}); // 调用目标方法");
|
||||
sb.AppendCode(3, $"}}");
|
||||
sb.AppendCode(3, $"catch (Exception)");
|
||||
sb.AppendCode(3, $"{{");
|
||||
sb.AppendCode(4, $"throw;");
|
||||
sb.AppendCode(3, $"}}");
|
||||
sb.AppendCode(3, $"finally");
|
||||
sb.AppendCode(3, $"{{");
|
||||
sb.AppendCode(4, $"{flowContext}.{nameof(IFlowContext.Reset)}(); ");
|
||||
sb.AppendCode(4, $"cts.{nameof(CancellationTokenSource.Dispose)}(); ");
|
||||
sb.AppendCode(4, $"{flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Free)}({flowContext}); // 释放上下文");
|
||||
sb.AppendCode(3, $"}}");
|
||||
sb.AppendCode(2, $"}}");
|
||||
return sb.ToString();
|
||||
}
|
||||
else if (type == ParamType.HasToken)
|
||||
{
|
||||
var paramSignature = string.Join(", ", ParamInfos.Select(p => $"global::{{{p.Type.FullName} {p.ParamName}"));
|
||||
var invokeParamSignature = string.Join(", ", ParamInfos.Select(p => p.ParamName));
|
||||
sb.AppendCode(2, $"public async {returnTypeContext} {ApiMethodName}({tokenFullName} {token}, {paramSignature})");
|
||||
sb.AppendCode(2, $"{{");
|
||||
sb.AppendCode(3, $"{contextApiFullName} {flowContext} = {flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Allocate)}(); // 从对象池获取一个上下文");
|
||||
sb.AppendCode(3, $"try");
|
||||
sb.AppendCode(3, $"{{");
|
||||
sb.AppendCode(4, $"await {ApiMethodName}({flowContext}, {token}, {invokeParamSignature}); // 调用目标方法");
|
||||
sb.AppendCode(4, $"{flowContext}.{nameof(IFlowContext.Reset)}(); ");
|
||||
sb.AppendCode(3, $"}}");
|
||||
sb.AppendCode(3, $"catch (Exception)");
|
||||
sb.AppendCode(3, $"{{");
|
||||
sb.AppendCode(4, $"throw;");
|
||||
sb.AppendCode(3, $"}}");
|
||||
sb.AppendCode(3, $"finally");
|
||||
sb.AppendCode(3, $"{{");
|
||||
sb.AppendCode(4, $"{flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Free)}({flowContext}); // 释放上下文");
|
||||
sb.AppendCode(3, $"}}");
|
||||
sb.AppendCode(2, $"}}");
|
||||
return sb.ToString();
|
||||
}
|
||||
else if (type == ParamType.HasContextAndToken)
|
||||
{
|
||||
var paramSignature = string.Join(", ", ParamInfos.Select(p => $"global::{{{p.Type.FullName} {p.ParamName}"));
|
||||
var invokeParamSignature = string.Join(", ", ParamInfos.Select(p => p.ParamName));
|
||||
|
||||
|
||||
sb.AppendCode(2, $"public async {returnTypeContext} {ApiMethodName}({contextApiFullName} {flowContext}, {tokenFullName} token, {paramSignature})");
|
||||
sb.AppendCode(2, $"{{");
|
||||
sb.AppendCode(3, $"token.ThrowIfCancellationRequested(); // 检查任务是否取消");
|
||||
sb.AppendCode(3, $"try");
|
||||
sb.AppendCode(3, $"{{");
|
||||
sb.AppendCode(3, $"global::{ParamTypeName} data = {ObjPoolName}.Get(); // 从对象池获取一个对象");
|
||||
for (int index = 0; index < ParamInfos.Count; index++)
|
||||
{
|
||||
ParamInfo? info = ParamInfos[index];
|
||||
sb.AppendCode(4, $"data.{info.ParamName.ToPascalCase()} = {info.ParamName}; // [{index}] {info.Comments}");
|
||||
}
|
||||
sb.AppendCode(3, $"{flowContext}.{nameof(IFlowContext.AddOrUpdate)}(\"{ApiMethodName}\", data);");
|
||||
sb.AppendCode(3, $"{flowContext}.{nameof(IFlowContext.SetPreviousNode)}(\"{NodeModel.TargetNode.Guid}\", \"{ApiMethodName}\");");
|
||||
sb.AppendCode(3, $"global::{typeof(CallNode).FullName} node = Get(\"{NodeModel.Guid}\");");
|
||||
sb.AppendCode(3, $"await node.{nameof(CallNode.StartFlowAsync)}({flowContext}, {token}); // 调用目标方法");
|
||||
sb.AppendCode(3, $"}}");
|
||||
sb.AppendCode(3, $"catch (Exception)");
|
||||
sb.AppendCode(3, $"{{");
|
||||
sb.AppendCode(4, $"throw;");
|
||||
sb.AppendCode(3, $"}}");
|
||||
sb.AppendCode(3, $"finally");
|
||||
sb.AppendCode(3, $"{{");
|
||||
sb.AppendCode(4, $"{flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Free)}({flowContext}); // 释放上下文");
|
||||
sb.AppendCode(3, $"}}");
|
||||
sb.AppendCode(2, $"}}");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string flowResult = nameof(flowResult);
|
||||
if (type == ParamType.Defute)
|
||||
{
|
||||
//sb.AppendCode(3, $"{contextApiFullName} {flowContext} = new {contextImpleFullName}({flowEnvironment}); // 创建上下文");
|
||||
|
||||
var paramSignature = string.Join(", ", ParamInfos.Select(p => $"global::{p.Type.FullName} {p.ParamName}"));
|
||||
var invokeParamSignature = string.Join(", ", ParamInfos.Select(p => p.ParamName));
|
||||
sb.AppendCode(2, $"public async {returnTypeContext} {ApiMethodName}({paramSignature})");
|
||||
sb.AppendCode(2, $"{{");
|
||||
sb.AppendCode(3, $"{contextApiFullName} {flowContext} = {flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Allocate)}(); // 从对象池获取一个上下文");
|
||||
sb.AppendCode(3, $"{tokenSourceFullName} cts = new {tokenSourceFullName}(); // 创建取消令牌");
|
||||
sb.AppendCode(3, $"try");
|
||||
sb.AppendCode(3, $"{{");
|
||||
sb.AppendCode(4, $"{ReturnType.FullName} {flowResult} = await {ApiMethodName}({flowContext}, cts.{nameof(CancellationTokenSource.Token)}, {invokeParamSignature}); // 调用目标方法");
|
||||
sb.AppendCode(4, $"return {flowResult};");
|
||||
sb.AppendCode(3, $"}}");
|
||||
sb.AppendCode(3, $"catch (Exception)");
|
||||
sb.AppendCode(3, $"{{");
|
||||
sb.AppendCode(4, $"throw;");
|
||||
sb.AppendCode(3, $"}}");
|
||||
sb.AppendCode(3, $"finally");
|
||||
sb.AppendCode(3, $"{{");
|
||||
sb.AppendCode(4, $"{flowContext}.{nameof(IFlowContext.Reset)}(); ");
|
||||
sb.AppendCode(4, $"cts.{nameof(CancellationTokenSource.Dispose)}(); ");
|
||||
sb.AppendCode(4, $"{flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Free)}({flowContext}); // 释放上下文");
|
||||
sb.AppendCode(3, $"}}");
|
||||
sb.AppendCode(2, $"}}");
|
||||
return sb.ToString();
|
||||
}
|
||||
else if (type == ParamType.HasToken)
|
||||
{
|
||||
var paramSignature = string.Join(", ", ParamInfos.Select(p => $"global::{p.Type.FullName} {p.ParamName}"));
|
||||
var invokeParamSignature = string.Join(", ", ParamInfos.Select(p => p.ParamName));
|
||||
sb.AppendCode(2, $"public async {returnTypeContext} {ApiMethodName}({tokenFullName} {token}, {paramSignature})");
|
||||
sb.AppendCode(2, $"{{");
|
||||
sb.AppendCode(3, $"{contextApiFullName} {flowContext} = {flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Allocate)}(); // 从对象池获取一个上下文");
|
||||
sb.AppendCode(3, $"try");
|
||||
sb.AppendCode(3, $"{{");
|
||||
sb.AppendCode(4, $"{ReturnType.FullName} {flowResult} = await {ApiMethodName}({flowContext}, {token}, {invokeParamSignature}); // 调用目标方法");
|
||||
sb.AppendCode(4, $"return {flowResult};");
|
||||
sb.AppendCode(3, $"}}");
|
||||
sb.AppendCode(3, $"catch (Exception)");
|
||||
sb.AppendCode(3, $"{{");
|
||||
sb.AppendCode(4, $"throw;");
|
||||
sb.AppendCode(3, $"}}");
|
||||
sb.AppendCode(3, $"finally");
|
||||
sb.AppendCode(3, $"{{");
|
||||
sb.AppendCode(4, $"{flowContext}.{nameof(IFlowContext.Reset)}(); ");
|
||||
sb.AppendCode(4, $"{flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Free)}({flowContext}); // 释放上下文");
|
||||
sb.AppendCode(3, $"}}");
|
||||
sb.AppendCode(2, $"}}");
|
||||
return sb.ToString();
|
||||
}
|
||||
else if (type == ParamType.HasContextAndToken)
|
||||
{
|
||||
var paramSignature = string.Join(", ", ParamInfos.Select(p => $"global::{p.Type.FullName} {p.ParamName}"));
|
||||
var invokeParamSignature = string.Join(", ", ParamInfos.Select(p => p.ParamName));
|
||||
sb.AppendCode(2, $"public async {returnTypeContext} {ApiMethodName}({contextApiFullName} {flowContext}, {tokenFullName} token, {paramSignature})");
|
||||
sb.AppendCode(2, $"{{");
|
||||
sb.AppendCode(3, $"token.ThrowIfCancellationRequested(); // 检查任务是否取消");
|
||||
sb.AppendCode(3, $"global::{ParamTypeName} data = {ObjPoolName}.Get(); // 从对象池获取一个对象");
|
||||
for (int index = 0; index < ParamInfos.Count; index++)
|
||||
{
|
||||
ParamInfo? info = ParamInfos[index];
|
||||
sb.AppendCode(4, $"data.{info.ParamName.ToPascalCase()} = {info.ParamName}; // [{index}] {info.Comments}"); // 进行赋值
|
||||
}
|
||||
sb.AppendCode(3, $"{flowContext}.{nameof(IFlowContext.AddOrUpdate)}(\"{ApiMethodName}\", data);");
|
||||
sb.AppendCode(3, $"{flowContext}.{nameof(IFlowContext.SetPreviousNode)}(\"{NodeModel.Guid}\", \"{ApiMethodName}\");");
|
||||
sb.AppendCode(3, $"global::{typeof(CallNode).FullName} node = Get(\"{NodeModel.Guid}\");");
|
||||
sb.AppendCode(3, $"global::{typeof(FlowResult).FullName} {flowResult} = await node.{nameof(CallNode.StartFlowAsync)}({flowContext}, {token}); // 调用目标方法");
|
||||
if(ReturnType == typeof(object))
|
||||
{
|
||||
sb.AppendCode(3, $"if ({flowResult}.{nameof(FlowResult.Value)} is null)");
|
||||
sb.AppendCode(3, $"{{");
|
||||
sb.AppendCode(4, $"return null;");
|
||||
sb.AppendCode(3, $"}}");
|
||||
sb.AppendCode(3, $"else", isWrapping :false);
|
||||
}
|
||||
sb.AppendCode(3, $"if ({flowResult}.{nameof(FlowResult.Value)} is global::{ReturnType.FullName} result)");
|
||||
sb.AppendCode(3, $"{{");
|
||||
sb.AppendCode(4, $"return result;");
|
||||
sb.AppendCode(3, $"}}");
|
||||
sb.AppendCode(3, $"else");
|
||||
sb.AppendCode(3, $"{{");
|
||||
sb.AppendCode(4, $"throw new ArgumentNullException($\"类型转换失败,{{(flowResult.Value is null ? \"返回数据为 null\" : $\"返回数据与需求类型不匹配,当前返回类型为[{{flowResult.Value.GetType().FullName}}。\")}}\");");
|
||||
sb.AppendCode(3, $"}}");
|
||||
//sb.AppendCode(3, $"return {flowResult};");
|
||||
sb.AppendCode(2, $"}}");
|
||||
return sb.ToString();
|
||||
// throw new ArgumentNullException($"类型转换失败,{(flowResult.Value is null ? "返回数据为 null" : $"返回数据与需求类型不匹配,当前返回类型为[{flowResult.Value.GetType().FullName}。")}");
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@ using System.ComponentModel;
|
||||
using System.Net.Mime;
|
||||
using System.Threading;
|
||||
|
||||
namespace Serein.NodeFlow.Model
|
||||
namespace Serein.NodeFlow.Model.Nodes
|
||||
{
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
|
||||
namespace Serein.NodeFlow.Model
|
||||
namespace Serein.NodeFlow.Model.Nodes
|
||||
{
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using Serein.Library;
|
||||
using System.Security.AccessControl;
|
||||
|
||||
namespace Serein.NodeFlow.Model
|
||||
namespace Serein.NodeFlow.Model.Nodes
|
||||
{
|
||||
/// <summary>
|
||||
/// 单动作节点(用于动作控件)
|
||||
|
||||
@@ -4,7 +4,7 @@ using Serein.Script;
|
||||
using System.Dynamic;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace Serein.NodeFlow.Model
|
||||
namespace Serein.NodeFlow.Model.Nodes
|
||||
{
|
||||
/// <summary>
|
||||
/// 条件节点(用于条件控件)
|
||||
@@ -177,7 +177,7 @@ namespace Serein.NodeFlow.Model
|
||||
context.ExceptionOfRuning = ex;
|
||||
}
|
||||
|
||||
SereinEnv.WriteLine(InfoType.INFO, $"{result} {Expression} -> " + context.NextOrientation);
|
||||
SereinEnv.WriteLine(InfoType.INFO, $"{Expression} -> " + context.NextOrientation);
|
||||
//return result;
|
||||
return new FlowResult(this.Guid, context, judgmentResult);
|
||||
}
|
||||
@@ -236,19 +236,18 @@ namespace Serein.NodeFlow.Model
|
||||
var dataName = nameof(data);
|
||||
if (!expression.Equals(conditionExpression))
|
||||
{
|
||||
conditionExpression = expression;
|
||||
conditionExpression = expression.Trim();
|
||||
conditionScript = new SereinScript();
|
||||
var dataType = data is null ? typeof(object) : data.GetType();
|
||||
conditionExpression = expression.Trim();
|
||||
if (expression[0] == '.')
|
||||
{
|
||||
// 对象取值
|
||||
conditionExpression = $"return {dataName}{expression};";
|
||||
conditionExpression = $"return {dataName}{conditionExpression};";
|
||||
}
|
||||
else
|
||||
{
|
||||
// 直接表达式
|
||||
conditionExpression = $"return {dataName}.{expression};";
|
||||
conditionExpression = $"return {dataName}.{conditionExpression};";
|
||||
}
|
||||
var resultType = conditionScript.ParserScript(conditionExpression, new Dictionary<string, Type>
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ using Serein.Library.Api;
|
||||
using Serein.Script;
|
||||
using System.Dynamic;
|
||||
|
||||
namespace Serein.NodeFlow.Model
|
||||
namespace Serein.NodeFlow.Model.Nodes
|
||||
{
|
||||
/// <summary>
|
||||
/// Expression Operation - 表达式操作
|
||||
|
||||
@@ -3,13 +3,14 @@ using Serein.Library;
|
||||
using Serein.Library.Utils;
|
||||
using System;
|
||||
|
||||
namespace Serein.NodeFlow.Model
|
||||
namespace Serein.NodeFlow.Model.Nodes
|
||||
{
|
||||
/// <summary>
|
||||
/// 触发器节点
|
||||
/// </summary>
|
||||
public class SingleFlipflopNode : NodeModelBase
|
||||
{
|
||||
|
||||
public SingleFlipflopNode(IFlowEnvironment environment) : base(environment)
|
||||
{
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ using Serein.NodeFlow.Services;
|
||||
using System.Dynamic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Serein.NodeFlow.Model
|
||||
namespace Serein.NodeFlow.Model.Nodes
|
||||
{
|
||||
|
||||
[NodeProperty(ValuePath = NodeValuePath.Node)]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using Serein.Library.Api;
|
||||
using System.Dynamic;
|
||||
|
||||
namespace Serein.NodeFlow.Model
|
||||
namespace Serein.NodeFlow.Model.Nodes
|
||||
{
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Serein.NodeFlow.Model
|
||||
public partial class SingleGlobalDataNode : NodeModelBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 表达式
|
||||
/// 全局数据的Key名称
|
||||
/// </summary>
|
||||
[PropertyInfo(IsNotification = true)]
|
||||
private string _keyName;
|
||||
@@ -43,7 +43,7 @@ namespace Serein.NodeFlow.Model
|
||||
/// <summary>
|
||||
/// 数据来源的节点
|
||||
/// </summary>
|
||||
private IFlowNode? DataNode;
|
||||
public IFlowNode? DataNode { get; private set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// 有节点被放置
|
||||
@@ -52,12 +52,27 @@ namespace Serein.NodeFlow.Model
|
||||
/// <returns></returns>
|
||||
public bool PlaceNode(IFlowNode nodeModel)
|
||||
{
|
||||
if(nodeModel.ControlType is not (NodeControlType.Action or NodeControlType.Script))
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.INFO, "放置在全局数据必须是有返回值的[Action]节点,[Script]节点。");
|
||||
return false;
|
||||
}
|
||||
if (nodeModel.MethodDetails?.ReturnType is null
|
||||
|| nodeModel.MethodDetails.ReturnType == typeof(void))
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.INFO, "放置在全局数据必须是有返回值的[Action]节点,[Script]节点。");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(DataNode is null)
|
||||
{
|
||||
// 放置节点
|
||||
nodeModel.ContainerNode = this;
|
||||
ChildrenNode.Add(nodeModel);
|
||||
DataNode = nodeModel;
|
||||
|
||||
MethodDetails.IsAsync = nodeModel.MethodDetails.IsAsync;
|
||||
MethodDetails.ReturnType = nodeModel.MethodDetails.ReturnType;
|
||||
return true;
|
||||
}
|
||||
else if (DataNode.Guid != nodeModel.Guid)
|
||||
|
||||
@@ -8,7 +8,7 @@ using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.NodeFlow.Model
|
||||
namespace Serein.NodeFlow.Model.Nodes
|
||||
{
|
||||
|
||||
[NodeProperty(ValuePath = NodeValuePath.Node)]
|
||||
|
||||
@@ -13,7 +13,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Serein.NodeFlow.Model
|
||||
namespace Serein.NodeFlow.Model.Nodes
|
||||
{
|
||||
|
||||
[NodeProperty(ValuePath = NodeValuePath.Node)]
|
||||
@@ -263,20 +263,6 @@ namespace Serein.NodeFlow.Model
|
||||
{
|
||||
if (token.IsCancellationRequested) return new FlowResult(this.Guid, context);
|
||||
var @params = await flowCallNode.GetParametersAsync(context, token);
|
||||
//if (token.IsCancellationRequested) return new FlowResult(this.Guid, context);
|
||||
//context.AddOrUpdate($"{context.Guid}_{this.Guid}_Params", @params[0]); // 后面再改
|
||||
|
||||
/* if (IsScriptChanged)
|
||||
{
|
||||
lock (@params) {
|
||||
if (IsScriptChanged)
|
||||
{
|
||||
ReloadScript();// 执行时检查是否需要重新解析
|
||||
IsScriptChanged = false;
|
||||
context.Env.WriteLine(InfoType.INFO, $"[{Guid}]脚本解析完成");
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
IScriptInvokeContext scriptContext = new ScriptInvokeContext(context);
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.NodeFlow.Model
|
||||
namespace Serein.NodeFlow.Model.Nodes
|
||||
{
|
||||
public class SingleUINode : NodeModelBase
|
||||
{
|
||||
|
||||
@@ -172,40 +172,58 @@ namespace Serein.NodeFlow.Model.Operation
|
||||
#region 类型检查
|
||||
bool checkTypeState = true;
|
||||
List<ParameterDetails> toPds = new List<ParameterDetails>();
|
||||
if(ToNode.MethodDetails.ParameterDetailss is null)
|
||||
|
||||
if (FromNode.ContainerNode is not null)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.WARN, "目标节点没有入参参数,无法进行连接");
|
||||
SereinEnv.WriteLine(InfoType.WARN, "连接失败,起始节点处于容器中");
|
||||
return false;
|
||||
}
|
||||
if (ToNode.MethodDetails.ParameterDetailss.Length > 0)
|
||||
|
||||
if (ToNode.ContainerNode is not null)
|
||||
{
|
||||
var fromNoeReturnType = fromNode.MethodDetails.ReturnType;
|
||||
if (fromNoeReturnType != null
|
||||
&& fromNoeReturnType != typeof(object)
|
||||
&& fromNoeReturnType != typeof(void)
|
||||
&& fromNoeReturnType != typeof(Unit))
|
||||
SereinEnv.WriteLine(InfoType.WARN, "连接失败,目标节点处于容器中");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ToNode.ControlType != NodeControlType.GlobalData)
|
||||
{
|
||||
|
||||
if (ToNode.MethodDetails.ParameterDetailss is null)
|
||||
{
|
||||
var toNodePds = toNode.MethodDetails.ParameterDetailss;
|
||||
foreach (ParameterDetails toNodePd in toNodePds)
|
||||
SereinEnv.WriteLine(InfoType.WARN, "连接失败,目标节点没有入参参数。");
|
||||
return false;
|
||||
}
|
||||
if (ToNode.MethodDetails.ParameterDetailss.Length > 0)
|
||||
{
|
||||
var fromNoeReturnType = fromNode.MethodDetails.ReturnType;
|
||||
if (fromNoeReturnType != null
|
||||
&& fromNoeReturnType != typeof(object)
|
||||
&& fromNoeReturnType != typeof(void)
|
||||
&& fromNoeReturnType != typeof(Unit))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(toNodePd.ArgDataSourceNodeGuid) // 入参没有设置数据来源节点
|
||||
&& toNodePd.DataType.IsAssignableFrom(fromNoeReturnType)) // 返回值与目标入参相同(或可转换为目标入参)
|
||||
var toNodePds = toNode.MethodDetails.ParameterDetailss;
|
||||
foreach (ParameterDetails toNodePd in toNodePds)
|
||||
{
|
||||
|
||||
toPds.Add(toNodePd);
|
||||
if (string.IsNullOrWhiteSpace(toNodePd.ArgDataSourceNodeGuid) // 入参没有设置数据来源节点
|
||||
&& toNodePd.DataType.IsAssignableFrom(fromNoeReturnType)) // 返回值与目标入参相同(或可转换为目标入参)
|
||||
{
|
||||
|
||||
toPds.Add(toNodePd);
|
||||
}
|
||||
}
|
||||
if (toPds.Count == 0)
|
||||
{
|
||||
var any = toNodePds.Any(pd => pd.ArgDataSourceNodeGuid == fromNode.Guid); // 判断目标节点是否已有该节点的连接
|
||||
checkTypeState = any;
|
||||
}
|
||||
else
|
||||
{
|
||||
checkTypeState = true; // 类型检查初步通过
|
||||
}
|
||||
}
|
||||
if (toPds.Count == 0)
|
||||
{
|
||||
var any = toNodePds.Any(pd => pd.ArgDataSourceNodeGuid == fromNode.Guid); // 判断目标节点是否已有该节点的连接
|
||||
checkTypeState = any;
|
||||
}
|
||||
else
|
||||
{
|
||||
checkTypeState = true; // 类型检查初步通过
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!checkTypeState) // 类型检查不通过
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.ERROR, "创建失败,目标节点没有合适的入参接收返回值");
|
||||
@@ -396,7 +414,11 @@ namespace Serein.NodeFlow.Model.Operation
|
||||
SereinEnv.WriteLine(InfoType.WARN, $"连接失败,节点参数入参不允许接收多个节点返回值。起始节点[{FromNode.Guid}],目标节点[{FromNode.Guid}]。");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FromNode.ContainerNode is not null)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.WARN, "连接失败,参数来源节点处于容器中");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 判断是否建立过连接关系
|
||||
if (FromNode.Guid == toNodeArgSourceGuid && toNodeArgSourceType == ConnectionArgSourceType)
|
||||
|
||||
Reference in New Issue
Block a user