优化了SereinEnv.WriteLine(Exception, InfoClass)输出,可以通过更改InfoClass控制是否输出异常堆栈信息。

优化了批量加载节点时,脚本节点类型分析异常的问题。
This commit is contained in:
fengjiayi
2025-07-17 22:46:40 +08:00
parent 550122208d
commit 88de5a21f5
13 changed files with 113 additions and 36 deletions

View File

@@ -248,7 +248,7 @@ namespace Serein.Library.Web
catch (Exception ex1)
{
SereinEnv.WriteLine(InfoType.ERROR, ex1.ToString());
SereinEnv.WriteLine(ex1);
}
}

View File

@@ -135,7 +135,7 @@ namespace Serein.Library.Web
}
catch (Exception ex)
{
SereinEnv.WriteLine(InfoType.ERROR, ex.ToString());
SereinEnv.WriteLine(ex);
}
}

View File

@@ -132,7 +132,16 @@ namespace Serein.Library
/// <param name="class"></param>
public static void WriteLine(Exception ex, InfoClass @class = InfoClass.General)
{
SereinEnv.environment.WriteLine(InfoType.ERROR, ex.ToString(), @class);
if(@class == InfoClass.Trivial)
{
SereinEnv.environment.WriteLine(InfoType.ERROR, ex.ToString(), @class);
}
else
{
SereinEnv.environment.WriteLine(InfoType.ERROR, ex.Message, @class);
}
}

View File

@@ -393,8 +393,8 @@ namespace Serein.NodeFlow.Env
public async Task LoadNodeInfosAsync(List<NodeInfo> nodeInfos)
{
#region NodeInfo创建NodeModel
// 流程接口节点最后才创建
// 加载节点与画布Model进行绑定
async Task AddNodeAsync(NodeInfo nodeInfo, IFlowNode nodeModel)
{
if (!TryGetCanvasModel(nodeInfo.CanvasGuid, out var canvasModel))
@@ -403,6 +403,8 @@ namespace Serein.NodeFlow.Env
}
else
{
// 节点与画布互相绑定
// 需要在UI线程上进行添加否则会报 “不支持从调度程序线程以外的线程对其 SourceCollection 进行的更改”异常
nodeModel.CanvasDetails = canvasModel;
@@ -431,7 +433,6 @@ namespace Serein.NodeFlow.Env
}
}
@@ -469,6 +470,53 @@ namespace Serein.NodeFlow.Env
}
#endregion
#region
HashSet<string> nodeIds = new HashSet<string>();
void ReloadScript(SingleScriptNode scriptNode)
{
if (nodeIds.Contains(scriptNode.Guid))
{
nodeIds.Add(scriptNode.Guid);
return;
}
var pds = scriptNode.MethodDetails?.ParameterDetailss;
if (pds is null || pds.Length == 0)
{
nodeIds.Add(scriptNode.Guid);
return;
}
foreach (var pd in pds)
{
//if (pd.ArgDataSourceType == ConnectionArgSourceType.GetPreviousNodeData) continue;
var argSourceNodeGuid = pd.ArgDataSourceNodeGuid;
if (!string.IsNullOrWhiteSpace(argSourceNodeGuid)
&& flowModelService.TryGetNodeModel(argSourceNodeGuid, out var flowNode) && flowNode is SingleScriptNode argSourceNode)
{
ReloadScript(argSourceNode);
}
}
scriptNode.ReloadScript(); // 如果是流程接口节点,则需要重新加载脚本
nodeIds.Add(scriptNode.Guid);
}
var scriptNodes = nodeInfos.Where(info => info.Type == nameof(NodeControlType.Script))
.Select(info => flowModelService.TryGetNodeModel(info.Guid, out var node) ? node : null)
.OfType<SingleScriptNode>()
.ToList();
foreach (SingleScriptNode scriptNode in scriptNodes)
{
ReloadScript(scriptNode);
}
#endregion
#region
List<NodeInfo> needPlaceNodeInfos = [];

View File

