流程接口节点新增了对脚本节点的支持

This commit is contained in:
fengjiayi
2025-05-30 15:42:59 +08:00
parent 9c4e5b2735
commit f0eb11c914
12 changed files with 234 additions and 150 deletions

View File

@@ -1,6 +1,7 @@
using Newtonsoft.Json.Linq;
using Serein.Library;
using Serein.Library.Api;
using Serein.Script;
using System;
using System.Collections.Generic;
using System.Dynamic;
@@ -88,10 +89,6 @@ namespace Serein.NodeFlow.Model
// 取消设置接口节点
targetNode.PropertyChanged -= TargetNode_PropertyChanged;
this.MethodDetails = new MethodDetails();
/*foreach (ConnectionInvokeType ctType in NodeStaticConfig.ConnectionTypes)
{
this.SuccessorNodes[ctType] = new List<NodeModelBase>();
}*/
}
else
{
@@ -99,20 +96,21 @@ namespace Serein.NodeFlow.Model
if(!this.IsShareParam
&& CacheMethodDetails is not null
&& targetNode.MethodDetails.AssemblyName.Equals(CacheMethodDetails.AssemblyName)
&& targetNode.MethodDetails.MethodName.Equals(CacheMethodDetails.MethodName))
&& targetNode.MethodDetails is not null
&& targetNode.MethodDetails.AssemblyName == CacheMethodDetails.AssemblyName
&& targetNode.MethodDetails.MethodName == CacheMethodDetails.MethodName)
{
this.MethodDetails = CacheMethodDetails;
}
else
{
CacheMethodDetails = targetNode.MethodDetails.CloneOfNode(this); // 从目标节点复制一份
targetNode.PropertyChanged += TargetNode_PropertyChanged;
this.MethodDetails = CacheMethodDetails;
/*foreach (ConnectionInvokeType ctType in NodeStaticConfig.ConnectionTypes)
if (targetNode.MethodDetails is not null)
{
this.SuccessorNodes[ctType] = targetNode.SuccessorNodes[ctType];
}*/
CacheMethodDetails = targetNode.MethodDetails.CloneOfNode(this); // 从目标节点复制一份
targetNode.PropertyChanged += TargetNode_PropertyChanged;
this.MethodDetails = CacheMethodDetails;
}
}
}
@@ -127,11 +125,20 @@ namespace Serein.NodeFlow.Model
}
if (value)
{
CacheMethodDetails = this.MethodDetails;
this.MethodDetails = targetNode.MethodDetails;
CacheMethodDetails = targetNode.MethodDetails.CloneOfNode(this);
this.MethodDetails = CacheMethodDetails;
}
else
{
if(targetNode.ControlType == NodeControlType.Script)
{
// 脚本节点入参需不可编辑入参数量、入参名称
foreach (var item in CacheMethodDetails.ParameterDetailss)
{
item.IsParams = false;
}
}
this.MethodDetails = CacheMethodDetails;
}
@@ -176,52 +183,6 @@ namespace Serein.NodeFlow.Model
}
/// <summary>
/// 需要调用其它流程图中的某个节点
/// </summary>
/// <param name="context"></param>
/// <param name="token"></param>
/// <returns></returns>
public override async Task<FlowResult> ExecutingAsync(IDynamicContext context, CancellationToken token)
{
if (!UploadTargetNode())
{
throw new ArgumentNullException();
}
if (IsShareParam)
{
this.MethodDetails = targetNode.MethodDetails;
}
this.SuccessorNodes = targetNode.SuccessorNodes;
var flowData = await base.ExecutingAsync(context, token);
if (IsShareParam)
{
// 设置运行时上一节点
// 此处代码与SereinFlow.Library.FlowNode.ParameterDetails
// ToMethodArgData()方法中判断流程接口节点分支逻辑耦合
// 不要轻易修改
context.AddOrUpdate(targetNode, flowData);
foreach (ConnectionInvokeType ctType in NodeStaticConfig.ConnectionTypes)
{
if (this.SuccessorNodes[ctType] == null) continue;
foreach (var node in this.SuccessorNodes[ctType])
{
if (node.DebugSetting.IsEnable)
{
context.SetPreviousNode(node, this);
}
}
}
}
return flowData;
}
/// <summary>
/// 保存全局变量的数据
/// </summary>
@@ -265,7 +226,61 @@ namespace Serein.NodeFlow.Model
CacheMethodDetails = null;
}
/// <summary>
/// 需要调用其它流程图中的某个节点
/// </summary>
/// <param name="context"></param>
/// <param name="token"></param>
/// <returns></returns>
public override async Task<FlowResult> ExecutingAsync(IDynamicContext context, CancellationToken token)
{
if (!UploadTargetNode())
{
throw new ArgumentNullException();
}
if (IsShareParam)
{
this.MethodDetails = targetNode.MethodDetails;
}
this.SuccessorNodes = targetNode.SuccessorNodes;
FlowResult flowData = await (targetNode.ControlType switch
{
NodeControlType.Script => ((SingleScriptNode)targetNode).ExecutingAsync(this, context, token),
_ => base.ExecutingAsync(context, token)
});
if (IsShareParam)
{
// 设置运行时上一节点
// 此处代码与SereinFlow.Library.FlowNode.ParameterDetails
// ToMethodArgData()方法中判断流程接口节点分支逻辑耦合
// 不要轻易修改
context.AddOrUpdate(targetNode, flowData);
foreach (ConnectionInvokeType ctType in NodeStaticConfig.ConnectionTypes)
{
if (this.SuccessorNodes[ctType] == null) continue;
foreach (var node in this.SuccessorNodes[ctType])
{
if (node.DebugSetting.IsEnable)
{
context.SetPreviousNode(node, this);
}
}
}
}
return flowData;
}
}
}

