2025-07-27 23:34:01 +08:00
|
|
|
|
using Microsoft.Extensions.ObjectPool;
|
2025-07-06 14:34:49 +08:00
|
|
|
|
using Serein.Library.Api;
|
|
|
|
|
|
using Serein.Library.Utils;
|
|
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Threading;
|
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
2025-07-07 20:40:24 +08:00
|
|
|
|
namespace Serein.Library
|
2025-07-06 14:34:49 +08:00
|
|
|
|
{
|
2025-07-07 20:40:24 +08:00
|
|
|
|
/*
|
|
|
|
|
|
public class CallNodeLookup : IFlowCallTree
|
2025-07-06 14:34:49 +08:00
|
|
|
|
{
|
2025-07-07 20:40:24 +08:00
|
|
|
|
private static readonly string[] _keys = new[]
|
|
|
|
|
|
{
|
|
|
|
|
|
"Start", // 0
|
|
|
|
|
|
"Stop", // 1
|
|
|
|
|
|
"Reset", // 2
|
|
|
|
|
|
"Pause", // 3
|
|
|
|
|
|
"Resume", // 4
|
|
|
|
|
|
"Check", // 5
|
|
|
|
|
|
"Init", // 6
|
|
|
|
|
|
"Load", // 7
|
|
|
|
|
|
"Save", // 8
|
|
|
|
|
|
"Clear" // 9
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
private static readonly CallNode[] _values = new CallNode[10];
|
|
|
|
|
|
|
|
|
|
|
|
static CallNodeLookup()
|
|
|
|
|
|
{
|
|
|
|
|
|
*//*_values[0] = new CallNode("Start");
|
|
|
|
|
|
_values[1] = new CallNode("Stop");
|
|
|
|
|
|
_values[2] = new CallNode("Reset");
|
|
|
|
|
|
_values[3] = new CallNode("Pause");
|
|
|
|
|
|
_values[4] = new CallNode("Resume");
|
|
|
|
|
|
_values[5] = new CallNode("Check");
|
|
|
|
|
|
_values[6] = new CallNode("Init");
|
|
|
|
|
|
_values[7] = new CallNode("Load");
|
|
|
|
|
|
_values[8] = new CallNode("Save");
|
|
|
|
|
|
_values[9] = new CallNode("Clear");*//*
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 最小冲突哈希函数(简单示例,固定键集有效)
|
|
|
|
|
|
private static int PerfectHash(string key)
|
|
|
|
|
|
{
|
|
|
|
|
|
return key switch
|
|
|
|
|
|
{
|
|
|
|
|
|
"Start" => 0,
|
|
|
|
|
|
"Stop" => 1,
|
|
|
|
|
|
"Reset" => 2,
|
|
|
|
|
|
"Pause" => 3,
|
|
|
|
|
|
"Resume" => 4,
|
|
|
|
|
|
"Check" => 5,
|
|
|
|
|
|
"Init" => 6,
|
|
|
|
|
|
"Load" => 7,
|
|
|
|
|
|
"Save" => 8,
|
|
|
|
|
|
"Clear" => 9,
|
|
|
|
|
|
_ => -1
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public CallNode Get(string key)
|
|
|
|
|
|
{
|
|
|
|
|
|
int index = PerfectHash(key);
|
|
|
|
|
|
if (index >= 0 && _keys[index] == key)
|
|
|
|
|
|
return _values[index];
|
|
|
|
|
|
return null;
|
2025-07-06 14:34:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-07 20:40:24 +08:00
|
|
|
|
|
|
|
|
|
|
*/
|
2025-07-06 14:34:49 +08:00
|
|
|
|
|
2025-07-07 20:40:24 +08:00
|
|
|
|
public class FlowCallTree : IFlowCallTree
|
2025-07-06 14:34:49 +08:00
|
|
|
|
{
|
|
|
|
|
|
|
2025-07-07 20:40:24 +08:00
|
|
|
|
private readonly SortedDictionary<string, CallNode> _callNodes = new SortedDictionary<string,CallNode>();
|
|
|
|
|
|
//private readonly Dictionary<string, CallNode> _callNodes = new Dictionary<string,CallNode>();
|
2025-07-06 14:34:49 +08:00
|
|
|
|
|
|
|
|
|
|
public CallNode this[string index]
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
_callNodes.TryGetValue(index, out CallNode callNode);
|
|
|
|
|
|
return callNode;
|
|
|
|
|
|
}
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
// 设置指定索引的值
|
2025-07-07 20:40:24 +08:00
|
|
|
|
_callNodes.Add(index, value);
|
2025-07-06 14:34:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-23 16:20:41 +08:00
|
|
|
|
public void AddCallNode(string nodeGuid, Action<IFlowContext> action)
|
2025-07-06 14:34:49 +08:00
|
|
|
|
{
|
2025-07-07 20:40:24 +08:00
|
|
|
|
var node = new CallNode(nodeGuid, action);
|
2025-07-06 14:34:49 +08:00
|
|
|
|
_callNodes[nodeGuid] = node;
|
|
|
|
|
|
}
|
2025-07-23 16:20:41 +08:00
|
|
|
|
public void AddCallNode(string nodeGuid, Func<IFlowContext, Task> func)
|
2025-07-06 14:34:49 +08:00
|
|
|
|
{
|
2025-07-07 20:40:24 +08:00
|
|
|
|
var node = new CallNode(nodeGuid, func);
|
2025-07-06 14:34:49 +08:00
|
|
|
|
_callNodes[nodeGuid] = node;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-07 20:40:24 +08:00
|
|
|
|
public CallNode Get(string key)
|
|
|
|
|
|
{
|
|
|
|
|
|
return _callNodes.TryGetValue(key, out CallNode callNode) ? callNode : null;
|
|
|
|
|
|
}
|
2025-07-06 14:34:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-07-07 20:40:24 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-07-06 14:34:49 +08:00
|
|
|
|
public class CallNode
|
|
|
|
|
|
{
|
|
|
|
|
|
|
2025-07-23 16:20:41 +08:00
|
|
|
|
private Func<IFlowContext, Task> taskFunc;
|
|
|
|
|
|
private Action<IFlowContext> action;
|
2025-07-06 14:34:49 +08:00
|
|
|
|
|
2025-07-07 20:40:24 +08:00
|
|
|
|
public CallNode(string nodeGuid)
|
|
|
|
|
|
{
|
|
|
|
|
|
Guid = nodeGuid;
|
|
|
|
|
|
Init();
|
|
|
|
|
|
}
|
2025-07-23 16:20:41 +08:00
|
|
|
|
public CallNode(string nodeGuid, Action<IFlowContext> action)
|
2025-07-06 14:34:49 +08:00
|
|
|
|
{
|
|
|
|
|
|
Guid = nodeGuid;
|
|
|
|
|
|
this.action = action;
|
2025-07-07 20:40:24 +08:00
|
|
|
|
Init();
|
2025-07-06 14:34:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-23 16:20:41 +08:00
|
|
|
|
public CallNode(string nodeGuid, Func<IFlowContext, Task> func)
|
2025-07-06 14:34:49 +08:00
|
|
|
|
{
|
|
|
|
|
|
Guid = nodeGuid;
|
2025-07-07 20:40:24 +08:00
|
|
|
|
this.taskFunc = func;
|
2025-07-06 14:34:49 +08:00
|
|
|
|
Init();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-07 20:40:24 +08:00
|
|
|
|
|
2025-07-06 14:34:49 +08:00
|
|
|
|
private void Init()
|
|
|
|
|
|
{
|
2025-07-08 17:37:03 +08:00
|
|
|
|
//PreviousNodes = new Dictionary<ConnectionInvokeType, List<CallNode>>();
|
2025-07-06 14:34:49 +08:00
|
|
|
|
SuccessorNodes = new Dictionary<ConnectionInvokeType, List<CallNode>>();
|
|
|
|
|
|
foreach (ConnectionInvokeType ctType in NodeStaticConfig.ConnectionTypes)
|
|
|
|
|
|
{
|
2025-07-08 17:37:03 +08:00
|
|
|
|
//PreviousNodes[ctType] = new List<CallNode>();
|
2025-07-06 14:34:49 +08:00
|
|
|
|
SuccessorNodes[ctType] = new List<CallNode>();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-07 20:40:24 +08:00
|
|
|
|
|
2025-07-23 16:20:41 +08:00
|
|
|
|
public void SetAction(Action<IFlowContext> action)
|
2025-07-07 20:40:24 +08:00
|
|
|
|
{
|
|
|
|
|
|
this.action = action;
|
|
|
|
|
|
}
|
2025-07-23 16:20:41 +08:00
|
|
|
|
public void SetAction(Func<IFlowContext, Task> taskFunc)
|
2025-07-07 20:40:24 +08:00
|
|
|
|
{
|
|
|
|
|
|
this.taskFunc = taskFunc;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-06 14:34:49 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 对应的节点
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public string Guid { get; }
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 不同分支的父节点(流程调用)
|
|
|
|
|
|
/// </summary>
|
2025-07-08 17:37:03 +08:00
|
|
|
|
//public Dictionary<ConnectionInvokeType, List<CallNode>> PreviousNodes { get; private set; }
|
2025-07-06 14:34:49 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 不同分支的子节点(流程调用)
|
|
|
|
|
|
/// </summary>
|
2025-07-08 17:37:03 +08:00
|
|
|
|
public Dictionary<ConnectionInvokeType, List<CallNode>> SuccessorNodes { get; private set; }
|
|
|
|
|
|
public CallNode[][] ChildNodes { get; private set; } = new CallNode[][]
|
|
|
|
|
|
{
|
|
|
|
|
|
new CallNode[32],
|
|
|
|
|
|
new CallNode[32],
|
|
|
|
|
|
new CallNode[32],
|
|
|
|
|
|
new CallNode[32]
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
2025-07-06 14:34:49 +08:00
|
|
|
|
|
2025-07-08 17:37:03 +08:00
|
|
|
|
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;
|
2025-07-06 14:34:49 +08:00
|
|
|
|
|
2025-07-07 20:40:24 +08:00
|
|
|
|
public CallNode AddChildNodeUpstream(CallNode callNode)
|
2025-07-06 14:34:49 +08:00
|
|
|
|
{
|
|
|
|
|
|
var connectionInvokeType = ConnectionInvokeType.Upstream;
|
2025-07-08 17:37:03 +08:00
|
|
|
|
ChildNodes[(int)connectionInvokeType][UpstreamNodeCount++] = callNode;
|
2025-07-07 20:40:24 +08:00
|
|
|
|
SuccessorNodes[connectionInvokeType].Add(callNode);
|
2025-07-06 14:34:49 +08:00
|
|
|
|
return this;
|
|
|
|
|
|
}
|
2025-07-08 17:37:03 +08:00
|
|
|
|
|
2025-07-07 20:40:24 +08:00
|
|
|
|
public CallNode AddChildNodeSucceed(CallNode callNode)
|
2025-07-06 14:34:49 +08:00
|
|
|
|
{
|
2025-07-08 17:37:03 +08:00
|
|
|
|
ChildNodes[0][UpstreamNodeCount++] = callNode;
|
|
|
|
|
|
|
|
|
|
|
|
var connectionInvokeType = ConnectionInvokeType.IsSucceed;
|
|
|
|
|
|
ChildNodes[(int)connectionInvokeType][IsSuccessorNodeCount++] = callNode;
|
2025-07-07 20:40:24 +08:00
|
|
|
|
SuccessorNodes[connectionInvokeType].Add(callNode);
|
|
|
|
|
|
|
2025-07-06 14:34:49 +08:00
|
|
|
|
return this;
|
|
|
|
|
|
}
|
2025-07-07 20:40:24 +08:00
|
|
|
|
public CallNode AddChildNodeFail(CallNode callNode)
|
2025-07-06 14:34:49 +08:00
|
|
|
|
{
|
2025-07-07 20:40:24 +08:00
|
|
|
|
var connectionInvokeType = ConnectionInvokeType.IsFail;
|
2025-07-08 17:37:03 +08:00
|
|
|
|
ChildNodes[(int)connectionInvokeType][IsFailNodeCount++] = callNode;
|
2025-07-07 20:40:24 +08:00
|
|
|
|
SuccessorNodes[connectionInvokeType].Add(callNode);
|
|
|
|
|
|
|
2025-07-06 14:34:49 +08:00
|
|
|
|
return this;
|
|
|
|
|
|
}
|
2025-07-07 20:40:24 +08:00
|
|
|
|
public CallNode AddChildNodeError(CallNode callNode)
|
2025-07-06 14:34:49 +08:00
|
|
|
|
{
|
|
|
|
|
|
var connectionInvokeType = ConnectionInvokeType.IsError;
|
2025-07-08 17:37:03 +08:00
|
|
|
|
ChildNodes[(int)connectionInvokeType][IsErrorNodeCount++] = callNode;
|
2025-07-07 20:40:24 +08:00
|
|
|
|
SuccessorNodes[connectionInvokeType].Add(callNode);
|
2025-07-06 14:34:49 +08:00
|
|
|
|
return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 调用
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="context"></param>
|
|
|
|
|
|
/// <param name="token"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
/// <exception cref="InvalidOperationException"></exception>
|
2025-07-23 16:20:41 +08:00
|
|
|
|
public async Task InvokeAsync(IFlowContext context, CancellationToken token)
|
2025-07-06 14:34:49 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (token.IsCancellationRequested)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (action is not null)
|
|
|
|
|
|
{
|
|
|
|
|
|
action(context);
|
|
|
|
|
|
}
|
2025-07-07 20:40:24 +08:00
|
|
|
|
else if (taskFunc is not null)
|
2025-07-06 14:34:49 +08:00
|
|
|
|
{
|
2025-07-07 20:40:24 +08:00
|
|
|
|
await taskFunc(context);
|
2025-07-06 14:34:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new InvalidOperationException($"生成了错误的CallNode。【{Guid}】");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-07 20:40:24 +08:00
|
|
|
|
private static readonly DefaultObjectPool<Stack<CallNode>> _stackPool = new DefaultObjectPool<Stack<CallNode>>(new DefaultPooledObjectPolicy<Stack<CallNode>>());
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-07-06 14:34:49 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 开始执行
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="context"></param>
|
|
|
|
|
|
/// <param name="token">流程运行</param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-07-23 16:20:41 +08:00
|
|
|
|
public async Task<FlowResult> StartFlowAsync(IFlowContext context, CancellationToken token)
|
2025-07-06 14:34:49 +08:00
|
|
|
|
{
|
2025-07-07 20:40:24 +08:00
|
|
|
|
var stack = _stackPool.Get();
|
2025-07-06 14:34:49 +08:00
|
|
|
|
stack.Push(this);
|
|
|
|
|
|
while (true)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (token.IsCancellationRequested)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new Exception($"流程执行被取消,未能获取到流程结果。");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#region 执行相关
|
|
|
|
|
|
// 从栈中弹出一个节点作为当前节点进行处理
|
|
|
|
|
|
var currentNode = stack.Pop();
|
|
|
|
|
|
context.NextOrientation = ConnectionInvokeType.None; // 重置上下文状态
|
|
|
|
|
|
FlowResult flowResult = null;
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
await currentNode.InvokeAsync(context, token);
|
|
|
|
|
|
if (context.NextOrientation == ConnectionInvokeType.None) // 没有手动设置时,进行自动设置
|
|
|
|
|
|
{
|
|
|
|
|
|
context.NextOrientation = ConnectionInvokeType.IsSucceed;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
flowResult = new FlowResult(currentNode.Guid, context);
|
|
|
|
|
|
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--)
|
|
|
|
|
|
{
|
|
|
|
|
|
//if (!ignodeState)
|
|
|
|
|
|
context.SetPreviousNode(nextNodes[index].Guid, currentNode.Guid);
|
|
|
|
|
|
stack.Push(nextNodes[index]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 然后将指上游分支的所有节点逆序推入栈中
|
|
|
|
|
|
var upstreamNodes = currentNode.SuccessorNodes[ConnectionInvokeType.Upstream];
|
|
|
|
|
|
for (int index = upstreamNodes.Count - 1; index >= 0; index--)
|
|
|
|
|
|
{
|
|
|
|
|
|
context.SetPreviousNode(upstreamNodes[index].Guid, currentNode.Guid);
|
|
|
|
|
|
stack.Push(upstreamNodes[index]);
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region 执行完成后检查
|
|
|
|
|
|
|
|
|
|
|
|
if (stack.Count == 0)
|
|
|
|
|
|
{
|
2025-07-07 20:40:24 +08:00
|
|
|
|
_stackPool.Return(stack);
|
|
|
|
|
|
flowResult = context.GetFlowData(currentNode.Guid);
|
2025-07-06 14:34:49 +08:00
|
|
|
|
return flowResult; // 说明流程到了终点
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (context.RunState == RunState.Completion)
|
|
|
|
|
|
{
|
2025-07-07 20:40:24 +08:00
|
|
|
|
|
|
|
|
|
|
_stackPool.Return(stack);
|
2025-07-06 14:34:49 +08:00
|
|
|
|
context.Env.WriteLine(InfoType.INFO, $"流程执行到节点[{currentNode.Guid}]时提前结束,将返回当前执行结果。");
|
2025-07-07 20:40:24 +08:00
|
|
|
|
flowResult = context.GetFlowData(currentNode.Guid); _stackPool.Return(stack);
|
2025-07-06 14:34:49 +08:00
|
|
|
|
return flowResult; // 流程执行完成,返回结果
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (token.IsCancellationRequested)
|
|
|
|
|
|
{
|
2025-07-07 20:40:24 +08:00
|
|
|
|
_stackPool.Return(stack);
|
2025-07-06 14:34:49 +08:00
|
|
|
|
throw new Exception($"流程执行到节点[{currentNode.Guid}]时被取消,未能获取到流程结果。");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
}
|
2025-07-07 20:40:24 +08:00
|
|
|
|
|
2025-07-06 14:34:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-07 20:40:24 +08:00
|
|
|
|
|
|
|
|
|
|
public interface IFlowCallTree
|
|
|
|
|
|
{
|
|
|
|
|
|
CallNode Get(string key);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-06 14:34:49 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 轻量级流程控制器
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class LightweightFlowControl : IFlowControl
|
|
|
|
|
|
{
|
2025-07-07 20:40:24 +08:00
|
|
|
|
private readonly IFlowCallTree flowCallTree;
|
|
|
|
|
|
private readonly IFlowEnvironment flowEnvironment;
|
2025-07-23 16:20:41 +08:00
|
|
|
|
public static Serein.Library.Utils.ObjectPool<IFlowContext> FlowContextPool { get; set; }
|
2025-07-06 14:34:49 +08:00
|
|
|
|
|
2025-07-18 22:45:06 +08:00
|
|
|
|
public ISereinIOC IOC => throw new NotImplementedException();
|
|
|
|
|
|
|
2025-07-07 20:40:24 +08:00
|
|
|
|
public LightweightFlowControl(IFlowCallTree flowCallTree, IFlowEnvironment flowEnvironment)
|
2025-07-06 14:34:49 +08:00
|
|
|
|
{
|
2025-07-07 20:40:24 +08:00
|
|
|
|
this.flowCallTree = flowCallTree;
|
|
|
|
|
|
this.flowEnvironment = flowEnvironment;
|
2025-07-23 16:20:41 +08:00
|
|
|
|
FlowContextPool = new Utils.ObjectPool<IFlowContext>(() =>
|
2025-07-08 17:37:03 +08:00
|
|
|
|
{
|
2025-07-23 16:20:41 +08:00
|
|
|
|
return new FlowContext(flowEnvironment);
|
2025-07-08 17:37:03 +08:00
|
|
|
|
});
|
2025-07-06 14:34:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public Task<object> InvokeAsync(string apiGuid, Dictionary<string, object> dict)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public Task<TResult> InvokeAsync<TResult>(string apiGuid, Dictionary<string, object> dict)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-07 20:40:24 +08:00
|
|
|
|
|
|
|
|
|
|
//private readonly DefaultObjectPool<IDynamicContext> _stackPool = new DefaultObjectPool<IDynamicContext>(new DynamicContext(this));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public async Task<TResult> StartFlowAsync<TResult>(string startNodeGuid)
|
2025-07-06 14:34:49 +08:00
|
|
|
|
{
|
2025-07-23 16:20:41 +08:00
|
|
|
|
IFlowContext context = Serein.Library.LightweightFlowControl.FlowContextPool.Allocate();
|
2025-07-07 20:40:24 +08:00
|
|
|
|
CancellationTokenSource cts = new CancellationTokenSource();
|
2025-07-08 17:37:03 +08:00
|
|
|
|
FlowResult flowResult;
|
2025-07-07 20:40:24 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
|
2025-07-08 17:37:03 +08:00
|
|
|
|
flowResult = await BenchmarkHelpers.BenchmarkAsync(async () =>
|
2025-07-07 20:40:24 +08:00
|
|
|
|
{
|
|
|
|
|
|
var node = flowCallTree.Get(startNodeGuid);
|
|
|
|
|
|
var flowResult = await node.StartFlowAsync(context, cts.Token);
|
|
|
|
|
|
return flowResult;
|
|
|
|
|
|
});
|
|
|
|
|
|
#else
|
|
|
|
|
|
var node = flowCallTree.Get(startNodeGuid);
|
2025-07-08 17:37:03 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
flowResult = await node.StartFlowAsync(context, cts.Token);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (global::System.Exception)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
|
|
|
|
|
finally
|
|
|
|
|
|
{
|
|
|
|
|
|
context.Reset();
|
|
|
|
|
|
FlowContextPool.Free(context);
|
|
|
|
|
|
}
|
2025-07-07 20:40:24 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
cts?.Cancel();
|
|
|
|
|
|
cts?.Dispose();
|
|
|
|
|
|
if (flowResult.Value is TResult result)
|
|
|
|
|
|
{
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (flowResult is FlowResult && flowResult is TResult result2)
|
|
|
|
|
|
{
|
|
|
|
|
|
return result2;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new ArgumentNullException($"类型转换失败,流程返回数据与泛型不匹配,当前返回类型为[{flowResult.Value.GetType().FullName}]。");
|
|
|
|
|
|
}
|
2025-07-06 14:34:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
public async Task<bool> StartFlowAsync(string[] canvasGuids)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public Task<bool> ExitFlowAsync()
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#region 无须实现
|
|
|
|
|
|
|
|
|
|
|
|
public void ActivateFlipflopNode(string nodeGuid)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void MonitorObjectNotification(string nodeGuid, object monitorData, MonitorObjectEventArgs.ObjSourceType sourceType)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void TerminateFlipflopNode(string nodeGuid)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void TriggerInterrupt(string nodeGuid, string expression, InterruptTriggerEventArgs.InterruptTriggerType type)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void UseExternalIOC(ISereinIOC ioc)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
2025-07-18 22:45:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void UseExternalIOC(ISereinIOC ioc, Action<ISereinIOC> setDefultMemberOnReset = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
2025-07-06 14:34:49 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 轻量级流程环境事件实现
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class LightweightFlowEnvironmentEvent : IFlowEnvironmentEvent
|
|
|
|
|
|
{
|
|
|
|
|
|
public event LoadDllHandler DllLoad;
|
|
|
|
|
|
public event ProjectLoadedHandler ProjectLoaded;
|
|
|
|
|
|
public event ProjectSavingHandler ProjectSaving;
|
|
|
|
|
|
public event NodeConnectChangeHandler NodeConnectChanged;
|
|
|
|
|
|
public event CanvasCreateHandler CanvasCreated;
|
|
|
|
|
|
public event CanvasRemoveHandler CanvasRemoved;
|
|
|
|
|
|
public event NodeCreateHandler NodeCreated;
|
|
|
|
|
|
public event NodeRemoveHandler NodeRemoved;
|
|
|
|
|
|
public event NodePlaceHandler NodePlace;
|
|
|
|
|
|
public event NodeTakeOutHandler NodeTakeOut;
|
|
|
|
|
|
public event StartNodeChangeHandler StartNodeChanged;
|
|
|
|
|
|
public event FlowRunCompleteHandler FlowRunComplete;
|
|
|
|
|
|
public event MonitorObjectChangeHandler MonitorObjectChanged;
|
|
|
|
|
|
public event NodeInterruptStateChangeHandler NodeInterruptStateChanged;
|
|
|
|
|
|
public event ExpInterruptTriggerHandler InterruptTriggered;
|
|
|
|
|
|
public event IOCMembersChangedHandler IOCMembersChanged;
|
|
|
|
|
|
public event NodeLocatedHandler NodeLocated;
|
|
|
|
|
|
public event EnvOutHandler EnvOutput;
|
|
|
|
|
|
|
|
|
|
|
|
public void OnDllLoad(LoadDllEventArgs eventArgs)
|
|
|
|
|
|
{
|
|
|
|
|
|
DllLoad?.Invoke(eventArgs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void OnProjectLoaded(ProjectLoadedEventArgs eventArgs)
|
|
|
|
|
|
{
|
|
|
|
|
|
ProjectLoaded?.Invoke(eventArgs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void OnProjectSaving(ProjectSavingEventArgs eventArgs)
|
|
|
|
|
|
{
|
|
|
|
|
|
ProjectSaving?.Invoke(eventArgs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void OnNodeConnectChanged(NodeConnectChangeEventArgs eventArgs)
|
|
|
|
|
|
{
|
|
|
|
|
|
NodeConnectChanged?.Invoke(eventArgs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void OnCanvasCreated(CanvasCreateEventArgs eventArgs)
|
|
|
|
|
|
{
|
|
|
|
|
|
CanvasCreated?.Invoke(eventArgs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void OnCanvasRemoved(CanvasRemoveEventArgs eventArgs)
|
|
|
|
|
|
{
|
|
|
|
|
|
CanvasRemoved?.Invoke(eventArgs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void OnNodeCreated(NodeCreateEventArgs eventArgs)
|
|
|
|
|
|
{
|
|
|
|
|
|
NodeCreated?.Invoke(eventArgs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void OnNodeRemoved(NodeRemoveEventArgs eventArgs)
|
|
|
|
|
|
{
|
|
|
|
|
|
NodeRemoved?.Invoke(eventArgs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void OnNodePlace(NodePlaceEventArgs eventArgs)
|
|
|
|
|
|
{
|
|
|
|
|
|
NodePlace?.Invoke(eventArgs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void OnNodeTakeOut(NodeTakeOutEventArgs eventArgs)
|
|
|
|
|
|
{
|
|
|
|
|
|
NodeTakeOut?.Invoke(eventArgs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void OnStartNodeChanged(StartNodeChangeEventArgs eventArgs)
|
|
|
|
|
|
{
|
|
|
|
|
|
StartNodeChanged?.Invoke(eventArgs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void OnFlowRunComplete(FlowEventArgs eventArgs)
|
|
|
|
|
|
{
|
|
|
|
|
|
FlowRunComplete?.Invoke(eventArgs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void OnMonitorObjectChanged(MonitorObjectEventArgs eventArgs)
|
|
|
|
|
|
{
|
|
|
|
|
|
MonitorObjectChanged?.Invoke(eventArgs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void OnNodeInterruptStateChanged(NodeInterruptStateChangeEventArgs eventArgs)
|
|
|
|
|
|
{
|
|
|
|
|
|
NodeInterruptStateChanged?.Invoke(eventArgs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void OnInterruptTriggered(InterruptTriggerEventArgs eventArgs)
|
|
|
|
|
|
{
|
|
|
|
|
|
InterruptTriggered?.Invoke(eventArgs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void OnIOCMembersChanged(IOCMembersChangedEventArgs eventArgs)
|
|
|
|
|
|
{
|
|
|
|
|
|
IOCMembersChanged?.Invoke(eventArgs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void OnNodeLocated(NodeLocatedEventArgs eventArgs)
|
|
|
|
|
|
{
|
|
|
|
|
|
NodeLocated?.Invoke(eventArgs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void OnEnvOutput(InfoType type, string value)
|
|
|
|
|
|
{
|
|
|
|
|
|
EnvOutput?.Invoke(type, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 轻量级流程环境实现
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class LightweightFlowEnvironment : IFlowEnvironment
|
|
|
|
|
|
{
|
2025-07-07 20:40:24 +08:00
|
|
|
|
|
|
|
|
|
|
public LightweightFlowEnvironment(IFlowEnvironmentEvent lightweightFlowEnvironmentEvent)
|
|
|
|
|
|
{
|
|
|
|
|
|
this.Event = lightweightFlowEnvironmentEvent;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-07-06 14:34:49 +08:00
|
|
|
|
public void WriteLine(InfoType type, string message, InfoClass @class = InfoClass.Trivial)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine(message);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public ISereinIOC IOC => throw new NotImplementedException();
|
|
|
|
|
|
|
|
|
|
|
|
public IFlowEdit FlowEdit => throw new NotImplementedException();
|
|
|
|
|
|
|
|
|
|
|
|
public IFlowControl FlowControl => throw new NotImplementedException();
|
|
|
|
|
|
|
2025-07-07 20:40:24 +08:00
|
|
|
|
public IFlowEnvironmentEvent Event { get; private set; }
|
2025-07-06 14:34:49 +08:00
|
|
|
|
|
|
|
|
|
|
public string EnvName => throw new NotImplementedException();
|
|
|
|
|
|
|
|
|
|
|
|
public string ProjectFileLocation => throw new NotImplementedException();
|
|
|
|
|
|
|
|
|
|
|
|
public bool IsGlobalInterrupt => throw new NotImplementedException();
|
|
|
|
|
|
|
|
|
|
|
|
public bool IsControlRemoteEnv => throw new NotImplementedException();
|
|
|
|
|
|
|
|
|
|
|
|
public InfoClass InfoClass { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
|
|
|
|
|
public RunState FlowState { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
|
|
|
|
|
|
|
|
|
|
|
public IFlowEnvironment CurrentEnv => throw new NotImplementedException();
|
|
|
|
|
|
|
|
|
|
|
|
public UIContextOperation UIContextOperation => throw new NotImplementedException();
|
|
|
|
|
|
|
2025-07-27 23:34:01 +08:00
|
|
|
|
/* public Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres, int port, string token)
|
2025-07-06 14:34:49 +08:00
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
2025-07-27 23:34:01 +08:00
|
|
|
|
}*/
|
2025-07-06 14:34:49 +08:00
|
|
|
|
|
|
|
|
|
|
public void ExitRemoteEnv()
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public Task<FlowEnvInfo> GetEnvInfoAsync()
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public Task<SereinProjectData> GetProjectInfoAsync()
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void LoadAllNativeLibraryOfRuning(string path, bool isRecurrence = true)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void LoadLibrary(string dllPath)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public bool LoadNativeLibraryOfRuning(string file)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void LoadProject(string filePath)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public Task LoadProjetAsync(string filePath)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public Task NotificationNodeValueChangeAsync(string nodeGuid, string path, object value)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void SaveProject()
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void SetUIContextOperation(UIContextOperation uiContextOperation)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public Task StartRemoteServerAsync(int port = 7525)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void StopRemoteServer()
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public bool TryGetDelegateDetails(string assemblyName, string methodName, out DelegateDetails del)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public bool TryGetMethodDetailsInfo(string assemblyName, string methodName, out MethodDetailsInfo mdInfo)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public bool TryGetNodeModel(string nodeGuid, out IFlowNode nodeModel)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public bool TryUnloadLibrary(string assemblyFullName)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|