@@ -481,7 +481,7 @@ namespace Serein.NodeFlow.Env
}
catch (Exception ex)
{
SereinEnv.WriteLine(InfoType.ERROR, $"无法加载DLL文件{ex}");
SereinEnv.WriteLine(InfoType.ERROR, $"无法加载DLL文件{ex.Message}");
}
}
@@ -501,7 +501,7 @@ namespace Serein.NodeFlow.Env
}
catch (Exception ex)
{
SereinEnv.WriteLine(InfoType.ERROR, $"无法加载DLL文件{ex}");
SereinEnv.WriteLine(InfoType.ERROR, $"无法加载DLL文件{ex.Message}");
}
}

View File

@@ -80,23 +80,17 @@ namespace Serein.NodeFlow.Model
/// </summary>
public override void OnCreating()
{
/* MethodInfo? method = this.GetType().GetMethod(nameof(GetFlowApi));
if (method != null)
{
ScriptInterpreter.AddFunction(nameof(GetFlowApi), method, () => this); // 挂载获取流程接口
}*/
var md = MethodDetails;
var pd = md.ParameterDetailss ??= new ParameterDetails[1];
md.ParamsArgIndex = 0;
pd[0] = new ParameterDetails
{
Index = 0,
Name = "object",
Name = "string",
IsExplicitData = true,
DataValue = string.Empty,
DataType = typeof(object),
ExplicitType = typeof(object),
DataType = typeof(string),
ExplicitType = typeof(string),
ArgDataSourceNodeGuid = string.Empty,
ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData,
NodeModel = this,
@@ -105,7 +99,7 @@ namespace Serein.NodeFlow.Model
IsParams = true,
//Description = "脚本节点入参"
};
md.ReturnType = typeof(object); // 默认返回 object
md.ReturnType = typeof(void); // 默认返回
}
@@ -136,7 +130,7 @@ namespace Serein.NodeFlow.Model
this.MethodDetails.ParameterDetailss[i].Name = nodeInfo.ParameterData[i].ArgName;
}
ReloadScript();// 加载时重新解析
//ReloadScript();// 加载时重新解析
IsScriptChanged = false; // 重置脚本改变标志
}
@@ -144,7 +138,7 @@ namespace Serein.NodeFlow.Model
/// <summary>
/// 重新加载脚本代码
/// </summary>
public void ReloadScript()
public bool ReloadScript()
{
try
{
@@ -158,16 +152,30 @@ namespace Serein.NodeFlow.Model
varNames.Add(pd.Name);
}
Dictionary<string, Type> dict = MethodDetails.ParameterDetailss.ToDictionary(pd => pd.Name, pd => pd.DataType); // 准备预定义类型
var returnType = sereinScript.ParserScript(dict, Script); // 开始解析获取程序主节点
var argTypes = MethodDetails.ParameterDetailss
.Select(pd =>
{
if (Env.TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var node) &&
node.MethodDetails?.ReturnType is not null)
{
pd.DataType = node.MethodDetails.ReturnType;
return (pd.Name, node.MethodDetails.ReturnType);
}
return default;
})
.Where(x => x != default)
.ToDictionary(x => x.Name, x => x.ReturnType); // 准备预定义类型
var returnType = sereinScript.ParserScript(Script, argTypes); // 开始解析获取程序主节点
MethodDetails.ReturnType = returnType;
return true;
}
catch (Exception ex)
{
SereinEnv.WriteLine(InfoType.ERROR, ex.ToString());
SereinEnv.WriteLine(ex);
return false; // 解析失败
}
}
@@ -202,7 +210,7 @@ namespace Serein.NodeFlow.Model
lock (@params) {
if (IsScriptChanged)
{
ReloadScript();// 每次都重新解析
ReloadScript();// 执行时检查是否需要重新解析
IsScriptChanged = false;
context.Env.WriteLine(InfoType.INFO, $"[{Guid}]脚本解析完成");
}

View File

@@ -378,7 +378,7 @@ namespace Serein.NodeFlow.Model.Operation
if (FromNode.MethodDetails.ReturnType == typeof(void))
{
SereinEnv.WriteLine(InfoType.WARN, $"连接失败,节点参数入参不允许接收 void 返回值");
SereinEnv.WriteLine(InfoType.WARN, $"连接失败,节点参数入参不允许接收 void 返回值。起始节点[{FromNode.Guid}],目标节点[{FromNode.Guid}]。");
return false;
}
@@ -388,7 +388,7 @@ namespace Serein.NodeFlow.Model.Operation
if (false && string.IsNullOrWhiteSpace(toNodeArgSourceGuid) && flowModelService.ContainsNodeModel(toNodeArgSourceGuid))
{
SereinEnv.WriteLine(InfoType.WARN, $"连接失败,节点参数入参不允许接收多个节点返回值");
SereinEnv.WriteLine(InfoType.WARN, $"连接失败,节点参数入参不允许接收多个节点返回值。起始节点[{FromNode.Guid}],目标节点[{FromNode.Guid}]。");
return false;
}

View File

@@ -93,7 +93,7 @@ namespace Serein.NodeFlow.Services
}
catch (Exception ex)
{
SereinEnv.WriteLine(InfoType.ERROR, $"尝试卸载程序集[{assemblyName}]发生错误:{ex}");
SereinEnv.WriteLine(InfoType.ERROR, $"尝试卸载程序集[{assemblyName}]发生错误:{ex.Message}");
return false;
}

