using Serein.Library; using Serein.Library.Api; using Serein.Script; using System.Dynamic; namespace Serein.NodeFlow.Model.Nodes { /// /// Expression Operation - 表达式操作 /// [FlowDataProperty(ValuePath = NodeValuePath.Node, IsNodeImp = true)] public partial class SingleExpOpNode : NodeModelBase { /// /// 表达式 /// [DataInfo(IsNotification = true)] private string _expression; } /// /// 表达式节点模型基类 /// public partial class SingleExpOpNode : NodeModelBase { /// /// 表达式节点是基础节点 /// public override bool IsBase => true; /// /// 表达式参数索引 /// private const int INDEX_EXPRESSION = 0; /// /// 表达式节点构造函数 /// /// public SingleExpOpNode(IFlowEnvironment environment) : base(environment) { } /// /// 加载完成后调用的方法 /// public override void OnCreating() { // 这里的这个参数是为了方便使用入参控制点,参数无意义 var pd = new ParameterDetails[1]; pd[INDEX_EXPRESSION] = new ParameterDetails { Index = INDEX_EXPRESSION, Name = nameof(Expression), IsExplicitData = false, DataValue = string.Empty, DataType = typeof(string), ExplicitType = typeof(string), ArgDataSourceNodeGuid = string.Empty, ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData, NodeModel = this, //Convertor = null, InputType = ParameterValueInputType.Input, Items = null, Description = "表达式节点入参控制点" }; this.MethodDetails.ParameterDetailss = [.. pd]; this.MethodDetails.ReturnType = typeof(object); } /// /// 导出方法信息 /// /// /// public override NodeInfo SaveCustomData(NodeInfo nodeInfo) { dynamic data = new ExpandoObject(); data.Expression = Expression ?? ""; nodeInfo.CustomData = data; return nodeInfo; } /// /// 加载自定义数据 /// /// public override void LoadCustomData(NodeInfo nodeInfo) { this.Expression = nodeInfo.CustomData?.Expression ?? ""; } /// /// 执行节点操作 /// /// /// /// public override async Task ExecutingAsync(IFlowContext context, CancellationToken token) { if(token.IsCancellationRequested) return FlowResult.Fail(this.Guid, context, "流程已通过token取消"); object? parameter = null;// 表达式节点使用上一节点数据 var pd = MethodDetails.ParameterDetailss[0]; var hasNode = context.Env.TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var argSourceNode); if (!hasNode) { parameter = null; } else { if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData) { // 使用自定义节点的参数 parameter = context.GetFlowData(argSourceNode.Guid).Value; } else if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke) { // 立刻调用目标节点,然后使用其返回值 var cts = new CancellationTokenSource(); var result = await argSourceNode.ExecutingAsync(context, cts.Token); cts?.Cancel(); cts?.Dispose(); parameter = result.Value; } } try { var result = await GetValueExpressionAsync(context, parameter, Expression); context.NextOrientation = ConnectionInvokeType.IsSucceed; return FlowResult.OK(this.Guid, context, result); } catch (Exception ex) { context.NextOrientation = ConnectionInvokeType.IsError; context.ExceptionOfRuning = ex; return FlowResult.Fail(this.Guid, context, ex.Message); } } /// /// 解析取值表达式 /// private SereinScript getValueScript; private string getValueExpression; private async Task GetValueExpressionAsync(IFlowContext flowContext, object? data, string expression) { var dataName = nameof(data); if (!expression.Equals(getValueExpression)) { getValueExpression = expression; getValueScript = new SereinScript(); var dataType = data is null ? typeof(object) : data.GetType(); if (expression[0..4].Equals("@get", StringComparison.CurrentCultureIgnoreCase)) { expression = expression[4..]; // 表达式默认包含 “.” expression = $"return {dataName}{expression};"; } else { // 表达式默认包含 “.” expression = $"return {expression};"; } var resultType = getValueScript.ParserScript(expression, new Dictionary { { dataName, dataType}, }); } IScriptInvokeContext scriptContext = new ScriptInvokeContext(flowContext); scriptContext.SetVarValue(dataName, data); var result = await getValueScript.InterpreterAsync(scriptContext); return result; } } }