整理了Serein.Library项目类文件,IDynamicContext、DynamicContext接口名称及实现类改为IFlowContext、FlowContext,使其与流程其它接口类命名风格统一。

This commit is contained in:
fengjiayi
2025-07-23 16:20:41 +08:00
parent 4e20e816ae
commit 9a8de6b571
39 changed files with 119 additions and 343 deletions

View File

@@ -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);
}
}

View File

@@ -9,7 +9,7 @@ namespace Serein.Library.Api
/// <summary>
/// 流程上下文,包含运行环境接口,可以通过注册环境事件或调用环境接口,实现在流程运行时更改流程行为。
/// </summary>
public interface IDynamicContext
public interface IFlowContext
{
/// <summary>
/// 标识流程

View File

@@ -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);
}
}

View File

@@ -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
{
}

View File

@@ -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];

View File

@@ -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>
/// 运行环境

View File

@@ -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;

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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\**" />

View File

@@ -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);
}

View File

@@ -9,8 +9,6 @@ using System.Threading.Tasks;
namespace Serein.Library.Utils
{
public class ChannelFlowTrigger<TSignal> : IFlowTrigger<TSignal>
{
// 使用并发字典管理每个枚举信号对应的 Channel

View File

@@ -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); // 广播给所有订阅者

View File

@@ -0,0 +1,21 @@
namespace Serein.Library.Utils
{
/// <summary>
/// 触发类型
/// </summary>
public enum TriggerDescription
{
/// <summary>
/// 外部触发
/// </summary>
External,
/// <summary>
/// 超时触发
/// </summary>
Overtime,
/// <summary>
/// 触发了,但类型不一致
/// </summary>
TypeInconsistency
}
}

View File

@@ -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
}
}

View File

@@ -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)

View File

@@ -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");
}
}

View File

@@ -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();

View File

@@ -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>
/// 获取全局数据

View File

@@ -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,
};
}
}
}
}