mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-03 00:00:49 +08:00
重写了节点主动中断功能,修改了运行环境持久化注册已有实例的逻辑。
This commit is contained in:
@@ -714,14 +714,7 @@ namespace Serein.Library.Api
|
|||||||
event EnvOutHandler OnEnvOut;
|
event EnvOutHandler OnEnvOut;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 流程接口
|
#region 基本接口
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置输出
|
|
||||||
/// </summary>
|
|
||||||
// <param name="output"></param>
|
|
||||||
// <param name="clearMsg"></param>
|
|
||||||
///void SetConsoleOut(); // Action<string> output, Action clearMsg
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 输出信息
|
/// 输出信息
|
||||||
@@ -730,21 +723,6 @@ namespace Serein.Library.Api
|
|||||||
/// <param name="type"></param>
|
/// <param name="type"></param>
|
||||||
void WriteLine(InfoType type, string message, InfoClass @class = InfoClass.Trivial);
|
void WriteLine(InfoType type, string message, InfoClass @class = InfoClass.Trivial);
|
||||||
|
|
||||||
///// <summary>
|
|
||||||
///// 使用JSON处理库输出对象信息
|
|
||||||
///// </summary>
|
|
||||||
///// <param name="obj"></param>
|
|
||||||
//void WriteLineObjToJson(object obj);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 启动远程服务
|
|
||||||
/// </summary>
|
|
||||||
Task StartRemoteServerAsync(int port = 7525);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 停止远程服务
|
|
||||||
/// </summary>
|
|
||||||
void StopRemoteServer();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 加载项目文件
|
/// 加载项目文件
|
||||||
@@ -764,47 +742,60 @@ namespace Serein.Library.Api
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<SereinProjectData> GetProjectInfoAsync();
|
Task<SereinProjectData> GetProjectInfoAsync();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从节点信息集合批量加载节点控件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nodeInfos">节点集合信息</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task LoadNodeInfosAsync(List<NodeInfo> nodeInfos);
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 远程相关
|
||||||
|
/// <summary>
|
||||||
|
/// 启动远程服务
|
||||||
|
/// </summary>
|
||||||
|
Task StartRemoteServerAsync(int port = 7525);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 停止远程服务
|
||||||
|
/// </summary>
|
||||||
|
void StopRemoteServer();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// (适用于远程连接后获取环境的运行状态)获取当前环境的信息
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<FlowEnvInfo> GetEnvInfoAsync();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 加载远程环境
|
/// 加载远程环境
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="addres">远程环境地址</param>
|
/// <param name="addres">远程环境地址</param>
|
||||||
/// <param name="port">远程环境端口</param>
|
/// <param name="port">远程环境端口</param>
|
||||||
/// <param name="token">密码</param>
|
/// <param name="token">密码</param>
|
||||||
Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres,int port, string token);
|
Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres, int port, string token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 退出远程环境
|
/// 退出远程环境
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void ExitRemoteEnv();
|
void ExitRemoteEnv();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 从文件中加载Dll
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dllPath"></param>
|
|
||||||
void LoadLibrary(string dllPath);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 移除DLL
|
/// (用于远程)通知节点属性变更
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="assemblyFullName">程序集的名称</param>
|
/// <param name="nodeGuid">节点Guid</param>
|
||||||
bool TryUnloadLibrary(string assemblyFullName);
|
/// <param name="path">属性路径</param>
|
||||||
|
/// <param name="value">属性值</param>
|
||||||
/// <summary>
|
|
||||||
/// 开始运行
|
|
||||||
/// </summary>
|
|
||||||
Task<bool> StartFlowAsync();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 从选定的节点开始运行
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="startNodeGuid"></param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<bool> StartAsyncInSelectNode(string startNodeGuid);
|
Task NotificationNodeValueChangeAsync(string nodeGuid, string path, object value);
|
||||||
|
|
||||||
/// <summary>
|
#endregion
|
||||||
/// 结束运行
|
|
||||||
/// </summary>
|
#region 流程节点操作接口
|
||||||
Task<bool> ExitFlowAsync();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 移动了某个节点(远程插件使用)
|
/// 移动了某个节点(远程插件使用)
|
||||||
@@ -851,12 +842,7 @@ namespace Serein.Library.Api
|
|||||||
ConnectionArgSourceType argSourceType,
|
ConnectionArgSourceType argSourceType,
|
||||||
int argIndex);
|
int argIndex);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 从节点信息集合批量加载节点控件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="List<NodeInfo>">节点集合信息</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task LoadNodeInfosAsync(List<NodeInfo> nodeInfos);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建节点
|
/// 创建节点
|
||||||
@@ -866,15 +852,6 @@ namespace Serein.Library.Api
|
|||||||
/// <param name="methodDetailsInfo">节点绑定的方法说明</param>
|
/// <param name="methodDetailsInfo">节点绑定的方法说明</param>
|
||||||
Task<NodeInfo> CreateNodeAsync(NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null);
|
Task<NodeInfo> CreateNodeAsync(NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null);
|
||||||
|
|
||||||
///// <summary>
|
|
||||||
///// 将节点放置在容器中/从容器中取出
|
|
||||||
///// </summary>
|
|
||||||
///// <param name="childNodeGuid">子节点(主要节点)</param>
|
|
||||||
///// <param name="parentNodeGuid">父节点</param>
|
|
||||||
///// <param name="isAssembly">是否组合(反之为分解节点组合关系)</param>
|
|
||||||
///// <returns></returns>
|
|
||||||
//Task<bool> ChangeNodeContainerChildAsync(string childNodeGuid,string parentNodeGuid,bool isAssembly);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将节点放置在容器中
|
/// 将节点放置在容器中
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -921,23 +898,21 @@ namespace Serein.Library.Api
|
|||||||
Task<bool> RemoveNodeAsync(string nodeGuid);
|
Task<bool> RemoveNodeAsync(string nodeGuid);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 激活未启动的全局触发器
|
/// 改变可选参数的数目
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="nodeGuid"></param>
|
/// <param name="nodeGuid">对应的节点Guid</param>
|
||||||
void ActivateFlipflopNode(string nodeGuid);
|
/// <param name="isAdd">true,增加参数;false,减少参数</param>
|
||||||
|
/// <param name="paramIndex">以哪个参数为模板进行拷贝,或删去某个参数(该参数必须为可选参数)</param>
|
||||||
/// <summary>
|
/// <returns></returns>
|
||||||
/// 终结一个全局触发器,在它触发后将不会再次监听消息(表现为已经启动的触发器至少会再次处理一次消息,后面版本再修正这个非预期行为)
|
Task<bool> ChangeParameter(string nodeGuid, bool isAdd, int paramIndex);
|
||||||
/// </summary>
|
|
||||||
/// <param name="nodeGuid"></param>
|
|
||||||
void TerminateFlipflopNode(string nodeGuid);
|
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region 节点中断、表达式
|
#region 节点中断、表达式
|
||||||
#if false
|
#if false
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置节点中断
|
/// 设置节点中断
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="nodeGuid">更改中断状态的节点Guid</param>
|
/// <param name="nodeGuid">更改中断状态的节点Guid</param>
|
||||||
@@ -978,24 +953,7 @@ namespace Serein.Library.Api
|
|||||||
#endif
|
#endif
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
#region 流程运行相关
|
||||||
/// (用于远程)通知节点属性变更
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="nodeGuid">节点Guid</param>
|
|
||||||
/// <param name="path">属性路径</param>
|
|
||||||
/// <param name="value">属性值</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task NotificationNodeValueChangeAsync(string nodeGuid, string path, object value);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 改变可选参数的数目
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="nodeGuid">对应的节点Guid</param>
|
|
||||||
/// <param name="isAdd">true,增加参数;false,减少参数</param>
|
|
||||||
/// <param name="paramIndex">以哪个参数为模板进行拷贝,或删去某个参数(该参数必须为可选参数)</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<bool> ChangeParameter(string nodeGuid, bool isAdd, int paramIndex);
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取方法描述信息
|
/// 获取方法描述信息
|
||||||
@@ -1016,17 +974,34 @@ namespace Serein.Library.Api
|
|||||||
bool TryGetDelegateDetails(string assemblyName, string methodName, out DelegateDetails del);
|
bool TryGetDelegateDetails(string assemblyName, string methodName, out DelegateDetails del);
|
||||||
|
|
||||||
|
|
||||||
#region 远程相关
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// (适用于远程连接后获取环境的运行状态)获取当前环境的信息
|
/// 开始运行
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
Task<bool> StartFlowAsync();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从选定的节点开始运行
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="startNodeGuid"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<FlowEnvInfo> GetEnvInfoAsync();
|
Task<bool> StartAsyncInSelectNode(string startNodeGuid);
|
||||||
#endregion
|
|
||||||
|
|
||||||
#endregion
|
/// <summary>
|
||||||
|
/// 结束运行
|
||||||
|
/// </summary>
|
||||||
|
Task<bool> ExitFlowAsync();
|
||||||
|
|
||||||
#region 启动器调用
|
/// <summary>
|
||||||
|
/// 激活未启动的全局触发器
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nodeGuid"></param>
|
||||||
|
void ActivateFlipflopNode(string nodeGuid);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 终结一个全局触发器,在它触发后将不会再次监听消息(表现为已经启动的触发器至少会再次处理一次消息,后面版本再修正这个非预期行为)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nodeGuid"></param>
|
||||||
|
void TerminateFlipflopNode(string nodeGuid);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 流程启动器调用,监视数据更新通知
|
/// 流程启动器调用,监视数据更新通知
|
||||||
@@ -1054,31 +1029,19 @@ namespace Serein.Library.Api
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 流程运行时
|
#region 类库依赖相关
|
||||||
|
|
||||||
#region 全局数据/方法信息
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 添加或更新全局数据
|
/// 从文件中加载Dll
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="keyName">数据名称</param>
|
/// <param name="dllPath"></param>
|
||||||
/// <param name="data">数据集</param>
|
void LoadLibrary(string dllPath);
|
||||||
/// <returns></returns>
|
|
||||||
object AddOrUpdateGlobalData(string keyName, object data);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取全局数据
|
/// 移除DLL
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="keyName">数据名称</param>
|
/// <param name="assemblyFullName">程序集的名称</param>
|
||||||
/// <returns></returns>
|
bool TryUnloadLibrary(string assemblyFullName);
|
||||||
object GetGlobalData(string keyName);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region 加载依赖
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 运行时加载
|
/// 运行时加载
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1093,7 +1056,6 @@ namespace Serein.Library.Api
|
|||||||
/// <param name="isRecurrence">是否递归加载</param>
|
/// <param name="isRecurrence">是否递归加载</param>
|
||||||
void LoadAllNativeLibraryOfRuning(string path, bool isRecurrence = true);
|
void LoadAllNativeLibraryOfRuning(string path, bool isRecurrence = true);
|
||||||
|
|
||||||
#endregion
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region UI视觉
|
#region UI视觉
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace Serein.Library.Api
|
|||||||
public interface IScriptFlowApi
|
public interface IScriptFlowApi
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当前流程
|
/// 当前流程运行环境
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IFlowEnvironment Env { get; }
|
IFlowEnvironment Env { get; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -20,34 +20,28 @@ namespace Serein.Library.Api
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
NodeModelBase NodeModel { get; }
|
NodeModelBase NodeModel { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 动态流程上下文
|
|
||||||
/// </summary>
|
|
||||||
IDynamicContext Context { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 根据索引从入参数据获取数据
|
/// 根据索引从入参数据获取数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
/// <param name="index"></param>
|
/// <param name="index"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
object GetArgData(int index);
|
object GetArgData(IDynamicContext context, int index);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 根据入参名称从入参数据获取数据
|
/// 获取流程当前传递的数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name"></param>
|
/// <param name="context"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
// object GetDataOfParams(string name);
|
object GetFlowData(IDynamicContext context);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取全局数据
|
/// 获取全局数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="keyName"></param>
|
/// <param name="keyName"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
object GetGlobalData(string keyName);
|
object GetGlobalData(string keyName);
|
||||||
/// <summary>
|
|
||||||
/// 获取流程当前传递的数据
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
object GetFlowData();
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 立即调用某个节点并获取其返回值
|
/// 立即调用某个节点并获取其返回值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -35,6 +35,22 @@ namespace Serein.Library.Api
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
ISereinIOC Register<TService, TImplementation>(params object[] parameters) where TImplementation : TService;
|
ISereinIOC Register<TService, TImplementation>(params object[] parameters) where TImplementation : TService;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 指定一个Key登记一个持久化的实例。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">登记使用的名称</param>
|
||||||
|
/// <param name="instance">实例对象</param>
|
||||||
|
/// <returns>是否注册成功</returns>
|
||||||
|
bool RegisterPersistennceInstance(string key, object instance);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 指定一个Key登记一个实例。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">登记使用的名称</param>
|
||||||
|
/// <param name="instance">实例对象</param>
|
||||||
|
/// <returns>是否注册成功</returns>
|
||||||
|
bool RegisterInstance(string key, object instance);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取类型的实例。如果需要获取的类型以“接口-实现类”的方式注册,请使用接口的类型。
|
/// 获取类型的实例。如果需要获取的类型以“接口-实现类”的方式注册,请使用接口的类型。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -53,14 +69,7 @@ namespace Serein.Library.Api
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
T Get<T>(string key);
|
T Get<T>(string key);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 指定一个Key登记一个实例。如果实例中需要注入的依赖项,需要将needInjectProperty设置为true。
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="key">注入名称</param>
|
|
||||||
/// <param name="instance">实例对象</param>
|
|
||||||
/// <param name="needInjectProperty">是否需要注入依赖项</param>
|
|
||||||
/// <returns>是否注册成功</returns>
|
|
||||||
bool CustomRegisterInstance(string key, object instance, bool needInjectProperty = true);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>创建实例并注入依赖项,不会注册到IOC容器中。</para>
|
/// <para>创建实例并注入依赖项,不会注册到IOC容器中。</para>
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using System;
|
using Newtonsoft.Json.Linq;
|
||||||
|
using Serein.Library.Utils;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -33,52 +35,67 @@ namespace Serein.Library
|
|||||||
private bool _isEnable = true;
|
private bool _isEnable = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 中断级别,暂时停止继续执行后继分支。
|
/// 是否中断节点。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
//[PropertyInfo]
|
[PropertyInfo(IsNotification = true, CustomCodeAtEnd = "ChangeInterruptState(value);")] // CustomCode = "NodeModel?.Env?.SetNodeInterruptAsync(NodeModel?.Guid, value);"
|
||||||
//private InterruptClass _interruptClass = InterruptClass.None;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 中断级别,暂时停止继续执行后继分支。
|
|
||||||
/// </summary>
|
|
||||||
[PropertyInfo(IsNotification = true, CustomCodeAtEnd = "// NodeModel?.Env?.SetNodeInterruptAsync(NodeModel?.Guid, value);")] // CustomCode = "NodeModel?.Env?.SetNodeInterruptAsync(NodeModel?.Guid, value);"
|
|
||||||
private bool _isInterrupt = false;
|
private bool _isInterrupt = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 节点中断
|
||||||
|
/// </summary>
|
||||||
|
public partial class NodeDebugSetting
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 取消中断的回调函数
|
/// 取消中断的回调函数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PropertyInfo]
|
private Action _cancelInterrupt { get; set; }
|
||||||
private Action _cancelInterruptCallback;
|
/// <summary>
|
||||||
|
/// 取消中断
|
||||||
|
/// </summary>
|
||||||
|
public Action CancelInterrupt => _cancelInterrupt;
|
||||||
|
/// <summary>
|
||||||
|
/// 中断节点
|
||||||
|
/// </summary>
|
||||||
|
public Func<Task> _getInterruptTask;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 中断Task(用来中断)
|
/// 获取中断的Task
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PropertyInfo]
|
public Func<Task> GetInterruptTask => _getInterruptTask;
|
||||||
private Func<Task> _getInterruptTask;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 中断级别,暂时停止继续执行后继分支。
|
/// 改变中断状态
|
||||||
/// </summary>
|
/// </summary>
|
||||||
//public enum InterruptClass
|
public void ChangeInterruptState(bool state)
|
||||||
//{
|
{
|
||||||
// /// <summary>
|
if (state && _getInterruptTask is null)
|
||||||
// /// 不中断
|
{
|
||||||
// /// </summary>
|
// 设置获取中断的委托
|
||||||
// None,
|
_getInterruptTask = () => NodeModel.Env.IOC.Get<FlowInterruptTool>().WaitTriggerAsync(NodeModel.Guid);
|
||||||
// /// <summary>
|
}
|
||||||
// /// 分支中断,中断进入当前节点的分支。
|
else if (!state)
|
||||||
// /// </summary>
|
{
|
||||||
// Branch,
|
if (_getInterruptTask is null)
|
||||||
// /// <summary>
|
{
|
||||||
// /// 全局中断,中断全局所有节点的运行。(暂未实现相关)
|
|
||||||
// /// </summary>
|
}
|
||||||
// Global,
|
else
|
||||||
//}
|
{
|
||||||
|
// 设置解除中断的委托
|
||||||
|
_cancelInterrupt = () => NodeModel.Env.IOC.Get<FlowInterruptTool>().InvokeTrigger(NodeModel.Guid);
|
||||||
|
_cancelInterrupt.Invoke();
|
||||||
|
_getInterruptTask = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ namespace Serein.Library
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 保存自定义信息
|
/// 保存自定义信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -60,21 +59,11 @@ namespace Serein.Library
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void Remove()
|
public virtual void Remove()
|
||||||
{
|
{
|
||||||
|
if (this.DebugSetting.CancelInterrupt != null)
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 移除该节点
|
|
||||||
/// </summary>
|
|
||||||
public virtual void RemoveFromEnv()
|
|
||||||
{
|
{
|
||||||
if (this.DebugSetting.CancelInterruptCallback != null)
|
this.DebugSetting.CancelInterrupt?.Invoke();
|
||||||
{
|
|
||||||
this.DebugSetting.CancelInterruptCallback?.Invoke();
|
|
||||||
}
|
}
|
||||||
this.DebugSetting.GetInterruptTask = null;
|
|
||||||
this.DebugSetting.NodeModel = null;
|
this.DebugSetting.NodeModel = null;
|
||||||
this.DebugSetting.CancelInterruptCallback = null;
|
|
||||||
this.DebugSetting = null;
|
this.DebugSetting = null;
|
||||||
foreach (var pd in this.MethodDetails.ParameterDetailss)
|
foreach (var pd in this.MethodDetails.ParameterDetailss)
|
||||||
{
|
{
|
||||||
@@ -131,7 +120,6 @@ namespace Serein.Library
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 导出为节点信息
|
/// 导出为节点信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -231,10 +219,6 @@ namespace Serein.Library
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 程序集更新,更新节点方法描述、以及所有入参描述的类型
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 调试中断
|
#region 调试中断
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -243,15 +227,13 @@ namespace Serein.Library
|
|||||||
public void CancelInterrupt()
|
public void CancelInterrupt()
|
||||||
{
|
{
|
||||||
this.DebugSetting.IsInterrupt = false;
|
this.DebugSetting.IsInterrupt = false;
|
||||||
DebugSetting.CancelInterruptCallback?.Invoke();
|
DebugSetting.CancelInterrupt?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 节点方法的执行
|
#region 节点方法的执行
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否应该退出执行
|
/// 是否应该退出执行
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -271,6 +253,7 @@ namespace Serein.Library
|
|||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果存在全局触发器,且触发器的执行任务已经被取消时,退出执行。
|
// 如果存在全局触发器,且触发器的执行任务已经被取消时,退出执行。
|
||||||
if (flowCts != null)
|
if (flowCts != null)
|
||||||
{
|
{
|
||||||
@@ -365,15 +348,21 @@ namespace Serein.Library
|
|||||||
/// <returns>节点传回数据对象</returns>
|
/// <returns>节点传回数据对象</returns>
|
||||||
public virtual async Task<object> ExecutingAsync(IDynamicContext context)
|
public virtual async Task<object> ExecutingAsync(IDynamicContext context)
|
||||||
{
|
{
|
||||||
//if(context.NextOrientation == ConnectionInvokeType.IsError)
|
|
||||||
//{
|
|
||||||
//}
|
|
||||||
#region 调试中断
|
|
||||||
|
|
||||||
if (DebugSetting.IsInterrupt) // 执行触发检查是否需要中断
|
#region 调试中断
|
||||||
|
if(context.NextOrientation == ConnectionInvokeType.IsError)
|
||||||
{
|
{
|
||||||
//var cancelType = await this.DebugSetting.GetInterruptTask(); // 等待中断结束
|
}
|
||||||
await Console.Out.WriteLineAsync($"[{this.MethodDetails?.MethodName}]中断已取消,开始执行后继分支");
|
|
||||||
|
// 执行触发检查是否需要中断
|
||||||
|
if (DebugSetting.IsInterrupt)
|
||||||
|
{
|
||||||
|
context.Env.TriggerInterrupt(Guid, "", InterruptTriggerEventArgs.InterruptTriggerType.Monitor); // 通知运行环境该节点中断了
|
||||||
|
await DebugSetting.GetInterruptTask.Invoke();
|
||||||
|
//await fit.WaitTriggerAsync(Guid); // 创建一个等待的中断任务
|
||||||
|
SereinEnv.WriteLine(InfoType.INFO, $"[{this.MethodDetails?.MethodName}]中断已取消,开始执行后继分支");
|
||||||
|
var flowCts = context.Env.IOC.Get<CancellationTokenSource>(NodeStaticConfig.FlipFlopCtsName);
|
||||||
|
if (IsBradk(context, flowCts)) return null; // 流程已终止,取消后续的执行
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -405,9 +394,10 @@ namespace Serein.Library
|
|||||||
{
|
{
|
||||||
if (MethodDetails.ParameterDetailss.Length == 0)
|
if (MethodDetails.ParameterDetailss.Length == 0)
|
||||||
{
|
{
|
||||||
return new object[0];// md.ActingInstance
|
return new object[0]; // 无参数
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region 定义返回的参数数组
|
||||||
object[] args;
|
object[] args;
|
||||||
Array paramsArgs = null; // 初始化可选参数
|
Array paramsArgs = null; // 初始化可选参数
|
||||||
int paramsArgIndex = 0; // 可选参数下标,与 object[] paramsArgs 一起使用
|
int paramsArgIndex = 0; // 可选参数下标,与 object[] paramsArgs 一起使用
|
||||||
@@ -424,12 +414,15 @@ namespace Serein.Library
|
|||||||
// 不存在可选参数
|
// 不存在可选参数
|
||||||
args = new object[MethodDetails.ParameterDetailss.Length]; // 调用方法的入参数组
|
args = new object[MethodDetails.ParameterDetailss.Length]; // 调用方法的入参数组
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
// 常规参数的获取
|
||||||
for (int i = 0; i < args.Length; i++) {
|
for (int i = 0; i < args.Length; i++) {
|
||||||
var pd = MethodDetails.ParameterDetailss[i];
|
var pd = MethodDetails.ParameterDetailss[i];
|
||||||
args[i] = await pd.ToMethodArgData(context); // 获取数据
|
args[i] = await pd.ToMethodArgData(context); // 获取数据
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 可选参数的获取
|
||||||
if(MethodDetails.ParamsArgIndex >= 0)
|
if(MethodDetails.ParamsArgIndex >= 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < paramsArgs.Length; i++)
|
for (int i = 0; i < paramsArgs.Length; i++)
|
||||||
@@ -441,10 +434,12 @@ namespace Serein.Library
|
|||||||
args[args.Length - 1] = paramsArgs;
|
args[args.Length - 1] = paramsArgs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 更新节点数据,并检查监视表达式是否生效
|
/// 更新节点数据,并检查监视表达式是否生效
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -518,26 +513,6 @@ namespace Serein.Library
|
|||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
///// <summary>
|
|
||||||
///// 释放对象
|
|
||||||
///// </summary>
|
|
||||||
//public void ReleaseFlowData()
|
|
||||||
//{
|
|
||||||
// if (typeof(IDisposable).IsAssignableFrom(FlowData?.GetType()) && FlowData is IDisposable disposable)
|
|
||||||
// {
|
|
||||||
// disposable?.Dispose();
|
|
||||||
// }
|
|
||||||
// this.FlowData = null;
|
|
||||||
//}
|
|
||||||
|
|
||||||
///// <summary>
|
|
||||||
///// 获取节点数据
|
|
||||||
///// </summary>
|
|
||||||
///// <returns></returns>
|
|
||||||
//public object GetFlowData()
|
|
||||||
//{
|
|
||||||
// return this.FlowData;
|
|
||||||
//}
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
85
Library/Utils/FlowInterruptTool.cs
Normal file
85
Library/Utils/FlowInterruptTool.cs
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reactive.Subjects;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Serein.Library.Utils
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 流程运行中断工具
|
||||||
|
/// </summary>
|
||||||
|
public class FlowInterruptTool
|
||||||
|
{
|
||||||
|
// 使用并发字典管理每个信号对应的广播列表
|
||||||
|
private readonly ConcurrentDictionary<string, Subject<bool>> _subscribers = new ConcurrentDictionary<string, Subject<bool>>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或创建指定信号的 Subject(消息广播者)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="signal">枚举信号标识符</param>
|
||||||
|
/// <returns>对应的 Subject</returns>
|
||||||
|
private Subject<bool> GetOrCreateSubject(string signal)
|
||||||
|
{
|
||||||
|
return _subscribers.GetOrAdd(signal, _ => new Subject<bool>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 订阅指定信号的消息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="signal">枚举信号标识符</param>
|
||||||
|
/// <param name="action">订阅者</param>
|
||||||
|
/// <returns>取消订阅的句柄</returns>
|
||||||
|
private IDisposable Subscribe(string signal, Action<bool> action)
|
||||||
|
{
|
||||||
|
IObserver<bool> observer = new Observer<bool>(action);
|
||||||
|
var subject = GetOrCreateSubject(signal);
|
||||||
|
return subject.Subscribe(observer); // 返回取消订阅的句柄
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 等待触发
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="signal"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<bool> WaitTriggerAsync(string signal)
|
||||||
|
{
|
||||||
|
var taskCompletionSource = new TaskCompletionSource<bool>();
|
||||||
|
var subscription = Subscribe(signal, taskCompletionSource.SetResult);
|
||||||
|
var result = await taskCompletionSource.Task;
|
||||||
|
subscription.Dispose(); // 取消订阅
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 手动触发信号,并广播给所有订阅者
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="signal">枚举信号标识符</param>
|
||||||
|
/// <returns>是否成功触发</returns>
|
||||||
|
public bool InvokeTrigger(string signal)
|
||||||
|
{
|
||||||
|
if (_subscribers.TryGetValue(signal, out var subject))
|
||||||
|
{
|
||||||
|
subject.OnNext(true); // 广播给所有订阅者
|
||||||
|
subject.OnCompleted(); // 通知订阅结束
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 取消所有任务
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
public void CancelAllTrigger()
|
||||||
|
{
|
||||||
|
foreach (var subject in _subscribers.Values)
|
||||||
|
{
|
||||||
|
subject.OnCompleted(); // 通知所有订阅者结束
|
||||||
|
}
|
||||||
|
_subscribers.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,147 +14,7 @@ namespace Serein.Library.Utils
|
|||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 信号触发器类,带有消息广播功能。
|
|
||||||
/// 使用枚举作为标记,创建
|
|
||||||
/// </summary>
|
|
||||||
public class ValueTaskFlowTrigger<TSignal>
|
|
||||||
{
|
|
||||||
// 使用并发字典管理每个信号对应的广播列表
|
|
||||||
private readonly ConcurrentDictionary<TSignal, Subject<TriggerResult<object>>> _subscribers = new ConcurrentDictionary<TSignal, Subject<TriggerResult<object>>>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取或创建指定信号的 Subject(消息广播者)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="signal">枚举信号标识符</param>
|
|
||||||
/// <returns>对应的 Subject</returns>
|
|
||||||
private Subject<TriggerResult<object>> GetOrCreateSubject(TSignal signal)
|
|
||||||
{
|
|
||||||
return _subscribers.GetOrAdd(signal, _ => new Subject<TriggerResult<object>>());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 订阅指定信号的消息
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="signal">枚举信号标识符</param>
|
|
||||||
/// <param name="observer">订阅者</param>
|
|
||||||
/// <returns>取消订阅的句柄</returns>
|
|
||||||
private IDisposable Subscribe<TResult>(TSignal signal, Action<TriggerResult<object>> action)
|
|
||||||
{
|
|
||||||
IObserver<TriggerResult<object>> observer = new Observer<TriggerResult<object>>(action);
|
|
||||||
var subject = GetOrCreateSubject(signal);
|
|
||||||
return subject.Subscribe(observer); // 返回取消订阅的句柄
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 等待触发器并指定超时的时间
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TResult">返回值类型</typeparam>
|
|
||||||
/// <param name="signal">等待信号</param>
|
|
||||||
/// <param name="outTime">超时时间</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async ValueTask<TriggerResult<TResult>> WaitTriggerWithTimeoutAsync<TResult>(TSignal signal, TimeSpan outTime)
|
|
||||||
{
|
|
||||||
var subject = GetOrCreateSubject(signal);
|
|
||||||
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
|
|
||||||
};
|
|
||||||
subject.OnNext(outResult); // 广播给所有订阅者
|
|
||||||
subject.OnCompleted(); // 通知订阅结束
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (OperationCanceledException)
|
|
||||||
{
|
|
||||||
// 超时任务被取消
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
cts?.Dispose(); // 确保 cts 被释放
|
|
||||||
}
|
|
||||||
}, cts.Token);
|
|
||||||
var result = await WaitTriggerAsync<TResult>(signal); // 返回一个可以超时触发的等待任务
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 等待触发
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TResult"></typeparam>
|
|
||||||
/// <param name="signal"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async ValueTask<TriggerResult<TResult>> WaitTriggerAsync<TResult>(TSignal signal)
|
|
||||||
{
|
|
||||||
|
|
||||||
var taskCompletionSource = new TaskCompletionSource<TriggerResult<object>>();
|
|
||||||
var subscription = Subscribe<TResult>(signal, taskCompletionSource.SetResult);
|
|
||||||
var result = await taskCompletionSource.Task;
|
|
||||||
subscription.Dispose(); // 取消订阅
|
|
||||||
if (result.Value is TResult data)
|
|
||||||
{
|
|
||||||
return new TriggerResult<TResult>()
|
|
||||||
{
|
|
||||||
Value = data,
|
|
||||||
Type = TriggerDescription.External,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new TriggerResult<TResult>()
|
|
||||||
{
|
|
||||||
Type = TriggerDescription.TypeInconsistency,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 手动触发信号,并广播给所有订阅者
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TResult">触发类型</typeparam>
|
|
||||||
/// <param name="signal">枚举信号标识符</param>
|
|
||||||
/// <param name="value">传递的数据</param>
|
|
||||||
/// <returns>是否成功触发</returns>
|
|
||||||
public Task<bool> InvokeTriggerAsync<TResult>(TSignal signal, TResult value)
|
|
||||||
{
|
|
||||||
if (_subscribers.TryGetValue(signal, out var subject))
|
|
||||||
{
|
|
||||||
var result = new TriggerResult<object>()
|
|
||||||
{
|
|
||||||
Type = TriggerDescription.External,
|
|
||||||
Value = value
|
|
||||||
};
|
|
||||||
subject.OnNext(result); // 广播给所有订阅者
|
|
||||||
subject.OnCompleted(); // 通知订阅结束
|
|
||||||
return Task.FromResult(true);
|
|
||||||
}
|
|
||||||
return Task.FromResult(false);
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// 取消所有任务
|
|
||||||
/// </summary>
|
|
||||||
|
|
||||||
public void CancelAllTrigger()
|
|
||||||
{
|
|
||||||
foreach (var subject in _subscribers.Values)
|
|
||||||
{
|
|
||||||
subject.OnCompleted(); // 通知所有订阅者结束
|
|
||||||
}
|
|
||||||
_subscribers.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace Serein.Library.Utils
|
|||||||
{
|
{
|
||||||
// 使用并发字典管理每个信号对应的广播列表
|
// 使用并发字典管理每个信号对应的广播列表
|
||||||
private readonly ConcurrentDictionary<TSignal, Subject<TriggerResult<object>>> _subscribers = new ConcurrentDictionary<TSignal, Subject<TriggerResult<object>>>();
|
private readonly ConcurrentDictionary<TSignal, Subject<TriggerResult<object>>> _subscribers = new ConcurrentDictionary<TSignal, Subject<TriggerResult<object>>>();
|
||||||
private readonly TriggerResultPool _triggerResultPool = new TriggerResultPool();
|
private readonly TriggerResultPool<object> _triggerResultPool = new TriggerResultPool<object>();
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取或创建指定信号的 Subject(消息广播者)
|
/// 获取或创建指定信号的 Subject(消息广播者)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -76,18 +76,18 @@ namespace Serein.Library.Utils
|
|||||||
/// 使用 ObjectPool 来复用 TriggerResult 对象
|
/// 使用 ObjectPool 来复用 TriggerResult 对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
// 示例 TriggerResult 对象池
|
// 示例 TriggerResult 对象池
|
||||||
public class TriggerResultPool
|
public class TriggerResultPool<TResult>
|
||||||
{
|
{
|
||||||
private readonly ConcurrentExpandingObjectPool<TriggerResult<object>> _objectPool;
|
private readonly ConcurrentExpandingObjectPool<TriggerResult<TResult>> _objectPool;
|
||||||
|
|
||||||
public TriggerResultPool(int defaultCapacity = 30)
|
public TriggerResultPool(int defaultCapacity = 30)
|
||||||
{
|
{
|
||||||
_objectPool = new ConcurrentExpandingObjectPool<TriggerResult<object>>(defaultCapacity);
|
_objectPool = new ConcurrentExpandingObjectPool<TriggerResult<TResult>>(defaultCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TriggerResult<object> Get() => _objectPool.Get();
|
public TriggerResult<TResult> Get() => _objectPool.Get();
|
||||||
|
|
||||||
public void Return(TriggerResult<object> result) => _objectPool.Return(result);
|
public void Return(TriggerResult<TResult> result) => _objectPool.Return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -107,12 +107,20 @@ namespace Serein.Library.Utils
|
|||||||
#region 通过名称记录或获取一个实例
|
#region 通过名称记录或获取一个实例
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 指定key值注册一个已经实例化的实例对象
|
/// 指定key值注册一个已经实例化的实例对象,并持久化储存
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key"></param>
|
/// <param name="key"></param>
|
||||||
/// <param name="instance"></param>
|
/// <param name="instance"></param>
|
||||||
/// <param name="needInjectProperty"></param>
|
public bool RegisterInstance(string key, object instance)
|
||||||
public bool CustomRegisterInstance(string key, object instance, bool needInjectProperty = true)
|
{
|
||||||
|
return RegisterPersistennceInstance(key, instance);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 指定key值注册一个已经实例化的实例对象,并持久化储存
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <param name="instance"></param>
|
||||||
|
public bool RegisterPersistennceInstance(string key, object instance)
|
||||||
{
|
{
|
||||||
// 不存在时才允许创建
|
// 不存在时才允许创建
|
||||||
if (_dependencies.ContainsKey(key))
|
if (_dependencies.ContainsKey(key))
|
||||||
@@ -120,11 +128,11 @@ namespace Serein.Library.Utils
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_dependencies.TryAdd(key, instance);
|
_dependencies.TryAdd(key, instance);
|
||||||
if (needInjectProperty)
|
//if (needInjectProperty)
|
||||||
{
|
//{
|
||||||
InjectDependencies(instance); // 注入实例需要的依赖项
|
// InjectDependencies(instance); // 注入实例需要的依赖项
|
||||||
}
|
//}
|
||||||
InjectUnfinishedDependencies(key, instance); // 检查是否存在其它实例需要该类型
|
//InjectUnfinishedDependencies(key, instance); // 检查是否存在其它实例需要该类型
|
||||||
OnIOCMembersChanged?.Invoke(new IOCMembersChangedEventArgs(key, instance));
|
OnIOCMembersChanged?.Invoke(new IOCMembersChangedEventArgs(key, instance));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using Net462DllTest.LogicControl;
|
using Net462DllTest.LogicControl;
|
||||||
using Serein.Library;
|
using Serein.Library;
|
||||||
using Serein.Library.Utils.FlowTrigger;
|
using Serein.Library.Utils;
|
||||||
|
|
||||||
namespace Net462DllTest.Trigger
|
namespace Net462DllTest.Trigger
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ using Net462DllTest.Signal;
|
|||||||
using Net462DllTest.Utils;
|
using Net462DllTest.Utils;
|
||||||
using Serein.Library;
|
using Serein.Library;
|
||||||
using Serein.Library.Utils;
|
using Serein.Library.Utils;
|
||||||
using Serein.Library.Utils.FlowTrigger;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ using System.Threading;
|
|||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
using Serein.Library.Utils;
|
using Serein.Library.Utils;
|
||||||
using Serein.Library.Utils.FlowTrigger;
|
|
||||||
|
|
||||||
namespace Net462DllTest.Trigger
|
namespace Net462DllTest.Trigger
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -69,6 +69,16 @@ namespace Serein.NodeFlow.Env
|
|||||||
NodeMVVMManagement.RegisterModel(NodeControlType.GlobalData, typeof(SingleGlobalDataNode)); // 全局数据节点
|
NodeMVVMManagement.RegisterModel(NodeControlType.GlobalData, typeof(SingleGlobalDataNode)); // 全局数据节点
|
||||||
NodeMVVMManagement.RegisterModel(NodeControlType.Script, typeof(SingleScriptNode)); // 脚本节点
|
NodeMVVMManagement.RegisterModel(NodeControlType.Script, typeof(SingleScriptNode)); // 脚本节点
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region 注册基本服务类
|
||||||
|
PersistennceInstance.Add(typeof(FlowInterruptTool).FullName, new FlowInterruptTool()); // 缓存流程实例
|
||||||
|
PersistennceInstance.Add(typeof(IFlowEnvironment).FullName, (FlowEnvironment)this); // 缓存流程实例
|
||||||
|
PersistennceInstance.Add(typeof(ISereinIOC).FullName, this); // 缓存容器服务
|
||||||
|
PersistennceInstance.Add(typeof(UIContextOperation).FullName, uiContextOperation); // 缓存封装好的UI线程上下文
|
||||||
|
|
||||||
|
ReRegisterPersistennceInstance();
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
#region 远程管理
|
#region 远程管理
|
||||||
@@ -303,6 +313,11 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly SereinIOC sereinIOC;
|
private readonly SereinIOC sereinIOC;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 本地运行环境缓存的持久化实例
|
||||||
|
/// </summary>
|
||||||
|
private Dictionary<string, object> PersistennceInstance { get; } = new Dictionary<string, object>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 环境加载的节点集合
|
/// 环境加载的节点集合
|
||||||
/// Node Guid - Node Model
|
/// Node Guid - Node Model
|
||||||
@@ -376,34 +391,23 @@ namespace Serein.NodeFlow.Env
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<bool> StartFlowAsync()
|
public async Task<bool> StartFlowAsync()
|
||||||
{
|
{
|
||||||
flowStarter = new FlowStarter();
|
flowStarter ??= new FlowStarter();
|
||||||
var nodes = NodeModels.Values.ToList();
|
var nodes = NodeModels.Values.ToList();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<MethodDetails> initMethods = this.FlowLibraryManagement.GetMdsOnFlowStart(NodeType.Init);
|
List<MethodDetails> initMethods = this.FlowLibraryManagement.GetMdsOnFlowStart(NodeType.Init);
|
||||||
List<MethodDetails> loadMethods = this.FlowLibraryManagement.GetMdsOnFlowStart(NodeType.Loading);
|
List<MethodDetails> loadMethods = this.FlowLibraryManagement.GetMdsOnFlowStart(NodeType.Loading);
|
||||||
List<MethodDetails> exitMethods = this.FlowLibraryManagement.GetMdsOnFlowStart(NodeType.Exit);
|
List<MethodDetails> exitMethods = this.FlowLibraryManagement.GetMdsOnFlowStart(NodeType.Exit);
|
||||||
Dictionary<RegisterSequence, List<Type>> autoRegisterTypes = this.FlowLibraryManagement.GetaAutoRegisterType();
|
Dictionary<RegisterSequence, List<Type>> autoRegisterTypes = this.FlowLibraryManagement.GetaAutoRegisterType();
|
||||||
|
|
||||||
|
IOC.Reset();
|
||||||
IOC.Reset(); // 开始运行时清空ioc中注册的实例
|
|
||||||
|
|
||||||
IOC.Register<IScriptFlowApi, ScriptFlowApi>(); // 注册脚本接口
|
|
||||||
IOC.CustomRegisterInstance(typeof(IFlowEnvironment).FullName, this); // 注册流程实例
|
|
||||||
if (this.UIContextOperation is not null)
|
|
||||||
{
|
|
||||||
// 注册封装好的UI线程上下文
|
|
||||||
IOC.CustomRegisterInstance(typeof(UIContextOperation).FullName, this.UIContextOperation, false);
|
|
||||||
}
|
|
||||||
_ = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await flowStarter.RunAsync(this, nodes, autoRegisterTypes, initMethods, loadMethods, exitMethods);
|
await flowStarter.RunAsync(this, nodes, autoRegisterTypes, initMethods, loadMethods, exitMethods);
|
||||||
if (FlipFlopState == RunState.Completion)
|
//_ = Task.Run(async () =>
|
||||||
{
|
//{
|
||||||
await ExitFlowAsync(); // 未运行触发器时,才会调用结束方法
|
// //if (FlipFlopState == RunState.Completion)
|
||||||
}
|
// //{
|
||||||
});
|
// // await ExitFlowAsync(); // 未运行触发器时,才会调用结束方法
|
||||||
|
// //}
|
||||||
|
//});
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|
||||||
@@ -466,6 +470,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
{
|
{
|
||||||
flowStarter?.Exit();
|
flowStarter?.Exit();
|
||||||
UIContextOperation?.Invoke(() => OnFlowRunComplete?.Invoke(new FlowEventArgs()));
|
UIContextOperation?.Invoke(() => OnFlowRunComplete?.Invoke(new FlowEventArgs()));
|
||||||
|
IOC.Reset();
|
||||||
flowStarter = null;
|
flowStarter = null;
|
||||||
GC.Collect();
|
GC.Collect();
|
||||||
return Task.FromResult(true);
|
return Task.FromResult(true);
|
||||||
@@ -829,7 +834,10 @@ namespace Serein.NodeFlow.Env
|
|||||||
foreach (var toNodeGuid in item.toNodeGuids)
|
foreach (var toNodeGuid in item.toNodeGuids)
|
||||||
{
|
{
|
||||||
var toNodeModel = GuidToModel(toNodeGuid);
|
var toNodeModel = GuidToModel(toNodeGuid);
|
||||||
if (toNodeModel is null) continue;
|
if (toNodeModel is null) {
|
||||||
|
// 防御性代码,加载正常保存的项目文件不会进入这里
|
||||||
|
continue;
|
||||||
|
};
|
||||||
var isSuccessful = ConnectInvokeOfNode(fromNodeModel, toNodeModel, item.connectionType); // 加载时确定节点间的连接关系
|
var isSuccessful = ConnectInvokeOfNode(fromNodeModel, toNodeModel, item.connectionType); // 加载时确定节点间的连接关系
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1396,29 +1404,6 @@ namespace Serein.NodeFlow.Env
|
|||||||
#region 流程依赖类库的接口
|
#region 流程依赖类库的接口
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 添加或更新全局数据
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="keyName">数据名称</param>
|
|
||||||
/// <param name="data">数据集</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public object AddOrUpdateGlobalData(string keyName, object data)
|
|
||||||
{
|
|
||||||
SereinEnv.AddOrUpdateFlowGlobalData(keyName, data);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取全局数据
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="keyName">数据名称</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public object? GetGlobalData(string keyName)
|
|
||||||
{
|
|
||||||
return SereinEnv.GetFlowGlobalData(keyName);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 运行时加载
|
/// 运行时加载
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1796,6 +1781,20 @@ namespace Serein.NodeFlow.Env
|
|||||||
|
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 向容器登记缓存的持久化实例
|
||||||
|
/// </summary>
|
||||||
|
private void ReRegisterPersistennceInstance()
|
||||||
|
{
|
||||||
|
lock (PersistennceInstance)
|
||||||
|
{
|
||||||
|
foreach (var kvp in PersistennceInstance)
|
||||||
|
{
|
||||||
|
IOC.RegisterPersistennceInstance(kvp.Key, kvp.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 视觉效果
|
#region 视觉效果
|
||||||
@@ -1819,6 +1818,7 @@ namespace Serein.NodeFlow.Env
|
|||||||
ISereinIOC ISereinIOC.Reset()
|
ISereinIOC ISereinIOC.Reset()
|
||||||
{
|
{
|
||||||
sereinIOC.Reset();
|
sereinIOC.Reset();
|
||||||
|
ReRegisterPersistennceInstance(); // 重置后重新登记
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1866,11 +1866,18 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ISereinIOC.CustomRegisterInstance(string key, object instance, bool needInjectProperty)
|
bool ISereinIOC.RegisterPersistennceInstance(string key, object instance)
|
||||||
{
|
{
|
||||||
return sereinIOC.CustomRegisterInstance(key, instance, needInjectProperty);
|
PersistennceInstance.TryAdd(key, instance); // 记录需要持久化的实例
|
||||||
|
return sereinIOC.RegisterPersistennceInstance(key, instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ISereinIOC.RegisterInstance(string key, object instance)
|
||||||
|
{
|
||||||
|
return sereinIOC.RegisterInstance(key, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
object ISereinIOC.Instantiate(Type type)
|
object ISereinIOC.Instantiate(Type type)
|
||||||
{
|
{
|
||||||
return sereinIOC.Instantiate(type);
|
return sereinIOC.Instantiate(type);
|
||||||
|
|||||||
@@ -544,26 +544,6 @@ namespace Serein.NodeFlow.Env
|
|||||||
}
|
}
|
||||||
|
|
||||||
#region 流程依赖类库的接口
|
#region 流程依赖类库的接口
|
||||||
/// <summary>
|
|
||||||
/// 添加或更新全局数据
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="keyName">数据名称</param>
|
|
||||||
/// <param name="data">数据集</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public object AddOrUpdateGlobalData(string keyName, object data)
|
|
||||||
{
|
|
||||||
return currentFlowEnvironment.AddOrUpdateGlobalData(keyName, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取全局数据
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="keyName">数据名称</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public object GetGlobalData(string keyName)
|
|
||||||
{
|
|
||||||
return currentFlowEnvironment.GetGlobalData(keyName);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -594,9 +574,14 @@ namespace Serein.NodeFlow.Env
|
|||||||
return IOC.Build();
|
return IOC.Build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CustomRegisterInstance(string key, object instance, bool needInjectProperty = true)
|
public bool RegisterPersistennceInstance(string key, object instance)
|
||||||
{
|
{
|
||||||
return IOC.CustomRegisterInstance(key, instance, needInjectProperty);
|
return IOC.RegisterPersistennceInstance(key, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool RegisterInstance(string key, object instance)
|
||||||
|
{
|
||||||
|
return IOC.RegisterInstance(key, instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Get(Type type)
|
public object Get(Type type)
|
||||||
|
|||||||
@@ -1297,29 +1297,6 @@ namespace Serein.NodeFlow.Env
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 添加或更新全局数据
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="keyName">数据名称</param>
|
|
||||||
/// <param name="data">数据集</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public object AddOrUpdateGlobalData(string keyName, object data)
|
|
||||||
{
|
|
||||||
this.WriteLine(InfoType.INFO, "远程环境尚未实现的接口:AddOrUpdateGlobalData");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// 获取全局数据
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="keyName">数据名称</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public object GetGlobalData(string keyName)
|
|
||||||
{
|
|
||||||
this.WriteLine(InfoType.INFO, "远程环境尚未实现的接口:GetGlobalData");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
13
NodeFlow/FlowInterruptTool.cs
Normal file
13
NodeFlow/FlowInterruptTool.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using Serein.Library.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reactive.Subjects;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Serein.NodeFlow
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -15,9 +15,8 @@ namespace Serein.NodeFlow
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class FlowStarter
|
public class FlowStarter
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 控制全局触发器的结束
|
/// 控制所有全局触发器的结束
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private CancellationTokenSource? _flipFlopCts;
|
private CancellationTokenSource? _flipFlopCts;
|
||||||
|
|
||||||
@@ -31,15 +30,6 @@ namespace Serein.NodeFlow
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private Func<Task>? ExitAction { get; set; }
|
private Func<Task>? ExitAction { get; set; }
|
||||||
|
|
||||||
private void CheckStartState()
|
|
||||||
{
|
|
||||||
if (IsStopStart)
|
|
||||||
{
|
|
||||||
throw new Exception("停止启动");
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 从选定的节点开始运行
|
/// 从选定的节点开始运行
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -76,6 +66,10 @@ namespace Serein.NodeFlow
|
|||||||
List<MethodDetails> exitMethods)
|
List<MethodDetails> exitMethods)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#region 注册基本类
|
||||||
|
env.IOC.Register<IScriptFlowApi, ScriptFlowApi>(); // 注册脚本接口
|
||||||
|
#endregion
|
||||||
|
|
||||||
env.FlowState = RunState.Running; // 开始运行
|
env.FlowState = RunState.Running; // 开始运行
|
||||||
NodeModelBase? startNode = nodes.FirstOrDefault(node => node.IsStart);
|
NodeModelBase? startNode = nodes.FirstOrDefault(node => node.IsStart);
|
||||||
if (startNode is null) {
|
if (startNode is null) {
|
||||||
@@ -116,13 +110,12 @@ namespace Serein.NodeFlow
|
|||||||
thisRuningMds.AddRange(loadingMethods.Where(md => md?.ActingInstanceType is not null));
|
thisRuningMds.AddRange(loadingMethods.Where(md => md?.ActingInstanceType is not null));
|
||||||
thisRuningMds.AddRange(exitMethods.Where(md => md?.ActingInstanceType is not null));
|
thisRuningMds.AddRange(exitMethods.Where(md => md?.ActingInstanceType is not null));
|
||||||
|
|
||||||
// .AddRange(initMethods).AddRange(loadingMethods).a
|
|
||||||
foreach (var nodeMd in thisRuningMds)
|
foreach (var nodeMd in thisRuningMds)
|
||||||
{
|
{
|
||||||
nodeMd.ActingInstance = null;
|
nodeMd.ActingInstance = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
env.IOC.CustomRegisterInstance(typeof(ISereinIOC).FullName, env);
|
|
||||||
// 初始化ioc容器中的类型对象
|
// 初始化ioc容器中的类型对象
|
||||||
foreach (var md in thisRuningMds)
|
foreach (var md in thisRuningMds)
|
||||||
{
|
{
|
||||||
@@ -206,12 +199,12 @@ namespace Serein.NodeFlow
|
|||||||
#region 设置流程退出时的回调函数
|
#region 设置流程退出时的回调函数
|
||||||
ExitAction = async () =>
|
ExitAction = async () =>
|
||||||
{
|
{
|
||||||
env.IOC.Run<WebApiServer>(web => {
|
//env.IOC.Run<WebApiServer>(web => {
|
||||||
web?.Stop();
|
// web?.Stop();
|
||||||
});
|
//});
|
||||||
env.IOC.Run<WebSocketServer>(server => {
|
//env.IOC.Run<WebSocketServer>(server => {
|
||||||
server?.Stop();
|
// server?.Stop();
|
||||||
});
|
//});
|
||||||
|
|
||||||
foreach (MethodDetails? md in exitMethods)
|
foreach (MethodDetails? md in exitMethods)
|
||||||
{
|
{
|
||||||
@@ -230,7 +223,7 @@ namespace Serein.NodeFlow
|
|||||||
TerminateAllGlobalFlipflop(); // 确保所有触发器不再运行
|
TerminateAllGlobalFlipflop(); // 确保所有触发器不再运行
|
||||||
SereinEnv.ClearFlowGlobalData(); // 清空全局数据缓存
|
SereinEnv.ClearFlowGlobalData(); // 清空全局数据缓存
|
||||||
NativeDllHelper.FreeLibrarys(); // 卸载所有已加载的 Native Dll
|
NativeDllHelper.FreeLibrarys(); // 卸载所有已加载的 Native Dll
|
||||||
|
env.IOC.Run<FlowInterruptTool>(fit => fit.CancelAllTrigger());// 取消所有中断
|
||||||
env.FlowState = RunState.Completion;
|
env.FlowState = RunState.Completion;
|
||||||
env.FlipFlopState = RunState.Completion;
|
env.FlipFlopState = RunState.Completion;
|
||||||
|
|
||||||
@@ -249,7 +242,7 @@ namespace Serein.NodeFlow
|
|||||||
env.FlipFlopState = RunState.Running;
|
env.FlipFlopState = RunState.Running;
|
||||||
// 如果存在需要启动的触发器,则开始启动
|
// 如果存在需要启动的触发器,则开始启动
|
||||||
_flipFlopCts = new CancellationTokenSource();
|
_flipFlopCts = new CancellationTokenSource();
|
||||||
env.IOC.CustomRegisterInstance(NodeStaticConfig.FlipFlopCtsName, _flipFlopCts,false);
|
env.IOC.RegisterInstance(NodeStaticConfig.FlipFlopCtsName, _flipFlopCts);
|
||||||
|
|
||||||
// 使用 TaskCompletionSource 创建未启动的触发器任务
|
// 使用 TaskCompletionSource 创建未启动的触发器任务
|
||||||
var tasks = flipflopNodes.Select(async node =>
|
var tasks = flipflopNodes.Select(async node =>
|
||||||
@@ -281,39 +274,6 @@ namespace Serein.NodeFlow
|
|||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if false
|
|
||||||
|
|
||||||
public async Task TestScript(IFlowEnvironment environment)
|
|
||||||
{
|
|
||||||
SingleScriptNode singleScriptNode = new SingleScriptNode(environment);
|
|
||||||
string script =
|
|
||||||
"""
|
|
||||||
|
|
||||||
//let argData1 = flow.GetArgIndex(0); // 通过索引的方式,获取当前节点入参第一个参数
|
|
||||||
//let argData2 = flow.GetArgName("name"); // 通过名称的方式,获取当前节点入参的第二个参数
|
|
||||||
//let nodeData = flow.GetFlowData(); // 获取上一个节点的数据
|
|
||||||
//let state = flow.GetGlobalData("key name"); // 获取全局数据
|
|
||||||
|
|
||||||
//let result1 = flow.CallNode("node guid",); // 立即调用某个节点,获取数据
|
|
||||||
//let result2 = flow.CallFunc();
|
|
||||||
|
|
||||||
class User{
|
|
||||||
int ID;
|
|
||||||
string Name;
|
|
||||||
}
|
|
||||||
let user = new User();
|
|
||||||
user.ID = 12345;
|
|
||||||
user.Name = "张三";
|
|
||||||
return user;
|
|
||||||
""";
|
|
||||||
singleScriptNode.Script = script;
|
|
||||||
singleScriptNode.LoadScript();
|
|
||||||
var result = await singleScriptNode.ExecutingAsync(new DynamicContext(environment));
|
|
||||||
SereinEnv.WriteLine(InfoType.INFO, result?.ToString());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private ConcurrentDictionary<SingleFlipflopNode, CancellationTokenSource> dictGlobalFlipflop = [];
|
private ConcurrentDictionary<SingleFlipflopNode, CancellationTokenSource> dictGlobalFlipflop = [];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -403,7 +363,7 @@ namespace Serein.NodeFlow
|
|||||||
context.SetPreviousNode(nextNodes[i], singleFlipFlopNode);
|
context.SetPreviousNode(nextNodes[i], singleFlipFlopNode);
|
||||||
if (nextNodes[i].DebugSetting.IsInterrupt) // 执行触发前
|
if (nextNodes[i].DebugSetting.IsInterrupt) // 执行触发前
|
||||||
{
|
{
|
||||||
await nextNodes[i].DebugSetting.GetInterruptTask();
|
await nextNodes[i].DebugSetting.GetInterruptTask.Invoke();
|
||||||
await Console.Out.WriteLineAsync($"[{nextNodes[i].MethodDetails.MethodName}]中断已取消,开始执行后继分支");
|
await Console.Out.WriteLineAsync($"[{nextNodes[i].MethodDetails.MethodName}]中断已取消,开始执行后继分支");
|
||||||
}
|
}
|
||||||
await nextNodes[i].StartFlowAsync(context); // 启动执行触发器后继分支的节点
|
await nextNodes[i].StartFlowAsync(context); // 启动执行触发器后继分支的节点
|
||||||
@@ -421,7 +381,7 @@ namespace Serein.NodeFlow
|
|||||||
context.SetPreviousNode(nextNodes[i], singleFlipFlopNode);
|
context.SetPreviousNode(nextNodes[i], singleFlipFlopNode);
|
||||||
if (nextNodes[i].DebugSetting.IsInterrupt) // 执行触发前
|
if (nextNodes[i].DebugSetting.IsInterrupt) // 执行触发前
|
||||||
{
|
{
|
||||||
await nextNodes[i].DebugSetting.GetInterruptTask();
|
await nextNodes[i].DebugSetting.GetInterruptTask.Invoke();
|
||||||
await Console.Out.WriteLineAsync($"[{nextNodes[i].MethodDetails.MethodName}]中断已取消,开始执行后继分支");
|
await Console.Out.WriteLineAsync($"[{nextNodes[i].MethodDetails.MethodName}]中断已取消,开始执行后继分支");
|
||||||
}
|
}
|
||||||
await nextNodes[i].StartFlowAsync(context); // 启动执行触发器后继分支的节点
|
await nextNodes[i].StartFlowAsync(context); // 启动执行触发器后继分支的节点
|
||||||
@@ -448,12 +408,14 @@ namespace Serein.NodeFlow
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 结束流程
|
||||||
|
/// </summary>
|
||||||
public void Exit()
|
public void Exit()
|
||||||
{
|
{
|
||||||
ExitAction?.Invoke();
|
ExitAction?.Invoke();
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
if (DebugSetting.IsInterrupt) // 执行触发前
|
if (DebugSetting.IsInterrupt) // 执行触发前
|
||||||
{
|
{
|
||||||
string guid = this.Guid.ToString();
|
string guid = this.Guid.ToString();
|
||||||
await this.DebugSetting.GetInterruptTask();
|
await this.DebugSetting.GetInterruptTask.Invoke();
|
||||||
await Console.Out.WriteLineAsync($"[{this.MethodDetails.MethodName}]中断已取消,开始执行后继分支");
|
await Console.Out.WriteLineAsync($"[{this.MethodDetails.MethodName}]中断已取消,开始执行后继分支");
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -141,12 +141,23 @@ namespace Serein.NodeFlow.Model
|
|||||||
public override async Task<object?> ExecutingAsync(IDynamicContext context)
|
public override async Task<object?> ExecutingAsync(IDynamicContext context)
|
||||||
{
|
{
|
||||||
var @params = await GetParametersAsync(context);
|
var @params = await GetParametersAsync(context);
|
||||||
ScriptFlowApi.Context= context;
|
//dynamic obj = ((object[])@params[0])[0];
|
||||||
|
//try
|
||||||
|
//{
|
||||||
|
// SereinEnv.WriteLine(InfoType.INFO, "Dynamic Object Value :" + obj.VarInfo);
|
||||||
|
//}
|
||||||
|
//catch (Exception ex)
|
||||||
|
//{
|
||||||
|
// SereinEnv.WriteLine(ex);
|
||||||
|
//}
|
||||||
|
//ScriptFlowApi.Context = context; // 并发破坏了数据状态
|
||||||
context.AddOrUpdate($"{context.Guid}_{this.Guid}_Params", @params[0]); // 后面再改
|
context.AddOrUpdate($"{context.Guid}_{this.Guid}_Params", @params[0]); // 后面再改
|
||||||
|
|
||||||
mainNode ??= new SereinScriptParser(Script).Parse();
|
mainNode ??= new SereinScriptParser(Script).Parse();
|
||||||
IScriptInvokeContext scriptContext = new ScriptInvokeContext();
|
IScriptInvokeContext scriptContext = new ScriptInvokeContext(context);
|
||||||
|
|
||||||
var result = await ScriptInterpreter.InterpretAsync(scriptContext, mainNode); // 从入口节点执行
|
var result = await ScriptInterpreter.InterpretAsync(scriptContext, mainNode); // 从入口节点执行
|
||||||
|
//SereinEnv.WriteLine(InfoType.INFO, "FlowContext Guid : " + context.Guid);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,10 +24,6 @@ namespace Serein.NodeFlow
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public NodeModelBase NodeModel { get; private set; }
|
public NodeModelBase NodeModel { get; private set; }
|
||||||
|
|
||||||
public IDynamicContext? Context{ get; set; }
|
|
||||||
|
|
||||||
private string _paramsKey => $"{Context?.Guid}_{NodeModel.Guid}_Params";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -46,9 +42,10 @@ namespace Serein.NodeFlow
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public object? GetArgData(int index)
|
public object? GetArgData(IDynamicContext context, int index)
|
||||||
{
|
{
|
||||||
var obj = Context?.GetFlowData(_paramsKey);
|
var _paramsKey = $"{context?.Guid}_{NodeModel.Guid}_Params";
|
||||||
|
var obj = context?.GetFlowData(_paramsKey);
|
||||||
if (obj is object[] @params && index < @params.Length)
|
if (obj is object[] @params && index < @params.Length)
|
||||||
{
|
{
|
||||||
return @params[index];
|
return @params[index];
|
||||||
@@ -57,9 +54,9 @@ namespace Serein.NodeFlow
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public object? GetFlowData()
|
public object? GetFlowData(IDynamicContext context)
|
||||||
{
|
{
|
||||||
return Context?.GetFlowData(NodeModel.Guid);
|
return context?.GetFlowData(NodeModel.Guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object? GetGlobalData(string keyName)
|
public object? GetGlobalData(string keyName)
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ namespace Serein.Script
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IScriptInvokeContext
|
public interface IScriptInvokeContext
|
||||||
{
|
{
|
||||||
|
IDynamicContext FlowContext { get; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否该退出了
|
/// 是否该退出了
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -61,6 +62,13 @@ namespace Serein.Script
|
|||||||
|
|
||||||
public class ScriptInvokeContext : IScriptInvokeContext
|
public class ScriptInvokeContext : IScriptInvokeContext
|
||||||
{
|
{
|
||||||
|
public ScriptInvokeContext(IDynamicContext dynamicContext)
|
||||||
|
{
|
||||||
|
FlowContext = dynamicContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDynamicContext FlowContext{ get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 定义的变量
|
/// 定义的变量
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -76,6 +84,7 @@ namespace Serein.Script
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsCheckNullValue { get; set; }
|
public bool IsCheckNullValue { get; set; }
|
||||||
|
|
||||||
|
|
||||||
object IScriptInvokeContext.GetVarValue(string varName)
|
object IScriptInvokeContext.GetVarValue(string varName)
|
||||||
{
|
{
|
||||||
_variables.TryGetValue(varName, out var value);
|
_variables.TryGetValue(varName, out var value);
|
||||||
@@ -309,6 +318,11 @@ namespace Serein.Script
|
|||||||
}
|
}
|
||||||
private async Task<object> InterpretFunctionCallAsync(IScriptInvokeContext context, FunctionCallNode functionCallNode)
|
private async Task<object> InterpretFunctionCallAsync(IScriptInvokeContext context, FunctionCallNode functionCallNode)
|
||||||
{
|
{
|
||||||
|
if (functionCallNode.FunctionName.Equals("GetFlowContext", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return context.FlowContext;
|
||||||
|
}
|
||||||
|
|
||||||
// 评估函数参数
|
// 评估函数参数
|
||||||
var arguments = new object?[functionCallNode.Arguments.Count];
|
var arguments = new object?[functionCallNode.Arguments.Count];
|
||||||
for (int i = 0; i < functionCallNode.Arguments.Count; i++)
|
for (int i = 0; i < functionCallNode.Arguments.Count; i++)
|
||||||
@@ -321,6 +335,7 @@ namespace Serein.Script
|
|||||||
|
|
||||||
object? instance = null; // 静态方法不需要传入实例,所以可以传入null
|
object? instance = null; // 静态方法不需要传入实例,所以可以传入null
|
||||||
|
|
||||||
|
|
||||||
// 查找并执行对应的函数
|
// 查找并执行对应的函数
|
||||||
if (_functionTable.TryGetValue(funcName, out DelegateDetails? function))
|
if (_functionTable.TryGetValue(funcName, out DelegateDetails? function))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,36 +1,30 @@
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Serein.Library;
|
using Serein.Library;
|
||||||
|
using Serein.Library.Utils;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
namespace Serein.Workbench
|
namespace Serein.Workbench
|
||||||
{
|
{
|
||||||
#if DEBUG
|
|
||||||
public class People
|
|
||||||
{
|
|
||||||
public string Name { get; set; }
|
|
||||||
public int Id { get; set; }
|
|
||||||
public int Age { get; set; }
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for App.xaml
|
/// Interaction logic for App.xaml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class App : Application
|
public partial class App : Application
|
||||||
{
|
{
|
||||||
void LoadLocalProject()
|
private async Task LoadLocalProjectAsync()
|
||||||
{
|
{
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (1 == 1)
|
if (1 == 1)
|
||||||
{
|
{
|
||||||
// 这里是我自己的测试代码,你可以删除
|
// 这里是测试代码,可以删除
|
||||||
string filePath;
|
string filePath;
|
||||||
filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\Release\net8.0\PLCproject.dnf";
|
filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\Release\net8.0\PLCproject.dnf";
|
||||||
filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\Release\banyunqi\project.dnf";
|
filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\Release\banyunqi\project.dnf";
|
||||||
filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\debug\net8.0\project.dnf";
|
filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\debug\net8.0\project.dnf";
|
||||||
|
//filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\debug\net8.0\test.dnf";
|
||||||
string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
|
string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
|
||||||
App.FlowProjectData = JsonConvert.DeserializeObject<SereinProjectData>(content);
|
App.FlowProjectData = JsonConvert.DeserializeObject<SereinProjectData>(content);
|
||||||
App.FileDataPath = System.IO.Path.GetDirectoryName(filePath)!; // filePath;//
|
App.FileDataPath = System.IO.Path.GetDirectoryName(filePath)!; // filePath;//
|
||||||
@@ -42,7 +36,7 @@ namespace Serein.Workbench
|
|||||||
public static SereinProjectData? FlowProjectData { get; set; }
|
public static SereinProjectData? FlowProjectData { get; set; }
|
||||||
public static string FileDataPath { get; set; } = "";
|
public static string FileDataPath { get; set; } = "";
|
||||||
|
|
||||||
private void Application_Startup(object sender, StartupEventArgs e)
|
private async void Application_Startup(object sender, StartupEventArgs e)
|
||||||
{
|
{
|
||||||
// 检查是否传入了参数
|
// 检查是否传入了参数
|
||||||
if (e.Args.Length == 1)
|
if (e.Args.Length == 1)
|
||||||
@@ -71,7 +65,7 @@ namespace Serein.Workbench
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
this.LoadLocalProject();
|
await this.LoadLocalProjectAsync();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2904,10 +2904,6 @@ namespace Serein.Workbench
|
|||||||
//var t = guids.Select(kvp => (kvp.Key, kvp.Value)).ToArray();
|
//var t = guids.Select(kvp => (kvp.Key, kvp.Value)).ToArray();
|
||||||
//var result = flashText.ReplaceWords(jsonText, t);
|
//var result = flashText.ReplaceWords(jsonText, t);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder(jsonText);
|
StringBuilder sb = new StringBuilder(jsonText);
|
||||||
foreach (var kv in guids)
|
foreach (var kv in guids)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user