using Serein.Library.Api; using Serein.Library.Utils; using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace Serein.Library { /// /// 调用节点,代表一个流程中的调用点,可以是一个Action或一个异步函数。 /// public class CallNode { private Func taskFunc; private Action action; /// /// 创建一个新的调用节点,使用指定的节点Guid。 /// /// public CallNode(string nodeGuid) { Guid = nodeGuid; Init(); } /// /// 创建一个新的调用节点,使用指定的节点Guid和Action。 /// /// /// public CallNode(string nodeGuid, Action action) { Guid = nodeGuid; this.action = action; Init(); } /// /// 创建一个新的调用节点,使用指定的节点Guid和异步函数。 /// /// /// public CallNode(string nodeGuid, Func func) { Guid = nodeGuid; this.taskFunc = func; Init(); } /// /// 初始化调用节点,设置默认的子节点和后继节点字典。 /// private void Init() { //PreviousNodes = new Dictionary>(); SuccessorNodes = new Dictionary>(); foreach (ConnectionInvokeType ctType in NodeStaticConfig.ConnectionTypes) { //PreviousNodes[ctType] = new List(); SuccessorNodes[ctType] = new List(); } } private enum ActionType { Action, Task, } private ActionType actionType = ActionType.Action; /// /// 设置调用节点的Action,表示该节点执行一个同步操作。 /// /// public void SetAction(Action action) { this.action = action; actionType = ActionType.Action; } /// /// 设置调用节点的异步函数,表示该节点执行一个异步操作。 /// /// public void SetAction(Func taskFunc) { this.taskFunc = taskFunc; actionType = ActionType.Task; } /// /// 对应的节点 /// public string Guid { get; } #if false /// /// 不同分支的父节点(流程调用) /// public Dictionary> PreviousNodes { get; private set; } #endif /// /// 不同分支的子节点(流程调用) /// public Dictionary> SuccessorNodes { get; private set; } /// /// 子节点数组,分为四个分支:上游、成功、失败、错误,每个分支最多支持16个子节点。 /// public CallNode[][] ChildNodes { get; private set; } = new CallNode[][] { new CallNode[MaxChildNodeCount], new CallNode[MaxChildNodeCount], new CallNode[MaxChildNodeCount], new CallNode[MaxChildNodeCount] }; private const int MaxChildNodeCount = 16; // 每个分支最多支持16个子节点 /// /// 获取指定类型的子节点数量。 /// /// /// public int GetCount(ConnectionInvokeType type) { if (type == ConnectionInvokeType.Upstream) return UpstreamNodeCount; if (type == ConnectionInvokeType.IsSucceed) return IsSuccessorNodeCount; if (type == ConnectionInvokeType.IsFail) return IsFailNodeCount; if (type == ConnectionInvokeType.IsError) return IsErrorNodeCount; return 0; } /// /// 获取当前节点的子节点数量。 /// public int UpstreamNodeCount { get; private set; } = 0; /// /// 获取当前节点的成功后继子节点数量。 /// public int IsSuccessorNodeCount { get; private set; } = 0; /// /// 获取当前节点的失败后继子节点数量。 /// public int IsFailNodeCount { get; private set; } = 0; /// /// 获取当前节点的错误后继子节点数量。 /// public int IsErrorNodeCount { get; private set; } = 0; /// /// 添加一个上游子节点到当前节点。 /// /// /// public CallNode AddChildNodeUpstream(CallNode callNode) { var connectionInvokeType = ConnectionInvokeType.Upstream; ChildNodes[(int)connectionInvokeType][UpstreamNodeCount++] = callNode; SuccessorNodes[connectionInvokeType].Add(callNode); return this; } /// /// 添加一个成功后继子节点到当前节点。 /// /// /// public CallNode AddChildNodeSucceed(CallNode callNode) { ChildNodes[0][UpstreamNodeCount++] = callNode; var connectionInvokeType = ConnectionInvokeType.IsSucceed; ChildNodes[(int)connectionInvokeType][IsSuccessorNodeCount++] = callNode; SuccessorNodes[connectionInvokeType].Add(callNode); return this; } /// /// 添加一个失败后继子节点到当前节点。 /// /// /// public CallNode AddChildNodeFail(CallNode callNode) { var connectionInvokeType = ConnectionInvokeType.IsFail; ChildNodes[(int)connectionInvokeType][IsFailNodeCount++] = callNode; SuccessorNodes[connectionInvokeType].Add(callNode); return this; } /// /// 添加一个错误后继子节点到当前节点。 /// /// /// public CallNode AddChildNodeError(CallNode callNode) { var connectionInvokeType = ConnectionInvokeType.IsError; ChildNodes[(int)connectionInvokeType][IsErrorNodeCount++] = callNode; SuccessorNodes[connectionInvokeType].Add(callNode); return this; } /// /// 调用 /// /// /// /// /// public async Task InvokeAsync(IFlowContext context, CancellationToken token) { if (token.IsCancellationRequested) { return; } if (actionType == ActionType.Action) { action.Invoke(context); } else if (actionType == ActionType.Task) { await taskFunc.Invoke(context); } else { throw new InvalidOperationException($"生成了错误的CallNode。【{Guid}】"); } } private static readonly ObjectPool> _stackPool = new ObjectPool>(() => new Stack()); /// /// 开始执行 /// /// /// 流程运行 /// public async Task StartFlowAsync(IFlowContext context, CancellationToken token) { var stack = _stackPool.Allocate(); stack.Push(this); while (true) { if (token.IsCancellationRequested) { throw new Exception($"流程执行被取消,未能获取到流程结果。"); } #region 执行相关 // 从栈中弹出一个节点作为当前节点进行处理 var currentNode = stack.Pop(); context.NextOrientation = ConnectionInvokeType.None; // 重置上下文状态 FlowResult flowResult = null; try { context.NextOrientation = ConnectionInvokeType.IsSucceed; // 默认执行成功 await currentNode.InvokeAsync(context, token); } catch (Exception ex) { flowResult = FlowResult.Fail(currentNode.Guid, context, ex.Message); context.Env.WriteLine(InfoType.ERROR, $"节点[{currentNode}]异常:" + ex); context.NextOrientation = ConnectionInvokeType.IsError; context.ExceptionOfRuning = ex; } #endregion #region 执行完成时更新栈 // 首先将指定类别后继分支的所有节点逆序推入栈中 var nextNodes = currentNode.SuccessorNodes[context.NextOrientation]; for (int index = nextNodes.Count - 1; index >= 0; index--) { var node = nextNodes[index]; context.SetPreviousNode(node.Guid, currentNode.Guid); stack.Push(node); } // 然后将指上游分支的所有节点逆序推入栈中 var upstreamNodes = currentNode.SuccessorNodes[ConnectionInvokeType.Upstream]; for (int index = upstreamNodes.Count - 1; index >= 0; index--) { var node = upstreamNodes[index]; context.SetPreviousNode(node.Guid, currentNode.Guid); stack.Push(node); } #endregion #region 执行完成后检查 if (stack.Count == 0) { _stackPool.Free(stack); flowResult = context.GetFlowData(currentNode.Guid); return flowResult; // 说明流程到了终点 } if (context.RunState == RunState.Completion) { _stackPool.Free(stack); context.Env.WriteLine(InfoType.INFO, $"流程执行到节点[{currentNode.Guid}]时提前结束,将返回当前执行结果。"); flowResult = context.GetFlowData(currentNode.Guid); return flowResult; // 流程执行完成,返回结果 } if (token.IsCancellationRequested) { _stackPool.Free(stack); throw new Exception($"流程执行到节点[{currentNode.Guid}]时被取消,未能获取到流程结果。"); } #endregion } } } }