View File

@@ -33,17 +33,17 @@ namespace Serein.NodeFlow.Model
/// </summary>
public override bool IsBase => true;
private IScriptFlowApi ScriptFlowApi { get; }
private IScriptFlowApi ScriptFlowApi;
private ASTNode mainNode;
private SereinScriptInterpreter ScriptInterpreter;
private bool IsScriptChanged = false;
/// <summary>
/// 构建流程脚本节点
/// </summary>
/// <param name="environment"></param>
public SingleScriptNode(IFlowEnvironment environment):base(environment)
{
//ScriptFlowApi = environment.IOC.Get<ScriptFlowApi>();
ScriptFlowApi = new ScriptFlowApi(environment, this);
ScriptInterpreter = new SereinScriptInterpreter();
}
@@ -64,7 +64,19 @@ namespace Serein.NodeFlow.Model
}
}
/// <summary>
/// 代码改变后
/// </summary>
/// <param name="value"></param>
/// <exception cref="NotImplementedException"></exception>
partial void OnScriptChanged(string value)
{
IsScriptChanged = true;
}
/// <summary>
/// 节点创建时
/// </summary>
public override void OnCreating()
{
MethodInfo? method = this.GetType().GetMethod(nameof(GetFlowApi));
@@ -90,7 +102,7 @@ namespace Serein.NodeFlow.Model
InputType = ParameterValueInputType.Input,
Items = null,
IsParams = true,
Description = "脚本节点入参"
//Description = "脚本节点入参"
};
@@ -166,13 +178,35 @@ namespace Serein.NodeFlow.Model
/// <param name="context"></param>
/// <returns></returns>
public override async Task<FlowResult> ExecutingAsync(IDynamicContext context, CancellationToken token)
{
return await ExecutingAsync(this, context, token);
}
/// <summary>
/// 流程接口提供参数进行调用脚本节点
/// </summary>
/// <param name="flowCallNode"></param>
/// <param name="context"></param>
/// <param name="token"></param>
/// <returns></returns>
public async Task<FlowResult> ExecutingAsync(NodeModelBase flowCallNode, IDynamicContext context, CancellationToken token)
{
if (token.IsCancellationRequested) return new FlowResult(this, context);
var @params = await this.GetParametersAsync(context, token);
if(token.IsCancellationRequested) return new FlowResult(this, context);
var @params = await flowCallNode.GetParametersAsync(context, token);
if (token.IsCancellationRequested) return new FlowResult(this, context);
//context.AddOrUpdate($"{context.Guid}_{this.Guid}_Params", @params[0]); // 后面再改
ReloadScript();// 每次都重新解析
if (IsScriptChanged)
{
lock (@params) {
if (IsScriptChanged)
{
ReloadScript();// 每次都重新解析
IsScriptChanged = false;
}
}
}
IScriptInvokeContext scriptContext = new ScriptInvokeContext(context);
@@ -180,13 +214,12 @@ namespace Serein.NodeFlow.Model
{
for (int i = 0; i < agrDatas.Length; i++)
{
var argName = MethodDetails.ParameterDetailss[i].Name;
var argName = flowCallNode.MethodDetails.ParameterDetailss[i].Name;
var argData = agrDatas[i];
scriptContext.SetVarValue(argName, argData);
}
}
FlowRunCompleteHandler onFlowStop = (e) =>
{
scriptContext.OnExit();
@@ -200,10 +233,8 @@ namespace Serein.NodeFlow.Model
var result = await ScriptInterpreter.InterpretAsync(scriptContext, mainNode); // 从入口节点执行
envEvent.OnFlowRunComplete -= onFlowStop;
return new FlowResult(this, context, result);
//SereinEnv.WriteLine(InfoType.INFO, "FlowContext Guid : " + context.Guid);
}
#region
public IScriptFlowApi GetFlowApi()