mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-19 16:06:33 +08:00
整理了Serein.Library项目类文件,IDynamicContext、DynamicContext接口名称及实现类改为IFlowContext、FlowContext,使其与流程其它接口类命名风格统一。
This commit is contained in:
@@ -12,7 +12,7 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
public interface IDynamicFlowNode
|
||||
{
|
||||
Task<FlowResult> ExecutingAsync(IDynamicContext context, CancellationToken token);
|
||||
Task<FlowResult> ExecutingAsync(IFlowContext context, CancellationToken token);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Serein.Library.Api
|
||||
/// <summary>
|
||||
/// 流程上下文,包含运行环境接口,可以通过注册环境事件或调用环境接口,实现在流程运行时更改流程行为。
|
||||
/// </summary>
|
||||
public interface IDynamicContext
|
||||
public interface IFlowContext
|
||||
{
|
||||
/// <summary>
|
||||
/// 标识流程
|
||||
@@ -123,6 +123,6 @@ namespace Serein.Library.Api
|
||||
/// <param name="context"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<FlowResult> ExecutingAsync(IDynamicContext context, CancellationToken token);
|
||||
Task<FlowResult> ExecutingAsync(IFlowContext context, CancellationToken token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
using Serein.Library;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library
|
||||
{
|
||||
|
||||
}
|
||||
@@ -206,7 +206,7 @@ namespace Serein.Library
|
||||
/// <param name="context"></param>
|
||||
/// <param name="token">流程运行</param>
|
||||
/// <returns></returns>
|
||||
public static async Task<FlowResult> StartFlowAsync(this IFlowNode nodeModel, IDynamicContext context, CancellationToken token)
|
||||
public static async Task<FlowResult> StartFlowAsync(this IFlowNode nodeModel, IFlowContext context, CancellationToken token)
|
||||
{
|
||||
Stack<IFlowNode> stack = new Stack<IFlowNode>();
|
||||
HashSet<IFlowNode> processedNodes = new HashSet<IFlowNode>(); // 用于记录已处理上游节点的节点
|
||||
@@ -296,7 +296,7 @@ namespace Serein.Library
|
||||
#endif
|
||||
}
|
||||
}
|
||||
public static async Task<object[]> GetParametersAsync(this IFlowNode nodeModel, IDynamicContext context, CancellationToken token)
|
||||
public static async Task<object[]> GetParametersAsync(this IFlowNode nodeModel, IFlowContext context, CancellationToken token)
|
||||
{
|
||||
var md = nodeModel.MethodDetails;
|
||||
var pds = md.ParameterDetailss;
|
||||
@@ -372,7 +372,7 @@ namespace Serein.Library
|
||||
/// <summary>
|
||||
/// 获取对应的参数数组
|
||||
/// </summary>
|
||||
public static async Task<object[]> GetParametersAsync2(this IFlowNode nodeModel, IDynamicContext context, CancellationToken token)
|
||||
public static async Task<object[]> GetParametersAsync2(this IFlowNode nodeModel, IFlowContext context, CancellationToken token)
|
||||
{
|
||||
if (nodeModel.MethodDetails.ParameterDetailss.Length == 0)
|
||||
{
|
||||
@@ -439,7 +439,7 @@ namespace Serein.Library
|
||||
throw new ArgumentNullException($"参数数量不一致。传入参数数量:{param.Keys.Count}。接口入参数量:{pds.Length}。");
|
||||
}
|
||||
|
||||
var context = new DynamicContext(flowCallNode.Env);
|
||||
var context = new FlowContext(flowCallNode.Env);
|
||||
for (int index = 0; index < pds.Length; index++)
|
||||
{
|
||||
ParameterDetails pd = pds[index];
|
||||
|
||||
@@ -10,21 +10,21 @@ namespace Serein.Library
|
||||
/// <summary>
|
||||
/// 动态流程上下文
|
||||
/// </summary>
|
||||
public class DynamicContext : IDynamicContext
|
||||
public class FlowContext : IFlowContext
|
||||
{
|
||||
/// <summary>
|
||||
/// 动态流程上下文
|
||||
/// </summary>
|
||||
/// <param name="flowEnvironment">脚本运行时的IOC</param>
|
||||
/// <param name="ioc">脚本运行时使用的IOC容器</param>
|
||||
public DynamicContext(IFlowEnvironment flowEnvironment)
|
||||
public FlowContext(IFlowEnvironment flowEnvironment)
|
||||
{
|
||||
Env = flowEnvironment;
|
||||
RunState = RunState.Running;
|
||||
}
|
||||
|
||||
private string _guid = global::System.Guid.NewGuid().ToString();
|
||||
string IDynamicContext.Guid => _guid;
|
||||
string IFlowContext.Guid => _guid;
|
||||
|
||||
/// <summary>
|
||||
/// 运行环境
|
||||
@@ -30,7 +30,7 @@ namespace Serein.Library
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid"></param>
|
||||
/// <param name="context"></param>
|
||||
public FlowResult(string nodeGuid, IDynamicContext context, object value)
|
||||
public FlowResult(string nodeGuid, IFlowContext context, object value)
|
||||
{
|
||||
this.SourceNodeGuid = nodeGuid;
|
||||
this.ContextGuid = context.Guid;
|
||||
@@ -42,7 +42,7 @@ namespace Serein.Library
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid"></param>
|
||||
/// <param name="context"></param>
|
||||
public FlowResult(string nodeGuid, IDynamicContext context)
|
||||
public FlowResult(string nodeGuid, IFlowContext context)
|
||||
{
|
||||
this.SourceNodeGuid = nodeGuid;
|
||||
this.ContextGuid = context.Guid;
|
||||
|
||||
@@ -98,12 +98,12 @@ namespace Serein.Library
|
||||
}
|
||||
}
|
||||
|
||||
public void AddCallNode(string nodeGuid, Action<IDynamicContext> action)
|
||||
public void AddCallNode(string nodeGuid, Action<IFlowContext> action)
|
||||
{
|
||||
var node = new CallNode(nodeGuid, action);
|
||||
_callNodes[nodeGuid] = node;
|
||||
}
|
||||
public void AddCallNode(string nodeGuid, Func<IDynamicContext, Task> func)
|
||||
public void AddCallNode(string nodeGuid, Func<IFlowContext, Task> func)
|
||||
{
|
||||
var node = new CallNode(nodeGuid, func);
|
||||
_callNodes[nodeGuid] = node;
|
||||
@@ -123,22 +123,22 @@ namespace Serein.Library
|
||||
public class CallNode
|
||||
{
|
||||
|
||||
private Func<IDynamicContext, Task> taskFunc;
|
||||
private Action<IDynamicContext> action;
|
||||
private Func<IFlowContext, Task> taskFunc;
|
||||
private Action<IFlowContext> action;
|
||||
|
||||
public CallNode(string nodeGuid)
|
||||
{
|
||||
Guid = nodeGuid;
|
||||
Init();
|
||||
}
|
||||
public CallNode(string nodeGuid, Action<IDynamicContext> action)
|
||||
public CallNode(string nodeGuid, Action<IFlowContext> action)
|
||||
{
|
||||
Guid = nodeGuid;
|
||||
this.action = action;
|
||||
Init();
|
||||
}
|
||||
|
||||
public CallNode(string nodeGuid, Func<IDynamicContext, Task> func)
|
||||
public CallNode(string nodeGuid, Func<IFlowContext, Task> func)
|
||||
{
|
||||
Guid = nodeGuid;
|
||||
this.taskFunc = func;
|
||||
@@ -158,11 +158,11 @@ namespace Serein.Library
|
||||
}
|
||||
|
||||
|
||||
public void SetAction(Action<IDynamicContext> action)
|
||||
public void SetAction(Action<IFlowContext> action)
|
||||
{
|
||||
this.action = action;
|
||||
}
|
||||
public void SetAction(Func<IDynamicContext, Task> taskFunc)
|
||||
public void SetAction(Func<IFlowContext, Task> taskFunc)
|
||||
{
|
||||
this.taskFunc = taskFunc;
|
||||
}
|
||||
@@ -245,7 +245,7 @@ namespace Serein.Library
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public async Task InvokeAsync(IDynamicContext context, CancellationToken token)
|
||||
public async Task InvokeAsync(IFlowContext context, CancellationToken token)
|
||||
{
|
||||
if (token.IsCancellationRequested)
|
||||
{
|
||||
@@ -274,7 +274,7 @@ namespace Serein.Library
|
||||
/// <param name="context"></param>
|
||||
/// <param name="token">流程运行</param>
|
||||
/// <returns></returns>
|
||||
public async Task<FlowResult> StartFlowAsync(IDynamicContext context, CancellationToken token)
|
||||
public async Task<FlowResult> StartFlowAsync(IFlowContext context, CancellationToken token)
|
||||
{
|
||||
var stack = _stackPool.Get();
|
||||
stack.Push(this);
|
||||
@@ -370,7 +370,7 @@ namespace Serein.Library
|
||||
{
|
||||
private readonly IFlowCallTree flowCallTree;
|
||||
private readonly IFlowEnvironment flowEnvironment;
|
||||
public static Serein.Library.Utils.ObjectPool<IDynamicContext> FlowContextPool { get; set; }
|
||||
public static Serein.Library.Utils.ObjectPool<IFlowContext> FlowContextPool { get; set; }
|
||||
|
||||
public ISereinIOC IOC => throw new NotImplementedException();
|
||||
|
||||
@@ -378,9 +378,9 @@ namespace Serein.Library
|
||||
{
|
||||
this.flowCallTree = flowCallTree;
|
||||
this.flowEnvironment = flowEnvironment;
|
||||
FlowContextPool = new Utils.ObjectPool<IDynamicContext>(() =>
|
||||
FlowContextPool = new Utils.ObjectPool<IFlowContext>(() =>
|
||||
{
|
||||
return new DynamicContext(flowEnvironment);
|
||||
return new FlowContext(flowEnvironment);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -400,7 +400,7 @@ namespace Serein.Library
|
||||
|
||||
public async Task<TResult> StartFlowAsync<TResult>(string startNodeGuid)
|
||||
{
|
||||
IDynamicContext context = Serein.Library.LightweightFlowControl.FlowContextPool.Allocate();
|
||||
IFlowContext context = Serein.Library.LightweightFlowControl.FlowContextPool.Allocate();
|
||||
CancellationTokenSource cts = new CancellationTokenSource();
|
||||
FlowResult flowResult;
|
||||
#if DEBUG
|
||||
|
||||
@@ -209,7 +209,7 @@ namespace Serein.Library
|
||||
return pd;
|
||||
}
|
||||
|
||||
public async Task<object> ToMethodArgData(IDynamicContext context)
|
||||
public async Task<object> ToMethodArgData(IFlowContext context)
|
||||
{
|
||||
// 1. 从缓存获取
|
||||
if (context.TryGetParamsTempData(NodeModel.Guid, Index, out var data))
|
||||
@@ -217,7 +217,7 @@ namespace Serein.Library
|
||||
|
||||
// 2. 特定快捷类型
|
||||
if (typeof(IFlowEnvironment).IsAssignableFrom(DataType)) return NodeModel.Env;
|
||||
if (typeof(IDynamicContext).IsAssignableFrom(DataType)) return context;
|
||||
if (typeof(IFlowContext).IsAssignableFrom(DataType)) return context;
|
||||
if (typeof(IFlowNode).IsAssignableFrom(DataType)) return NodeModel;
|
||||
|
||||
// 3. 显式常量参数
|
||||
@@ -296,7 +296,7 @@ namespace Serein.Library
|
||||
/// 转为方法入参数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<object> ToMethodArgData2(IDynamicContext context)
|
||||
public async Task<object> ToMethodArgData2(IFlowContext context)
|
||||
{
|
||||
|
||||
var nodeModel = NodeModel;
|
||||
@@ -316,7 +316,7 @@ namespace Serein.Library
|
||||
return env;
|
||||
}
|
||||
// 返回流程上下文
|
||||
if (typeof(IDynamicContext).IsAssignableFrom(DataType))
|
||||
if (typeof(IFlowContext).IsAssignableFrom(DataType))
|
||||
{
|
||||
return context;
|
||||
}
|
||||
|
||||
@@ -23,15 +23,12 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Entity\Base\**" />
|
||||
<Compile Remove="Http\**" />
|
||||
<Compile Remove="Network\Socket\**" />
|
||||
<Compile Remove="Utils\SerinExpression\**" />
|
||||
<EmbeddedResource Remove="Entity\Base\**" />
|
||||
<EmbeddedResource Remove="Http\**" />
|
||||
<EmbeddedResource Remove="Network\Socket\**" />
|
||||
<EmbeddedResource Remove="Utils\SerinExpression\**" />
|
||||
<None Remove="Entity\Base\**" />
|
||||
<None Remove="Http\**" />
|
||||
<None Remove="Network\Socket\**" />
|
||||
<None Remove="Utils\SerinExpression\**" />
|
||||
|
||||
@@ -179,7 +179,7 @@ namespace Serein.Library.Utils
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
return Activator.CreateInstance(type);
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -308,7 +308,7 @@ namespace Serein.Library.Utils
|
||||
}
|
||||
public static object ToValueData(this string valueStr, Type type)
|
||||
{
|
||||
if (string.IsNullOrEmpty(valueStr))
|
||||
if (string.IsNullOrWhiteSpace(valueStr))
|
||||
{
|
||||
return Activator.CreateInstance(type);
|
||||
}
|
||||
|
||||
@@ -9,8 +9,6 @@ using System.Threading.Tasks;
|
||||
namespace Serein.Library.Utils
|
||||
{
|
||||
|
||||
|
||||
|
||||
public class ChannelFlowTrigger<TSignal> : IFlowTrigger<TSignal>
|
||||
{
|
||||
// 使用并发字典管理每个枚举信号对应的 Channel
|
||||
|
||||
@@ -23,7 +23,10 @@ namespace Serein.Library.Utils
|
||||
{
|
||||
// 使用并发字典管理每个信号对应的广播列表
|
||||
private readonly ConcurrentDictionary<TSignal, Subject<TriggerResult<object>>> _subscribers = new ConcurrentDictionary<TSignal, Subject<TriggerResult<object>>>();
|
||||
private readonly TriggerResultPool<object> _triggerResultPool = new TriggerResultPool<object>();
|
||||
private readonly ObjectPool<TriggerResult<object>> _triggerResultPool = new ObjectPool<TriggerResult<object>>(() => new TriggerResult<object>());
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取或创建指定信号的 Subject(消息广播者)
|
||||
/// </summary>
|
||||
@@ -66,7 +69,7 @@ namespace Serein.Library.Utils
|
||||
{
|
||||
if (!cts.Token.IsCancellationRequested)
|
||||
{
|
||||
var outResult = _triggerResultPool.Get();
|
||||
var outResult = _triggerResultPool.Allocate();
|
||||
outResult.Type = TriggerDescription.Overtime;
|
||||
subject.OnNext(outResult);
|
||||
subject.OnCompleted();
|
||||
@@ -96,7 +99,7 @@ namespace Serein.Library.Utils
|
||||
var result2 = result.Value is TResult data
|
||||
? new TriggerResult<TResult> { Value = data, Type = TriggerDescription.External }
|
||||
: new TriggerResult<TResult> { Type = TriggerDescription.TypeInconsistency };
|
||||
_triggerResultPool.Return(result); // 将结果归还池中
|
||||
_triggerResultPool.Free(result); // 将结果归还池中
|
||||
return result2;
|
||||
}
|
||||
|
||||
@@ -112,7 +115,7 @@ namespace Serein.Library.Utils
|
||||
{
|
||||
if (_subscribers.TryGetValue(signal, out var subject))
|
||||
{
|
||||
var result = _triggerResultPool.Get();
|
||||
var result = _triggerResultPool.Allocate();
|
||||
result.Type = TriggerDescription.External;
|
||||
result.Value = value;
|
||||
subject.OnNext(result); // 广播给所有订阅者
|
||||
|
||||
21
Library/Utils/FlowTrigger/TriggerDescription.cs
Normal file
21
Library/Utils/FlowTrigger/TriggerDescription.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
namespace Serein.Library.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// 触发类型
|
||||
/// </summary>
|
||||
public enum TriggerDescription
|
||||
{
|
||||
/// <summary>
|
||||
/// 外部触发
|
||||
/// </summary>
|
||||
External,
|
||||
/// <summary>
|
||||
/// 超时触发
|
||||
/// </summary>
|
||||
Overtime,
|
||||
/// <summary>
|
||||
/// 触发了,但类型不一致
|
||||
/// </summary>
|
||||
TypeInconsistency
|
||||
}
|
||||
}
|
||||
@@ -12,100 +12,4 @@ namespace Serein.Library.Utils
|
||||
public TriggerDescription Type { get; set; }
|
||||
public TResult Value { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对象池队列
|
||||
/// </summary>
|
||||
public class ConcurrentExpandingObjectPool<T> where T : class, new()
|
||||
{
|
||||
private readonly ConcurrentQueue<T> _pool; // 存储池中对象的队列
|
||||
|
||||
public ConcurrentExpandingObjectPool(int initialCapacity)
|
||||
{
|
||||
// 初始化对象池,初始容量为 initialCapacity
|
||||
_pool = new ConcurrentQueue<T>();
|
||||
|
||||
// 填充初始对象
|
||||
for (int i = 0; i < initialCapacity; i++)
|
||||
{
|
||||
_pool.Enqueue(new T());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取一个对象,如果池中没有对象,则动态创建新的对象
|
||||
/// </summary>
|
||||
/// <returns>池中的一个对象</returns>
|
||||
public T Get()
|
||||
{
|
||||
// 尝试从池中获取一个对象
|
||||
if (!_pool.TryDequeue(out var item))
|
||||
{
|
||||
// 如果池为空,则创建一个新的对象
|
||||
item = new T();
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将一个对象归还到池中
|
||||
/// </summary>
|
||||
/// <param name="item">需要归还的对象</param>
|
||||
public void Return(T item)
|
||||
{
|
||||
// 将对象归还到池中
|
||||
_pool.Enqueue(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前池中的对象数
|
||||
/// </summary>
|
||||
public int CurrentSize => _pool.Count;
|
||||
|
||||
/// <summary>
|
||||
/// 清空池中的所有对象
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
while (_pool.TryDequeue(out _)) { } // 清空队列
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用 ObjectPool 来复用 TriggerResult 对象
|
||||
/// </summary>
|
||||
public class TriggerResultPool<TResult>
|
||||
{
|
||||
private readonly ConcurrentExpandingObjectPool<TriggerResult<TResult>> _objectPool;
|
||||
|
||||
public TriggerResultPool(int defaultCapacity = 30)
|
||||
{
|
||||
_objectPool = new ConcurrentExpandingObjectPool<TriggerResult<TResult>>(defaultCapacity);
|
||||
}
|
||||
|
||||
public TriggerResult<TResult> Get() => _objectPool.Get();
|
||||
|
||||
public void Return(TriggerResult<TResult> result) => _objectPool.Return(result);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 触发类型
|
||||
/// </summary>
|
||||
public enum TriggerDescription
|
||||
{
|
||||
/// <summary>
|
||||
/// 外部触发
|
||||
/// </summary>
|
||||
External,
|
||||
/// <summary>
|
||||
/// 超时触发
|
||||
/// </summary>
|
||||
Overtime,
|
||||
/// <summary>
|
||||
/// 触发了,但类型不一致
|
||||
/// </summary>
|
||||
TypeInconsistency
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace Serein.Library.Utils
|
||||
return await Task.WhenAll(source.Select(async s => await method(s)));
|
||||
}
|
||||
|
||||
|
||||
public static async Task<IEnumerable<TResult>> SelectAsync<TSource, TResult>(this IEnumerable<TSource> source,
|
||||
Func<TSource, Task<TResult>> method,
|
||||
int concurrency = int.MaxValue)
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Serein.Library.Utils
|
||||
// 时间戳
|
||||
long timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
|
||||
// 机器标识(可以替换成更加独特的标识,如机器的MAC地址等)
|
||||
// 机器标识
|
||||
string machineId = GetMachineId();
|
||||
|
||||
// 进程ID
|
||||
@@ -53,7 +53,6 @@ namespace Serein.Library.Utils
|
||||
private static string GetMachineId()
|
||||
{
|
||||
// 这里使用 GUID 模拟机器标识
|
||||
// 可以替换为更具体的机器信息
|
||||
return Guid.NewGuid().ToString("N");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Serein.Library.Utils
|
||||
/// <param name="parent">父类对象</param>
|
||||
/// <param name="childType">子类类型</param>
|
||||
/// <returns></returns>
|
||||
public static object ConvertParentToChild(object parent,Type childType)
|
||||
public static object ConvertParentToChild(object parent, Type childType)
|
||||
{
|
||||
var child = Activator.CreateInstance(childType);
|
||||
var parentType = parent.GetType();
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Serein.Library
|
||||
SereinEnv.EnvGlobalData.AddOrUpdate(name, data, (k, o) => data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/*/// <summary>
|
||||
/// 更改某个数据的名称
|
||||
/// </summary>
|
||||
/// <param name="oldName">旧名称</param>
|
||||
@@ -56,7 +56,7 @@ namespace Serein.Library
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
/// <summary>
|
||||
/// 获取全局数据
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Serein.Library.Api;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Channels;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// 同步的单体消息触发器
|
||||
/// </summary>
|
||||
/// <typeparam name="TSingle"></typeparam>
|
||||
public class SingleSyncFlowTrigger<TSingle> : IFlowTrigger<TSingle>
|
||||
{
|
||||
private readonly ConcurrentDictionary<TSingle, Queue<TaskCompletionSource<TriggerResult<object>>>> _syncChannel
|
||||
= new ConcurrentDictionary<TSingle, Queue<TaskCompletionSource<TriggerResult<object>>>>();
|
||||
|
||||
public void CancelAllTrigger()
|
||||
{
|
||||
foreach (var triggers in _syncChannel.Values)
|
||||
{
|
||||
foreach (var trigger in triggers)
|
||||
{
|
||||
trigger.SetCanceled();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Task<bool> InvokeTriggerAsync<TResult>(TSingle signal, TResult value)
|
||||
{
|
||||
if(_syncChannel.TryGetValue(signal, out var tcss))
|
||||
{
|
||||
var tcs = tcss.Dequeue();
|
||||
var result = new TriggerResult<object>
|
||||
{
|
||||
Type = TriggerDescription.External,
|
||||
Value = value,
|
||||
};
|
||||
tcs.SetResult(result);
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
public async Task<TriggerResult<TResult>> WaitTriggerAsync<TResult>(TSingle signal)
|
||||
{
|
||||
if (!_syncChannel.TryGetValue(signal,out var tcss))
|
||||
{
|
||||
tcss = new Queue<TaskCompletionSource<TriggerResult<object>>>();
|
||||
_syncChannel.TryAdd(signal, tcss);
|
||||
}
|
||||
var taskCompletionSource = new TaskCompletionSource<TriggerResult<object>>();
|
||||
tcss.Enqueue(taskCompletionSource);
|
||||
var result = await taskCompletionSource.Task;
|
||||
if (result.Value is TResult result2)
|
||||
{
|
||||
return new TriggerResult<TResult>
|
||||
{
|
||||
Type = TriggerDescription.External,
|
||||
Value = result2,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return new TriggerResult<TResult>
|
||||
{
|
||||
Type = TriggerDescription.TypeInconsistency,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<TriggerResult<TResult>> WaitTriggerWithTimeoutAsync<TResult>(TSingle signal, TimeSpan outTime)
|
||||
{
|
||||
if (!_syncChannel.TryGetValue(signal, out var tcss))
|
||||
{
|
||||
tcss = new Queue<TaskCompletionSource<TriggerResult<object>>>();
|
||||
_syncChannel.TryAdd(signal, tcss);
|
||||
}
|
||||
|
||||
|
||||
var taskCompletionSource = new TaskCompletionSource<TriggerResult<object>>();
|
||||
tcss.Enqueue(taskCompletionSource);
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
// 异步任务:超时后自动触发信号
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(outTime, cts.Token);
|
||||
if (!cts.IsCancellationRequested) // 如果还没有被取消
|
||||
{
|
||||
var outResult = new TriggerResult<object>()
|
||||
{
|
||||
Type = TriggerDescription.Overtime
|
||||
};
|
||||
taskCompletionSource.SetResult(outResult); // 超时触发
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// 超时任务被取消
|
||||
}
|
||||
finally
|
||||
{
|
||||
cts?.Dispose(); // 确保 cts 被释放
|
||||
}
|
||||
}, cts.Token);
|
||||
var result = await taskCompletionSource.Task;
|
||||
cts?.Cancel();
|
||||
if (result.Value is TResult result2)
|
||||
{
|
||||
return new TriggerResult<TResult>
|
||||
{
|
||||
Type = result.Type,
|
||||
Value = result2,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return new TriggerResult<TResult>
|
||||
{
|
||||
Type = result.Type,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,14 +27,14 @@ namespace Net462DllTest.LogicControl
|
||||
|
||||
#region 初始化
|
||||
[NodeAction(NodeType.Loading)] // Loading 初始化完成已注入依赖项,可以开始逻辑上的操作
|
||||
public void Loading(IDynamicContext context)
|
||||
public void Loading(IFlowContext context)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
[NodeAction(NodeType.Exit)] // 流程结束时自动执行
|
||||
public void Exit(IDynamicContext context)
|
||||
public void Exit(IFlowContext context)
|
||||
{
|
||||
MyPlc.Close();
|
||||
MyPlc.CancelAllTrigger();
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Net462DllTest.Web
|
||||
|
||||
#region 初始化、初始化完成以及退出的事件
|
||||
[NodeAction(NodeType.Init)]
|
||||
public void Init(IDynamicContext context)
|
||||
public void Init(IFlowContext context)
|
||||
{
|
||||
var ioc = context.Env.FlowControl.IOC;
|
||||
ioc.Register<WebSocketServer>();
|
||||
@@ -42,7 +42,7 @@ namespace Net462DllTest.Web
|
||||
}
|
||||
|
||||
[NodeAction(NodeType.Loading)] // Loading 初始化完成已注入依赖项,可以开始逻辑上的操作
|
||||
public void Loading(IDynamicContext context)
|
||||
public void Loading(IFlowContext context)
|
||||
{
|
||||
var ioc = context.Env.FlowControl.IOC;
|
||||
// 注册控制器
|
||||
@@ -69,7 +69,7 @@ namespace Net462DllTest.Web
|
||||
}
|
||||
|
||||
[NodeAction(NodeType.Exit)] // 流程结束时自动执行
|
||||
public void Exit(IDynamicContext context)
|
||||
public void Exit(IFlowContext context)
|
||||
{
|
||||
var ioc = context.Env.FlowControl.IOC;
|
||||
ioc.Run<WebApiServer>((apiServer) =>
|
||||
|
||||
@@ -36,10 +36,10 @@ namespace Serein.NodeFlow.Env
|
||||
this.flowModelService = flowModelService;
|
||||
this.UIContextOperation = UIContextOperation;
|
||||
|
||||
contexts = new ObjectPool<IDynamicContext>(() => new DynamicContext(flowEnvironment));
|
||||
contexts = new ObjectPool<IFlowContext>(() => new FlowContext(flowEnvironment));
|
||||
}
|
||||
|
||||
private ObjectPool<IDynamicContext> contexts;
|
||||
private ObjectPool<IFlowContext> contexts;
|
||||
private FlowWorkManagement flowWorkManagement;
|
||||
private ISereinIOC externalIOC;
|
||||
private Action<ISereinIOC> setDefultMemberOnReset;
|
||||
@@ -312,7 +312,7 @@ namespace Serein.NodeFlow.Env
|
||||
throw new ArgumentNullException($"参数数量不一致。传入参数数量:{dict.Keys.Count}。接口入参数量:{pds.Length}。");
|
||||
}
|
||||
|
||||
IDynamicContext context = contexts.Allocate();
|
||||
IFlowContext context = contexts.Allocate();
|
||||
for (int index = 0; index < pds.Length; index++)
|
||||
{
|
||||
ParameterDetails pd = pds[index];
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace Serein.NodeFlow
|
||||
/// <summary>
|
||||
/// 上下文线程池
|
||||
/// </summary>
|
||||
public Serein.Library.Utils.ObjectPool<IDynamicContext> FlowContextPool { get; set; }
|
||||
public Serein.Library.Utils.ObjectPool<IFlowContext> FlowContextPool { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 每个画布需要启用的节点
|
||||
|
||||
@@ -110,7 +110,7 @@ namespace Serein.NodeFlow.Model
|
||||
/// <param name="token"></param>
|
||||
/// <param name="args">自定义参数</param>
|
||||
/// <returns>节点传回数据对象</returns>
|
||||
public virtual async Task<FlowResult> ExecutingAsync(IDynamicContext context, CancellationToken token)
|
||||
public virtual async Task<FlowResult> ExecutingAsync(IFlowContext context, CancellationToken token)
|
||||
{
|
||||
|
||||
// 执行触发检查是否需要中断
|
||||
|
||||
@@ -110,7 +110,7 @@ namespace Serein.NodeFlow.Model
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public override async Task<FlowResult> ExecutingAsync(IDynamicContext context, CancellationToken token)
|
||||
public override async Task<FlowResult> ExecutingAsync(IFlowContext context, CancellationToken token)
|
||||
{
|
||||
if (token.IsCancellationRequested)
|
||||
{
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace Serein.NodeFlow.Model
|
||||
}
|
||||
|
||||
|
||||
public override async Task<FlowResult> ExecutingAsync(IDynamicContext context, CancellationToken token)
|
||||
public override async Task<FlowResult> ExecutingAsync(IFlowContext context, CancellationToken token)
|
||||
{
|
||||
if(token.IsCancellationRequested) return new FlowResult(this.Guid, context);
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Serein.NodeFlow.Model
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public override async Task<FlowResult> ExecutingAsync(IDynamicContext context, CancellationToken token)
|
||||
public override async Task<FlowResult> ExecutingAsync(IFlowContext context, CancellationToken token)
|
||||
{
|
||||
#region 执行前中断
|
||||
if (DebugSetting.IsInterrupt) // 执行触发前
|
||||
|
||||
@@ -313,7 +313,7 @@ namespace Serein.NodeFlow.Model
|
||||
/// <param name="context"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public override async Task<FlowResult> ExecutingAsync(IDynamicContext context, CancellationToken token)
|
||||
public override async Task<FlowResult> ExecutingAsync(IFlowContext context, CancellationToken token)
|
||||
{
|
||||
if (!UploadTargetNode())
|
||||
{
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace Serein.NodeFlow.Model
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public override async Task<FlowResult> ExecutingAsync(IDynamicContext context, CancellationToken token)
|
||||
public override async Task<FlowResult> ExecutingAsync(IFlowContext context, CancellationToken token)
|
||||
{
|
||||
if (token.IsCancellationRequested) return new FlowResult(this.Guid, context);
|
||||
if (string.IsNullOrEmpty(KeyName))
|
||||
|
||||
@@ -195,7 +195,7 @@ namespace Serein.NodeFlow.Model
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public override async Task<FlowResult> ExecutingAsync(IDynamicContext context, CancellationToken token)
|
||||
public override async Task<FlowResult> ExecutingAsync(IFlowContext context, CancellationToken token)
|
||||
{
|
||||
var result = await ExecutingAsync(this, context, token);
|
||||
return result;
|
||||
@@ -208,7 +208,7 @@ namespace Serein.NodeFlow.Model
|
||||
/// <param name="context"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<FlowResult> ExecutingAsync(NodeModelBase flowCallNode, IDynamicContext context, CancellationToken token)
|
||||
public async Task<FlowResult> ExecutingAsync(NodeModelBase flowCallNode, IFlowContext context, CancellationToken token)
|
||||
{
|
||||
if (token.IsCancellationRequested) return new FlowResult(this.Guid, context);
|
||||
var @params = await flowCallNode.GetParametersAsync(context, token);
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Serein.NodeFlow.Model
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<FlowResult> ExecutingAsync(IDynamicContext context, CancellationToken token)
|
||||
public override async Task<FlowResult> ExecutingAsync(IFlowContext context, CancellationToken token)
|
||||
{
|
||||
if (token.IsCancellationRequested) return new FlowResult(this.Guid, context);
|
||||
if(Adapter is null)
|
||||
|
||||
@@ -132,7 +132,7 @@ namespace Serein.NodeFlow.Services
|
||||
/// <exception cref="Exception"></exception>
|
||||
private void GenerateMethod(StringBuilder sb_main, IFlowNode flowNode)
|
||||
{
|
||||
string? dynamicContextTypeName = typeof(IDynamicContext).FullName;
|
||||
string? dynamicContextTypeName = typeof(IFlowContext).FullName;
|
||||
string? flowContext = nameof(flowContext);
|
||||
|
||||
if (flowNode.ControlType == NodeControlType.Action && flowNode is SingleActionNode actionNode)
|
||||
@@ -241,7 +241,7 @@ namespace Serein.NodeFlow.Services
|
||||
var previousNode = $"previousNode{index}";
|
||||
var valueType = pd.IsParams ? $"global::{pd.DataType.FullName}" : $"global::{paramtTypeFullName}";
|
||||
sb_invoke_login.AppendCode(3, $"global::System.String {previousNode} = {flowContext}.GetPreviousNode(\"{actionNode.Guid}\");"); // 获取运行时上一节点Guid
|
||||
sb_invoke_login.AppendCode(3, $"{valueType} value{index} = {previousNode} == null ? default : ({valueType}){flowContext}.{nameof(IDynamicContext.GetFlowData)}({previousNode}).Value; // 获取运行时上一节点的数据");
|
||||
sb_invoke_login.AppendCode(3, $"{valueType} value{index} = {previousNode} == null ? default : ({valueType}){flowContext}.{nameof(IFlowContext.GetFlowData)}({previousNode}).Value; // 获取运行时上一节点的数据");
|
||||
}
|
||||
else if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
|
||||
{
|
||||
@@ -251,11 +251,11 @@ namespace Serein.NodeFlow.Services
|
||||
var otherNodeReturnType = otherNode.MethodDetails.ReturnType;
|
||||
if (otherNodeReturnType == typeof(object))
|
||||
{
|
||||
sb_invoke_login.AppendCode(3, $"{valueType} value{index} = ({valueType}){flowContext}.{nameof(IDynamicContext.GetFlowData)}(\"{pd.ArgDataSourceNodeGuid}\").Value; // 获取指定节点的数据");
|
||||
sb_invoke_login.AppendCode(3, $"{valueType} value{index} = ({valueType}){flowContext}.{nameof(IFlowContext.GetFlowData)}(\"{pd.ArgDataSourceNodeGuid}\").Value; // 获取指定节点的数据");
|
||||
}
|
||||
else if (pd.DataType.IsAssignableFrom(otherNodeReturnType))
|
||||
{
|
||||
sb_invoke_login.AppendCode(3, $"{valueType} value{index} = ({valueType}){flowContext}.{nameof(IDynamicContext.GetFlowData)}(\"{pd.ArgDataSourceNodeGuid}\").Value; // 获取指定节点的数据");
|
||||
sb_invoke_login.AppendCode(3, $"{valueType} value{index} = ({valueType}){flowContext}.{nameof(IFlowContext.GetFlowData)}(\"{pd.ArgDataSourceNodeGuid}\").Value; // 获取指定节点的数据");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -277,7 +277,7 @@ namespace Serein.NodeFlow.Services
|
||||
var valueType = pd.IsParams ? $"global::{pd.DataType.FullName}" : $"global::{otherNode.MethodDetails.ReturnType.FullName}";
|
||||
if (otherNodeReturnType == typeof(object))
|
||||
{
|
||||
sb_invoke_login.AppendCode(3, $"{valueType} value{index} = ({valueType}){flowContext}.{nameof(IDynamicContext.GetFlowData)}(\"{pd.ArgDataSourceNodeGuid}\").Value; // 获取指定节点的数据");
|
||||
sb_invoke_login.AppendCode(3, $"{valueType} value{index} = ({valueType}){flowContext}.{nameof(IFlowContext.GetFlowData)}(\"{pd.ArgDataSourceNodeGuid}\").Value; // 获取指定节点的数据");
|
||||
}
|
||||
else if (pd.DataType.IsAssignableFrom(otherNodeReturnType))
|
||||
{
|
||||
@@ -329,7 +329,7 @@ namespace Serein.NodeFlow.Services
|
||||
}
|
||||
sb_invoke_login.AppendCode(0, $"); // 调用方法 {md.MethodAnotherName}");
|
||||
|
||||
sb_invoke_login.AppendCode(3, $"{flowContext}.{nameof(IDynamicContext.AddOrUpdate)}(\"{actionNode.Guid}\", result);", false); // 更新数据
|
||||
sb_invoke_login.AppendCode(3, $"{flowContext}.{nameof(IFlowContext.AddOrUpdate)}(\"{actionNode.Guid}\", result);", false); // 更新数据
|
||||
//sb_invoke_login.AppendCode(3, $"return result;", false);
|
||||
}
|
||||
#endregion
|
||||
@@ -422,7 +422,7 @@ namespace Serein.NodeFlow.Services
|
||||
// 如果目标方法是异步的,则自动 await 进行等待
|
||||
sb_invoke_login.AppendCode(4, $"var {resultName} = {(md.IsAsync ? $"await" : string.Empty)} {invokeFunctionContext}({invokeParamContext});");
|
||||
|
||||
sb_invoke_login.AppendCode(4, $"{flowContext}.{nameof(IDynamicContext.AddOrUpdate)}(\"{flowCallNode.TargetNode.Guid}\", {resultName});"); // 更新数据
|
||||
sb_invoke_login.AppendCode(4, $"{flowContext}.{nameof(IFlowContext.AddOrUpdate)}(\"{flowCallNode.TargetNode.Guid}\", {resultName});"); // 更新数据
|
||||
sb_invoke_login.AppendCode(4, $"{flowApiMethodInfo.ObjPoolName}.Return({apiData});"); // 归还到对象池
|
||||
//sb_invoke_login.AppendCode(3, $"return result;", false);
|
||||
}
|
||||
@@ -865,7 +865,7 @@ namespace Serein.NodeFlow.Services
|
||||
public string ToInterfaceMethodSignature(ParamType type)
|
||||
{
|
||||
var taskTypeFullName = $"global::System.Threading.Tasks.Task";
|
||||
var contextFullName = $"global::{typeof(IDynamicContext).FullName}";
|
||||
var contextFullName = $"global::{typeof(IFlowContext).FullName}";
|
||||
var tokenFullName = $"global::{typeof(CancellationToken).FullName}";
|
||||
var returnContext = IsVoid ? taskTypeFullName : $"{taskTypeFullName}<{ReturnType.FullName}>";
|
||||
if (type == ParamType.Defute)
|
||||
@@ -895,8 +895,8 @@ namespace Serein.NodeFlow.Services
|
||||
public string ToImpleMethodSignature(ParamType type)
|
||||
{
|
||||
var taskTypeFullName = $"global::System.Threading.Tasks.Task";
|
||||
var contextApiFullName = $"global::{typeof(IDynamicContext).FullName}";
|
||||
var contextImpleFullName = $"global::{typeof(DynamicContext).FullName}";
|
||||
var contextApiFullName = $"global::{typeof(IFlowContext).FullName}";
|
||||
var contextImpleFullName = $"global::{typeof(FlowContext).FullName}";
|
||||
var tokenSourceFullName = $"global::{typeof(CancellationTokenSource).FullName}";
|
||||
var tokenFullName = $"global::{typeof(CancellationToken).FullName}";
|
||||
var flowContextPoolName = $"global::{typeof(LightweightFlowControl).FullName}";
|
||||
@@ -927,7 +927,7 @@ namespace Serein.NodeFlow.Services
|
||||
sb.AppendCode(3, $"}}");
|
||||
sb.AppendCode(3, $"finally");
|
||||
sb.AppendCode(3, $"{{");
|
||||
sb.AppendCode(4, $"{flowContext}.{nameof(IDynamicContext.Reset)}(); ");
|
||||
sb.AppendCode(4, $"{flowContext}.{nameof(IFlowContext.Reset)}(); ");
|
||||
sb.AppendCode(4, $"cts.{nameof(CancellationTokenSource.Dispose)}(); ");
|
||||
sb.AppendCode(4, $"{flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Free)}({flowContext}); // 释放上下文");
|
||||
sb.AppendCode(3, $"}}");
|
||||
@@ -944,7 +944,7 @@ namespace Serein.NodeFlow.Services
|
||||
sb.AppendCode(3, $"try");
|
||||
sb.AppendCode(3, $"{{");
|
||||
sb.AppendCode(4, $"await {ApiMethodName}({flowContext}, {token}, {invokeParamSignature}); // 调用目标方法");
|
||||
sb.AppendCode(4, $"{flowContext}.{nameof(IDynamicContext.Reset)}(); ");
|
||||
sb.AppendCode(4, $"{flowContext}.{nameof(IFlowContext.Reset)}(); ");
|
||||
sb.AppendCode(3, $"}}");
|
||||
sb.AppendCode(3, $"catch (Exception)");
|
||||
sb.AppendCode(3, $"{{");
|
||||
@@ -974,8 +974,8 @@ namespace Serein.NodeFlow.Services
|
||||
ParamInfo? info = ParamInfos[index];
|
||||
sb.AppendCode(4, $"data.{info.ParamName.ToPascalCase()} = {info.ParamName}; // [{index}] {info.Comments}");
|
||||
}
|
||||
sb.AppendCode(3, $"{flowContext}.{nameof(IDynamicContext.AddOrUpdate)}(\"{ApiMethodName}\", data);");
|
||||
sb.AppendCode(3, $"{flowContext}.{nameof(IDynamicContext.SetPreviousNode)}(\"{NodeModel.TargetNode.Guid}\", \"{ApiMethodName}\");");
|
||||
sb.AppendCode(3, $"{flowContext}.{nameof(IFlowContext.AddOrUpdate)}(\"{ApiMethodName}\", data);");
|
||||
sb.AppendCode(3, $"{flowContext}.{nameof(IFlowContext.SetPreviousNode)}(\"{NodeModel.TargetNode.Guid}\", \"{ApiMethodName}\");");
|
||||
sb.AppendCode(3, $"global::{typeof(CallNode).FullName} node = Get(\"{NodeModel.Guid}\");");
|
||||
sb.AppendCode(3, $"await node.{nameof(CallNode.StartFlowAsync)}({flowContext}, {token}); // 调用目标方法");
|
||||
sb.AppendCode(3, $"}}");
|
||||
@@ -1015,7 +1015,7 @@ namespace Serein.NodeFlow.Services
|
||||
sb.AppendCode(3, $"}}");
|
||||
sb.AppendCode(3, $"finally");
|
||||
sb.AppendCode(3, $"{{");
|
||||
sb.AppendCode(4, $"{flowContext}.{nameof(IDynamicContext.Reset)}(); ");
|
||||
sb.AppendCode(4, $"{flowContext}.{nameof(IFlowContext.Reset)}(); ");
|
||||
sb.AppendCode(4, $"cts.{nameof(CancellationTokenSource.Dispose)}(); ");
|
||||
sb.AppendCode(4, $"{flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Free)}({flowContext}); // 释放上下文");
|
||||
sb.AppendCode(3, $"}}");
|
||||
@@ -1040,7 +1040,7 @@ namespace Serein.NodeFlow.Services
|
||||
sb.AppendCode(3, $"}}");
|
||||
sb.AppendCode(3, $"finally");
|
||||
sb.AppendCode(3, $"{{");
|
||||
sb.AppendCode(4, $"{flowContext}.{nameof(IDynamicContext.Reset)}(); ");
|
||||
sb.AppendCode(4, $"{flowContext}.{nameof(IFlowContext.Reset)}(); ");
|
||||
sb.AppendCode(4, $"{flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Free)}({flowContext}); // 释放上下文");
|
||||
sb.AppendCode(3, $"}}");
|
||||
sb.AppendCode(2, $"}}");
|
||||
@@ -1059,8 +1059,8 @@ namespace Serein.NodeFlow.Services
|
||||
ParamInfo? info = ParamInfos[index];
|
||||
sb.AppendCode(4, $"data.{info.ParamName.ToPascalCase()} = {info.ParamName}; // [{index}] {info.Comments}"); // 进行赋值
|
||||
}
|
||||
sb.AppendCode(3, $"{flowContext}.{nameof(IDynamicContext.AddOrUpdate)}(\"{ApiMethodName}\", data);");
|
||||
sb.AppendCode(3, $"{flowContext}.{nameof(IDynamicContext.SetPreviousNode)}(\"{NodeModel.Guid}\", \"{ApiMethodName}\");");
|
||||
sb.AppendCode(3, $"{flowContext}.{nameof(IFlowContext.AddOrUpdate)}(\"{ApiMethodName}\", data);");
|
||||
sb.AppendCode(3, $"{flowContext}.{nameof(IFlowContext.SetPreviousNode)}(\"{NodeModel.Guid}\", \"{ApiMethodName}\");");
|
||||
sb.AppendCode(3, $"global::{typeof(CallNode).FullName} node = Get(\"{NodeModel.Guid}\");");
|
||||
sb.AppendCode(3, $"global::{typeof(FlowResult).FullName} {flowResult} = await node.{nameof(CallNode.StartFlowAsync)}({flowContext}, {token}); // 调用目标方法");
|
||||
sb.AppendCode(3, $"if ({flowResult}.{nameof(FlowResult.Value)} is global::{ReturnType.FullName} result)");
|
||||
|
||||
@@ -378,7 +378,7 @@ namespace Serein.NodeFlow.Services
|
||||
/// <param name="pool"></param>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
private static async Task? CallSubsequentNode(SingleFlipflopNode singleFlipFlopNode, CancellationToken singleToken, ObjectPool<IDynamicContext> pool, IDynamicContext context)
|
||||
private static async Task? CallSubsequentNode(SingleFlipflopNode singleFlipFlopNode, CancellationToken singleToken, ObjectPool<IFlowContext> pool, IFlowContext context)
|
||||
{
|
||||
var flowState = context.NextOrientation; // 记录一下流程状态
|
||||
var nextNodes = singleFlipFlopNode.SuccessorNodes[ConnectionInvokeType.Upstream]; // 优先调用上游分支
|
||||
|
||||
18
README.md
18
README.md
@@ -15,14 +15,14 @@ https://space.bilibili.com/33526379
|
||||
* 动作节点 - Action
|
||||
* 触发器节点 - Flipflop
|
||||
* UI节点 - UI
|
||||
# 关于 IDynamicContext 说明(重要)
|
||||
* 基本说明:IDynamicContext 是节点之间传递数据的接口、载体,其实例由 FlowEnvironment 运行环境自动实现,内部提供全局单例的环境接口,用以注册、获取实例(单例模式),一般情况下,你无须关注 FlowEnvironment 对外暴露的属性方法。
|
||||
# 关于 IFlowContext 说明(重要)
|
||||
* 基本说明:IFlowContext 是节点之间传递数据的接口、载体,其实例由 FlowEnvironment 运行环境自动实现,内部提供全局单例的环境接口,用以注册、获取实例(单例模式),一般情况下,你无须关注 FlowEnvironment 对外暴露的属性方法。
|
||||
* 重要概念:
|
||||
* 每个节点其实对应类库中的某一个方法,这些方法组合起来,加上预先设置的逻辑分支,就是一个完整的节点流。在这个节点流当中,从第一个节点开始、直到所有可达的节点,都会通过同一个流程上下文传递、共享数据。为了符合多线程操作的理念,每个运行起来的节点流之间,流程数据并不互通,从根本隔绝了“脏数据”的产生。
|
||||
* 一些重要的属性:
|
||||
* RunState - 流程状态:
|
||||
* 简述:枚举,标识流程运行的状态(初始化,运行中,运行完成)
|
||||
* 场景:类库代码中创建了运行时间较长的异步任务、或开辟了另一个线程进行循环操作时,可以在方法入参定义一个 IDynamicContext 类型入参,然后在代码中使用形成闭包,以及时判断流程是否已经结束。另外的,如果想监听项目停止运行,可以订阅 context.Env.OnFlowRunComplete 事件。
|
||||
* 场景:类库代码中创建了运行时间较长的异步任务、或开辟了另一个线程进行循环操作时,可以在方法入参定义一个 IFlowContext 类型入参,然后在代码中使用形成闭包,以及时判断流程是否已经结束。另外的,如果想监听项目停止运行,可以订阅 context.Env.OnFlowRunComplete 事件。
|
||||
* NextOrientation - 即将进入的分支:
|
||||
* 简述:流程分支枚举, Upstream(上游分支)、IsSucceed(真分支)、IsFail(假分支),IsError(异常分支)。
|
||||
* 场景:允许你在类库代码中操作该属性,手动控制当前节点运行完成后,下一个会执行哪一个类别的节点。
|
||||
@@ -32,15 +32,15 @@ https://space.bilibili.com/33526379
|
||||
# 关于 DynamicNodeType 枚举的补充说明。
|
||||
## 1. 不生成节点控件的枚举值:
|
||||
* **Init - 初始化方法**
|
||||
* 入参:**IDynamicContext**(有且只有一个参数)。
|
||||
* 入参:**IFlowContext**(有且只有一个参数)。
|
||||
* 返回值:自定义,但不会处理返回值,支持异步等待。
|
||||
* 描述:在运行时首先被调用。语义类似于构造方法。建议在Init方法内初始化类、注册类等一切需要在构造函数中执行的方法。
|
||||
* **Loading - 加载方法**
|
||||
* 入参:**IDynamicContext**(有且只有一个参数)。
|
||||
* 入参:**IFlowContext**(有且只有一个参数)。
|
||||
* 返回值:自定义,但不会处理返回值,支持异步等待。
|
||||
* 描述:当所有Dll的Init方法调用完成后,首先调用、也才会调用DLL的Loading方法。建议在Loading方法内进行业务上的初始化(例如启动Web,启动第三方服务)。
|
||||
* **Exit - 结束方法**
|
||||
* 入参:**IDynamicContext**(有且只有一个参数)。
|
||||
* 入参:**IFlowContext**(有且只有一个参数)。
|
||||
* 返回值:自定义,但不会处理返回值,支持异步等待。
|
||||
* 描述:当结束/手动结束运行时,会调用所有Dll的Exit方法。使用场景类似于:终止内部的其它线程,通知其它进程关闭,例如停止第三方服务。
|
||||
## 2. 基础节点
|
||||
@@ -172,14 +172,14 @@ https://space.bilibili.com/33526379
|
||||
~~~
|
||||
## 3. 从DLL生成控件的枚举值:
|
||||
* **Action - 动作**
|
||||
* 入参:自定义。如果入参类型为IDynamicContext,会传入当前的上下文;如果入参类型为IFlowNode,会传入节点对应的实体Model。如果不显式指定参数来源,参数会尝试获取运行时上一节点返回值,并根据当前入参类型尝试进行类型转换。
|
||||
* 入参:自定义。如果入参类型为IFlowContext,会传入当前的上下文;如果入参类型为IFlowNode,会传入节点对应的实体Model。如果不显式指定参数来源,参数会尝试获取运行时上一节点返回值,并根据当前入参类型尝试进行类型转换。
|
||||
* 返回值:自定义,支持异步等待。
|
||||
* 描述:同步执行对应的方法。
|
||||
* **Flipflop - 触发器**
|
||||
* 全局触发器
|
||||
* 入参:依照Action节点。
|
||||
* 返回值:Task`<IFlipflopContext<TResult>>`
|
||||
* 描述:运行开始时,所有无上级节点的触发器节点(在当前分支中作为起始节点),分别建立新的线程运行,然后异步等待触发(如果有)。这种触发器拥有独自的IDynamicContext上下文(共用同一个Ioc),执行完成之后,会重新从分支起点的触发器开始等待。
|
||||
* 描述:运行开始时,所有无上级节点的触发器节点(在当前分支中作为起始节点),分别建立新的线程运行,然后异步等待触发(如果有)。这种触发器拥有独自的IFlowContext上下文(共用同一个Ioc),执行完成之后,会重新从分支起点的触发器开始等待。
|
||||
* 分支中的触发器
|
||||
* 入参:依照Action节点。
|
||||
* 返回值:Task`<IFlipflopContext<TResult>>`
|
||||
@@ -201,7 +201,7 @@ https://space.bilibili.com/33526379
|
||||
internal class FlowControl
|
||||
{
|
||||
[NodeAction(NodeType.UI)]
|
||||
public async Task<IEmbeddedContent> CreateImageControl(DynamicContext context)
|
||||
public async Task<IEmbeddedContent> CreateImageControl(FlowContext context)
|
||||
{
|
||||
WpfUserControlAdapter adapter = null;
|
||||
// 其实你也可以直接创建实例
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Serein.Script
|
||||
/// <summary>
|
||||
/// 脚本运行的流程上下文,包含了流程上下文和变量等信息
|
||||
/// </summary>
|
||||
IDynamicContext FlowContext { get; }
|
||||
IFlowContext FlowContext { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否该退出了(由 TokenSource 控制,用于响应外部发出停止信号)
|
||||
|
||||
@@ -7,10 +7,10 @@ namespace Serein.Script
|
||||
/// <summary>
|
||||
/// 脚本使用流程上下文
|
||||
/// </summary>
|
||||
/// <param name="dynamicContext"></param>
|
||||
public ScriptInvokeContext(IDynamicContext dynamicContext)
|
||||
/// <param name="flowContext"></param>
|
||||
public ScriptInvokeContext(IFlowContext flowContext)
|
||||
{
|
||||
FlowContext = dynamicContext;
|
||||
FlowContext = flowContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -20,7 +20,7 @@ namespace Serein.Script
|
||||
{
|
||||
}
|
||||
|
||||
public IDynamicContext FlowContext{ get; }
|
||||
public IFlowContext FlowContext{ get; }
|
||||
|
||||
/// <summary>
|
||||
/// 定义的变量
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Serein.Workbench.Node.ViewModel
|
||||
try
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
var result = await NodeModel.ExecutingAsync(new Library.DynamicContext(nodeModel.Env), cts.Token);
|
||||
var result = await NodeModel.ExecutingAsync(new Library.FlowContext(nodeModel.Env), cts.Token);
|
||||
var data = result.Value;
|
||||
cts.Cancel();
|
||||
SereinEnv.WriteLine(InfoType.INFO, data?.ToString());
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Serein.Workbench.Node.ViewModel
|
||||
{
|
||||
Task.Factory.StartNew(async () =>
|
||||
{
|
||||
var context = new DynamicContext(NodeModel.Env);
|
||||
var context = new FlowContext(NodeModel.Env);
|
||||
var cts = new CancellationTokenSource();
|
||||
var result = await NodeModel.ExecutingAsync(context, cts.Token);
|
||||
cts?.Dispose();
|
||||
@@ -52,7 +52,7 @@ namespace Serein.Workbench.Node.ViewModel
|
||||
{
|
||||
Task.Factory.StartNew(async () =>
|
||||
{
|
||||
var context = new DynamicContext(NodeModel.Env);
|
||||
var context = new FlowContext(NodeModel.Env);
|
||||
var cts = new CancellationTokenSource();
|
||||
var result = await NodeModel.ExecutingAsync(context, cts.Token);
|
||||
cts?.Dispose();
|
||||
|
||||
Reference in New Issue
Block a user