View File

@@ -21,12 +21,18 @@ namespace Serein.Script
private ProgramNode? programNode;
public Type ParserScript(Dictionary<string, Type> argTypes, string script)
/// <summary>
/// 解析脚本
/// </summary>
/// <param name="script">脚本</param>
/// <param name="argTypes">挂载的变量</param>
/// <returns></returns>
public Type ParserScript(string script, Dictionary<string, Type>? argTypes = null)
{
SereinScriptParser parser = new SereinScriptParser();
var programNode = parser.Parse(script);
TypeAnalysis.NodeSymbolInfos.Clear(); // 清空符号表
TypeAnalysis.LoadSymbol(argTypes); // 提前加载脚本节点定义的符号
if(argTypes is not null) TypeAnalysis.LoadSymbol(argTypes); // 提前加载脚本节点定义的符号
TypeAnalysis.Analysis(programNode); // 分析节点类型
var returnType = TypeAnalysis.NodeSymbolInfos[programNode]; // 获取返回类型
this.programNode = programNode;

View File

@@ -623,7 +623,13 @@ namespace Serein.Script
NextToken(); // 消耗 ")"
break;
}
else if (peekToken.Type == TokenType.BraceLeft)
{
NextToken(); // 消耗 类型名称
break;
}
}
TypeNode typeNode = new TypeNode(typeName);
typeNode.SetTokenInfo(typeToken);
ObjectInstantiationNode objectInstantiationNode = new ObjectInstantiationNode(typeNode, ctorArguments);

View File

@@ -37,13 +37,13 @@ namespace Serein.Workbench.Node.ViewModel
}
catch (Exception ex)
{
SereinEnv.WriteLine(InfoType.ERROR, ex.ToString());
SereinEnv.WriteLine(ex);
}
});
CommandLoadScript = new RelayCommand( o =>
{
NodeModel.ReloadScript();
NodeModel.ReloadScript(); // 工作台重新加载脚本
});
}

View File

@@ -40,7 +40,7 @@ namespace Serein.Workbench.ViewModels
}
catch (Exception ex)
{
flowEnvironment.WriteLine(Library.InfoType.ERROR, ex.ToString());
SereinEnv.WriteLine(ex);
return;
}
}

View File

@@ -804,7 +804,7 @@ namespace Serein.Workbench.Views
}
catch (Exception ex)
{
SereinEnv.WriteLine(InfoType.ERROR, ex.ToString());
SereinEnv.WriteLine(ex);
}
}
@@ -1578,7 +1578,7 @@ namespace Serein.Workbench.Views
}
catch (Exception ex)
{
SereinEnv.WriteLine(InfoType.ERROR, ex.ToString());
SereinEnv.WriteLine(ex);
}
}
#endregion