diff --git a/Library/Api/IFlowEnvironment.cs b/Library/Api/IFlowEnvironment.cs
index 81da808..2b45879 100644
--- a/Library/Api/IFlowEnvironment.cs
+++ b/Library/Api/IFlowEnvironment.cs
@@ -714,14 +714,7 @@ namespace Serein.Library.Api
event EnvOutHandler OnEnvOut;
#endregion
- #region 流程接口
-
- ///
- /// 设置输出
- ///
- //
- //
- ///void SetConsoleOut(); // Action output, Action clearMsg
+ #region 基本接口
///
/// 输出信息
@@ -730,21 +723,6 @@ namespace Serein.Library.Api
///
void WriteLine(InfoType type, string message, InfoClass @class = InfoClass.Trivial);
- /////
- ///// 使用JSON处理库输出对象信息
- /////
- /////
- //void WriteLineObjToJson(object obj);
-
- ///
- /// 启动远程服务
- ///
- Task StartRemoteServerAsync(int port = 7525);
-
- ///
- /// 停止远程服务
- ///
- void StopRemoteServer();
///
/// 加载项目文件
@@ -764,47 +742,60 @@ namespace Serein.Library.Api
///
Task GetProjectInfoAsync();
+ ///
+ /// 从节点信息集合批量加载节点控件
+ ///
+ /// 节点集合信息
+ ///
+ Task LoadNodeInfosAsync(List nodeInfos);
+
+
+ #endregion
+
+ #region 远程相关
+ ///
+ /// 启动远程服务
+ ///
+ Task StartRemoteServerAsync(int port = 7525);
+
+ ///
+ /// 停止远程服务
+ ///
+ void StopRemoteServer();
+
+ ///
+ /// (适用于远程连接后获取环境的运行状态)获取当前环境的信息
+ ///
+ ///
+ Task GetEnvInfoAsync();
+
///
/// 加载远程环境
///
/// 远程环境地址
/// 远程环境端口
/// 密码
- Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres,int port, string token);
+ Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres, int port, string token);
///
/// 退出远程环境
///
void ExitRemoteEnv();
- ///
- /// 从文件中加载Dll
- ///
- ///
- void LoadLibrary(string dllPath);
+
///
- /// 移除DLL
+ /// (用于远程)通知节点属性变更
///
- /// 程序集的名称
- bool TryUnloadLibrary(string assemblyFullName);
-
- ///
- /// 开始运行
- ///
- Task StartFlowAsync();
-
- ///
- /// 从选定的节点开始运行
- ///
- ///
+ /// 节点Guid
+ /// 属性路径
+ /// 属性值
///
- Task StartAsyncInSelectNode(string startNodeGuid);
+ Task NotificationNodeValueChangeAsync(string nodeGuid, string path, object value);
- ///
- /// 结束运行
- ///
- Task ExitFlowAsync();
+ #endregion
+
+ #region 流程节点操作接口
///
/// 移动了某个节点(远程插件使用)
@@ -851,12 +842,7 @@ namespace Serein.Library.Api
ConnectionArgSourceType argSourceType,
int argIndex);
- ///
- /// 从节点信息集合批量加载节点控件
- ///
- /// 节点集合信息
- ///
- Task LoadNodeInfosAsync(List nodeInfos);
+
///
/// 创建节点
@@ -866,15 +852,6 @@ namespace Serein.Library.Api
/// 节点绑定的方法说明
Task CreateNodeAsync(NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null);
- /////
- ///// 将节点放置在容器中/从容器中取出
- /////
- ///// 子节点(主要节点)
- ///// 父节点
- ///// 是否组合(反之为分解节点组合关系)
- /////
- //Task ChangeNodeContainerChildAsync(string childNodeGuid,string parentNodeGuid,bool isAssembly);
-
///
/// 将节点放置在容器中
///
@@ -921,23 +898,21 @@ namespace Serein.Library.Api
Task RemoveNodeAsync(string nodeGuid);
///
- /// 激活未启动的全局触发器
+ /// 改变可选参数的数目
///
- ///
- void ActivateFlipflopNode(string nodeGuid);
-
- ///
- /// 终结一个全局触发器,在它触发后将不会再次监听消息(表现为已经启动的触发器至少会再次处理一次消息,后面版本再修正这个非预期行为)
- ///
- ///
- void TerminateFlipflopNode(string nodeGuid);
+ /// 对应的节点Guid
+ /// true,增加参数;false,减少参数
+ /// 以哪个参数为模板进行拷贝,或删去某个参数(该参数必须为可选参数)
+ ///
+ Task ChangeParameter(string nodeGuid, bool isAdd, int paramIndex);
+ #endregion
#region 节点中断、表达式
#if false
-///
+ ///
/// 设置节点中断
///
/// 更改中断状态的节点Guid
@@ -978,24 +953,7 @@ namespace Serein.Library.Api
#endif
#endregion
- ///
- /// (用于远程)通知节点属性变更
- ///
- /// 节点Guid
- /// 属性路径
- /// 属性值
- ///
- Task NotificationNodeValueChangeAsync(string nodeGuid, string path, object value);
-
- ///
- /// 改变可选参数的数目
- ///
- /// 对应的节点Guid
- /// true,增加参数;false,减少参数
- /// 以哪个参数为模板进行拷贝,或删去某个参数(该参数必须为可选参数)
- ///
- Task ChangeParameter(string nodeGuid, bool isAdd, int paramIndex);
-
+ #region 流程运行相关
///
/// 获取方法描述信息
@@ -1016,17 +974,34 @@ namespace Serein.Library.Api
bool TryGetDelegateDetails(string assemblyName, string methodName, out DelegateDetails del);
- #region 远程相关
///
- /// (适用于远程连接后获取环境的运行状态)获取当前环境的信息
+ /// 开始运行
///
+ Task StartFlowAsync();
+
+ ///
+ /// 从选定的节点开始运行
+ ///
+ ///
///
- Task GetEnvInfoAsync();
- #endregion
+ Task StartAsyncInSelectNode(string startNodeGuid);
- #endregion
+ ///
+ /// 结束运行
+ ///
+ Task ExitFlowAsync();
- #region 启动器调用
+ ///
+ /// 激活未启动的全局触发器
+ ///
+ ///
+ void ActivateFlipflopNode(string nodeGuid);
+
+ ///
+ /// 终结一个全局触发器,在它触发后将不会再次监听消息(表现为已经启动的触发器至少会再次处理一次消息,后面版本再修正这个非预期行为)
+ ///
+ ///
+ void TerminateFlipflopNode(string nodeGuid);
///
/// 流程启动器调用,监视数据更新通知
@@ -1054,31 +1029,19 @@ namespace Serein.Library.Api
#endregion
- #region 流程运行时
-
- #region 全局数据/方法信息
-
+ #region 类库依赖相关
///
- /// 添加或更新全局数据
+ /// 从文件中加载Dll
///
- /// 数据名称
- /// 数据集
- ///
- object AddOrUpdateGlobalData(string keyName, object data);
+ ///
+ void LoadLibrary(string dllPath);
///
- /// 获取全局数据
+ /// 移除DLL
///
- /// 数据名称
- ///
- object GetGlobalData(string keyName);
-
- #endregion
-
-
- #region 加载依赖
-
+ /// 程序集的名称
+ bool TryUnloadLibrary(string assemblyFullName);
///
/// 运行时加载
///
@@ -1093,7 +1056,6 @@ namespace Serein.Library.Api
/// 是否递归加载
void LoadAllNativeLibraryOfRuning(string path, bool isRecurrence = true);
- #endregion
#endregion
#region UI视觉
diff --git a/Library/Api/IScriptFlowApi.cs b/Library/Api/IScriptFlowApi.cs
index 27f48e9..0cc4e4a 100644
--- a/Library/Api/IScriptFlowApi.cs
+++ b/Library/Api/IScriptFlowApi.cs
@@ -12,7 +12,7 @@ namespace Serein.Library.Api
public interface IScriptFlowApi
{
///
- /// 当前流程
+ /// 当前流程运行环境
///
IFlowEnvironment Env { get; }
///
@@ -20,34 +20,28 @@ namespace Serein.Library.Api
///
NodeModelBase NodeModel { get; }
- ///
- /// 动态流程上下文
- ///
- IDynamicContext Context { get; set; }
-
///
/// 根据索引从入参数据获取数据
///
+ ///
///
///
- object GetArgData(int index);
+ object GetArgData(IDynamicContext context, int index);
///
- /// 根据入参名称从入参数据获取数据
+ /// 获取流程当前传递的数据
///
- ///
+ ///
///
- // object GetDataOfParams(string name);
+ object GetFlowData(IDynamicContext context);
+
///
/// 获取全局数据
///
///
///
object GetGlobalData(string keyName);
- ///
- /// 获取流程当前传递的数据
- ///
- ///
- object GetFlowData();
+
+
///
/// 立即调用某个节点并获取其返回值
///
diff --git a/Library/Api/ISereinIoc.cs b/Library/Api/ISereinIoc.cs
index b7491a1..5516b4b 100644
--- a/Library/Api/ISereinIoc.cs
+++ b/Library/Api/ISereinIoc.cs
@@ -35,6 +35,22 @@ namespace Serein.Library.Api
///
ISereinIOC Register(params object[] parameters) where TImplementation : TService;
+ ///
+ /// 指定一个Key登记一个持久化的实例。
+ ///
+ /// 登记使用的名称
+ /// 实例对象
+ /// 是否注册成功
+ bool RegisterPersistennceInstance(string key, object instance);
+
+ ///
+ /// 指定一个Key登记一个实例。
+ ///
+ /// 登记使用的名称
+ /// 实例对象
+ /// 是否注册成功
+ bool RegisterInstance(string key, object instance);
+
///
/// 获取类型的实例。如果需要获取的类型以“接口-实现类”的方式注册,请使用接口的类型。
///
@@ -53,14 +69,7 @@ namespace Serein.Library.Api
///
T Get(string key);
- ///
- /// 指定一个Key登记一个实例。如果实例中需要注入的依赖项,需要将needInjectProperty设置为true。
- ///
- /// 注入名称
- /// 实例对象
- /// 是否需要注入依赖项
- /// 是否注册成功
- bool CustomRegisterInstance(string key, object instance, bool needInjectProperty = true);
+
///
/// 创建实例并注入依赖项,不会注册到IOC容器中。
diff --git a/Library/FlowNode/NodeDebugSetting.cs b/Library/FlowNode/NodeDebugSetting.cs
index 492aa70..87d5c4a 100644
--- a/Library/FlowNode/NodeDebugSetting.cs
+++ b/Library/FlowNode/NodeDebugSetting.cs
@@ -1,4 +1,6 @@
-using System;
+using Newtonsoft.Json.Linq;
+using Serein.Library.Utils;
+using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
@@ -33,52 +35,67 @@ namespace Serein.Library
private bool _isEnable = true;
///
- /// 中断级别,暂时停止继续执行后继分支。
+ /// 是否中断节点。
///
- //[PropertyInfo]
- //private InterruptClass _interruptClass = InterruptClass.None;
-
- ///
- /// 中断级别,暂时停止继续执行后继分支。
- ///
- [PropertyInfo(IsNotification = true, CustomCodeAtEnd = "// NodeModel?.Env?.SetNodeInterruptAsync(NodeModel?.Guid, value);")] // CustomCode = "NodeModel?.Env?.SetNodeInterruptAsync(NodeModel?.Guid, value);"
+ [PropertyInfo(IsNotification = true, CustomCodeAtEnd = "ChangeInterruptState(value);")] // CustomCode = "NodeModel?.Env?.SetNodeInterruptAsync(NodeModel?.Guid, value);"
private bool _isInterrupt = false;
+ }
+
+ ///
+ /// 节点中断
+ ///
+ public partial class NodeDebugSetting
+ {
///
/// 取消中断的回调函数
///
- [PropertyInfo]
- private Action _cancelInterruptCallback;
+ private Action _cancelInterrupt { get; set; }
+ ///
+ /// 取消中断
+ ///
+ public Action CancelInterrupt => _cancelInterrupt;
+ ///
+ /// 中断节点
+ ///
+ public Func _getInterruptTask;
///
- /// 中断Task(用来中断)
+ /// 获取中断的Task
///
- [PropertyInfo]
- private Func _getInterruptTask;
+ public Func GetInterruptTask => _getInterruptTask;
- }
-
-
///
- /// 中断级别,暂时停止继续执行后继分支。
+ /// 改变中断状态
///
- //public enum InterruptClass
- //{
- // ///
- // /// 不中断
- // ///
- // None,
- // ///
- // /// 分支中断,中断进入当前节点的分支。
- // ///
- // Branch,
- // ///
- // /// 全局中断,中断全局所有节点的运行。(暂未实现相关)
- // ///
- // Global,
- //}
+ public void ChangeInterruptState(bool state)
+ {
+ if (state && _getInterruptTask is null)
+ {
+ // 设置获取中断的委托
+ _getInterruptTask = () => NodeModel.Env.IOC.Get().WaitTriggerAsync(NodeModel.Guid);
+ }
+ else if (!state)
+ {
+ if (_getInterruptTask is null)
+ {
+
+ }
+ else
+ {
+ // 设置解除中断的委托
+ _cancelInterrupt = () => NodeModel.Env.IOC.Get().InvokeTrigger(NodeModel.Guid);
+ _cancelInterrupt.Invoke();
+ _getInterruptTask = null;
+ }
+
+ }
+ }
+
+
}
+}
diff --git a/Library/FlowNode/NodeModelBaseFunc.cs b/Library/FlowNode/NodeModelBaseFunc.cs
index fb8746d..5a14cf7 100644
--- a/Library/FlowNode/NodeModelBaseFunc.cs
+++ b/Library/FlowNode/NodeModelBaseFunc.cs
@@ -36,7 +36,6 @@ namespace Serein.Library
}
-
///
/// 保存自定义信息
///
@@ -60,21 +59,11 @@ namespace Serein.Library
///
public virtual void Remove()
{
-
- }
-
- ///
- /// 移除该节点
- ///
- public virtual void RemoveFromEnv()
- {
- if (this.DebugSetting.CancelInterruptCallback != null)
+ if (this.DebugSetting.CancelInterrupt != null)
{
- this.DebugSetting.CancelInterruptCallback?.Invoke();
+ this.DebugSetting.CancelInterrupt?.Invoke();
}
- this.DebugSetting.GetInterruptTask = null;
this.DebugSetting.NodeModel = null;
- this.DebugSetting.CancelInterruptCallback = null;
this.DebugSetting = null;
foreach (var pd in this.MethodDetails.ParameterDetailss)
{
@@ -87,7 +76,7 @@ namespace Serein.Library
pd.ArgDataSourceNodeGuid = null;
pd.ExplicitTypeName = null;
}
- this.MethodDetails.ParameterDetailss = null;
+ this.MethodDetails.ParameterDetailss = null;
this.MethodDetails.ActingInstance = null;
this.MethodDetails.NodeModel = null;
this.MethodDetails.ReturnType = null;
@@ -131,7 +120,6 @@ namespace Serein.Library
}
}
-
///
/// 导出为节点信息
///
@@ -231,10 +219,6 @@ namespace Serein.Library
}
#endregion
- #region 程序集更新,更新节点方法描述、以及所有入参描述的类型
-
- #endregion
-
#region 调试中断
///
@@ -243,15 +227,13 @@ namespace Serein.Library
public void CancelInterrupt()
{
this.DebugSetting.IsInterrupt = false;
- DebugSetting.CancelInterruptCallback?.Invoke();
+ DebugSetting.CancelInterrupt?.Invoke();
}
#endregion
#region 节点方法的执行
-
-
///
/// 是否应该退出执行
///
@@ -271,6 +253,7 @@ namespace Serein.Library
{
return true;
}
+
// 如果存在全局触发器,且触发器的执行任务已经被取消时,退出执行。
if (flowCts != null)
{
@@ -365,15 +348,21 @@ namespace Serein.Library
/// 节点传回数据对象
public virtual async Task
// 示例 TriggerResult 对象池
- public class TriggerResultPool
+ public class TriggerResultPool
{
- private readonly ConcurrentExpandingObjectPool> _objectPool;
+ private readonly ConcurrentExpandingObjectPool> _objectPool;
public TriggerResultPool(int defaultCapacity = 30)
{
- _objectPool = new ConcurrentExpandingObjectPool>(defaultCapacity);
+ _objectPool = new ConcurrentExpandingObjectPool>(defaultCapacity);
}
- public TriggerResult Get() => _objectPool.Get();
+ public TriggerResult Get() => _objectPool.Get();
- public void Return(TriggerResult result) => _objectPool.Return(result);
+ public void Return(TriggerResult result) => _objectPool.Return(result);
}
diff --git a/Library/Utils/SereinIoc.cs b/Library/Utils/SereinIoc.cs
index a71bf4d..8642eff 100644
--- a/Library/Utils/SereinIoc.cs
+++ b/Library/Utils/SereinIoc.cs
@@ -107,12 +107,20 @@ namespace Serein.Library.Utils
#region 通过名称记录或获取一个实例
///
- /// 指定key值注册一个已经实例化的实例对象
+ /// 指定key值注册一个已经实例化的实例对象,并持久化储存
///
///
///
- ///
- public bool CustomRegisterInstance(string key, object instance, bool needInjectProperty = true)
+ public bool RegisterInstance(string key, object instance)
+ {
+ return RegisterPersistennceInstance(key, instance);
+ }
+ ///
+ /// 指定key值注册一个已经实例化的实例对象,并持久化储存
+ ///
+ ///
+ ///
+ public bool RegisterPersistennceInstance(string key, object instance)
{
// 不存在时才允许创建
if (_dependencies.ContainsKey(key))
@@ -120,11 +128,11 @@ namespace Serein.Library.Utils
return false;
}
_dependencies.TryAdd(key, instance);
- if (needInjectProperty)
- {
- InjectDependencies(instance); // 注入实例需要的依赖项
- }
- InjectUnfinishedDependencies(key, instance); // 检查是否存在其它实例需要该类型
+ //if (needInjectProperty)
+ //{
+ // InjectDependencies(instance); // 注入实例需要的依赖项
+ //}
+ //InjectUnfinishedDependencies(key, instance); // 检查是否存在其它实例需要该类型
OnIOCMembersChanged?.Invoke(new IOCMembersChangedEventArgs(key, instance));
return true;
}
diff --git a/Net462DllTest/Trigger/PrakingDevice.cs b/Net462DllTest/Trigger/PrakingDevice.cs
index edf4539..a7f0701 100644
--- a/Net462DllTest/Trigger/PrakingDevice.cs
+++ b/Net462DllTest/Trigger/PrakingDevice.cs
@@ -1,6 +1,6 @@
using Net462DllTest.LogicControl;
using Serein.Library;
-using Serein.Library.Utils.FlowTrigger;
+using Serein.Library.Utils;
namespace Net462DllTest.Trigger
{
diff --git a/Net462DllTest/Trigger/SiemensPlcDevice.cs b/Net462DllTest/Trigger/SiemensPlcDevice.cs
index 5d1b5f6..8d510e6 100644
--- a/Net462DllTest/Trigger/SiemensPlcDevice.cs
+++ b/Net462DllTest/Trigger/SiemensPlcDevice.cs
@@ -8,7 +8,6 @@ using Net462DllTest.Signal;
using Net462DllTest.Utils;
using Serein.Library;
using Serein.Library.Utils;
-using Serein.Library.Utils.FlowTrigger;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
diff --git a/Net462DllTest/Trigger/ViewManagement.cs b/Net462DllTest/Trigger/ViewManagement.cs
index 077c7c7..5238d7d 100644
--- a/Net462DllTest/Trigger/ViewManagement.cs
+++ b/Net462DllTest/Trigger/ViewManagement.cs
@@ -9,7 +9,6 @@ using System.Threading;
using System.Windows.Forms;
using System.Windows.Threading;
using Serein.Library.Utils;
-using Serein.Library.Utils.FlowTrigger;
namespace Net462DllTest.Trigger
{
diff --git a/NodeFlow/Env/FlowEnvironment.cs b/NodeFlow/Env/FlowEnvironment.cs
index cb88d7d..23e4e23 100644
--- a/NodeFlow/Env/FlowEnvironment.cs
+++ b/NodeFlow/Env/FlowEnvironment.cs
@@ -69,6 +69,16 @@ namespace Serein.NodeFlow.Env
NodeMVVMManagement.RegisterModel(NodeControlType.GlobalData, typeof(SingleGlobalDataNode)); // 全局数据节点
NodeMVVMManagement.RegisterModel(NodeControlType.Script, typeof(SingleScriptNode)); // 脚本节点
#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 远程管理
@@ -303,6 +313,11 @@ namespace Serein.NodeFlow.Env
///
private readonly SereinIOC sereinIOC;
+ ///
+ /// 本地运行环境缓存的持久化实例
+ ///
+ private Dictionary PersistennceInstance { get; } = new Dictionary();
+
///
/// 环境加载的节点集合
/// Node Guid - Node Model
@@ -376,34 +391,23 @@ namespace Serein.NodeFlow.Env
///
public async Task StartFlowAsync()
{
- flowStarter = new FlowStarter();
+ flowStarter ??= new FlowStarter();
var nodes = NodeModels.Values.ToList();
-
-
List initMethods = this.FlowLibraryManagement.GetMdsOnFlowStart(NodeType.Init);
List loadMethods = this.FlowLibraryManagement.GetMdsOnFlowStart(NodeType.Loading);
List exitMethods = this.FlowLibraryManagement.GetMdsOnFlowStart(NodeType.Exit);
Dictionary> autoRegisterTypes = this.FlowLibraryManagement.GetaAutoRegisterType();
-
- IOC.Reset(); // 开始运行时清空ioc中注册的实例
-
- IOC.Register(); // 注册脚本接口
- 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);
- if (FlipFlopState == RunState.Completion)
- {
- await ExitFlowAsync(); // 未运行触发器时,才会调用结束方法
- }
- });
+ IOC.Reset();
+ await flowStarter.RunAsync(this, nodes, autoRegisterTypes, initMethods, loadMethods, exitMethods);
+ //_ = Task.Run(async () =>
+ //{
+ // //if (FlipFlopState == RunState.Completion)
+ // //{
+ // // await ExitFlowAsync(); // 未运行触发器时,才会调用结束方法
+ // //}
+ //});
return true;
@@ -466,6 +470,7 @@ namespace Serein.NodeFlow.Env
{
flowStarter?.Exit();
UIContextOperation?.Invoke(() => OnFlowRunComplete?.Invoke(new FlowEventArgs()));
+ IOC.Reset();
flowStarter = null;
GC.Collect();
return Task.FromResult(true);
@@ -829,7 +834,10 @@ namespace Serein.NodeFlow.Env
foreach (var toNodeGuid in item.toNodeGuids)
{
var toNodeModel = GuidToModel(toNodeGuid);
- if (toNodeModel is null) continue;
+ if (toNodeModel is null) {
+ // 防御性代码,加载正常保存的项目文件不会进入这里
+ continue;
+ };
var isSuccessful = ConnectInvokeOfNode(fromNodeModel, toNodeModel, item.connectionType); // 加载时确定节点间的连接关系
}
}
@@ -1396,29 +1404,6 @@ namespace Serein.NodeFlow.Env
#region 流程依赖类库的接口
- ///
- /// 添加或更新全局数据
- ///
- /// 数据名称
- /// 数据集
- ///
- public object AddOrUpdateGlobalData(string keyName, object data)
- {
- SereinEnv.AddOrUpdateFlowGlobalData(keyName, data);
- return data;
- }
-
- ///
- /// 获取全局数据
- ///
- /// 数据名称
- ///
- public object? GetGlobalData(string keyName)
- {
- return SereinEnv.GetFlowGlobalData(keyName);
- }
-
-
///
/// 运行时加载
///
@@ -1796,6 +1781,20 @@ namespace Serein.NodeFlow.Env
//}
+ ///
+ /// 向容器登记缓存的持久化实例
+ ///
+ private void ReRegisterPersistennceInstance()
+ {
+ lock (PersistennceInstance)
+ {
+ foreach (var kvp in PersistennceInstance)
+ {
+ IOC.RegisterPersistennceInstance(kvp.Key, kvp.Value);
+ }
+ }
+ }
+
#endregion
#region 视觉效果
@@ -1819,6 +1818,7 @@ namespace Serein.NodeFlow.Env
ISereinIOC ISereinIOC.Reset()
{
sereinIOC.Reset();
+ ReRegisterPersistennceInstance(); // 重置后重新登记
return this;
}
@@ -1866,10 +1866,17 @@ 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)
{
diff --git a/NodeFlow/Env/FlowEnvironmentDecorator.cs b/NodeFlow/Env/FlowEnvironmentDecorator.cs
index 3e10fee..2a8685a 100644
--- a/NodeFlow/Env/FlowEnvironmentDecorator.cs
+++ b/NodeFlow/Env/FlowEnvironmentDecorator.cs
@@ -544,27 +544,7 @@ namespace Serein.NodeFlow.Env
}
#region 流程依赖类库的接口
- ///
- /// 添加或更新全局数据
- ///
- /// 数据名称
- /// 数据集
- ///
- public object AddOrUpdateGlobalData(string keyName, object data)
- {
- return currentFlowEnvironment.AddOrUpdateGlobalData(keyName, data);
- }
-
- ///
- /// 获取全局数据
- ///
- /// 数据名称
- ///
- public object GetGlobalData(string keyName)
- {
- return currentFlowEnvironment.GetGlobalData(keyName);
- }
-
+
///
/// 运行时加载
@@ -594,9 +574,14 @@ namespace Serein.NodeFlow.Env
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)
diff --git a/NodeFlow/Env/RemoteFlowEnvironment.cs b/NodeFlow/Env/RemoteFlowEnvironment.cs
index 8893c6b..13878d6 100644
--- a/NodeFlow/Env/RemoteFlowEnvironment.cs
+++ b/NodeFlow/Env/RemoteFlowEnvironment.cs
@@ -1297,29 +1297,6 @@ namespace Serein.NodeFlow.Env
- ///
- /// 添加或更新全局数据
- ///
- /// 数据名称
- /// 数据集
- ///
- public object AddOrUpdateGlobalData(string keyName, object data)
- {
- this.WriteLine(InfoType.INFO, "远程环境尚未实现的接口:AddOrUpdateGlobalData");
- return null;
- }
- ///
- /// 获取全局数据
- ///
- /// 数据名称
- ///
- public object GetGlobalData(string keyName)
- {
- this.WriteLine(InfoType.INFO, "远程环境尚未实现的接口:GetGlobalData");
- return null;
- }
-
-
#endregion
diff --git a/NodeFlow/FlowInterruptTool.cs b/NodeFlow/FlowInterruptTool.cs
new file mode 100644
index 0000000..f85b1e1
--- /dev/null
+++ b/NodeFlow/FlowInterruptTool.cs
@@ -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
+{
+
+}
diff --git a/NodeFlow/FlowStarter.cs b/NodeFlow/FlowStarter.cs
index f82a05d..4958779 100644
--- a/NodeFlow/FlowStarter.cs
+++ b/NodeFlow/FlowStarter.cs
@@ -15,9 +15,8 @@ namespace Serein.NodeFlow
///
public class FlowStarter
{
-
///
- /// 控制全局触发器的结束
+ /// 控制所有全局触发器的结束
///
private CancellationTokenSource? _flipFlopCts;
@@ -31,15 +30,6 @@ namespace Serein.NodeFlow
///
private Func? ExitAction { get; set; }
- private void CheckStartState()
- {
- if (IsStopStart)
- {
- throw new Exception("停止启动");
-
- }
- }
-
///
/// 从选定的节点开始运行
///
@@ -76,6 +66,10 @@ namespace Serein.NodeFlow
List exitMethods)
{
+ #region 注册基本类
+ env.IOC.Register(); // 注册脚本接口
+ #endregion
+
env.FlowState = RunState.Running; // 开始运行
NodeModelBase? startNode = nodes.FirstOrDefault(node => node.IsStart);
if (startNode is null) {
@@ -116,13 +110,12 @@ namespace Serein.NodeFlow
thisRuningMds.AddRange(loadingMethods.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)
{
nodeMd.ActingInstance = null;
}
- env.IOC.CustomRegisterInstance(typeof(ISereinIOC).FullName, env);
// 初始化ioc容器中的类型对象
foreach (var md in thisRuningMds)
{
@@ -206,12 +199,12 @@ namespace Serein.NodeFlow
#region 设置流程退出时的回调函数
ExitAction = async () =>
{
- env.IOC.Run(web => {
- web?.Stop();
- });
- env.IOC.Run(server => {
- server?.Stop();
- });
+ //env.IOC.Run(web => {
+ // web?.Stop();
+ //});
+ //env.IOC.Run(server => {
+ // server?.Stop();
+ //});
foreach (MethodDetails? md in exitMethods)
{
@@ -230,7 +223,7 @@ namespace Serein.NodeFlow
TerminateAllGlobalFlipflop(); // 确保所有触发器不再运行
SereinEnv.ClearFlowGlobalData(); // 清空全局数据缓存
NativeDllHelper.FreeLibrarys(); // 卸载所有已加载的 Native Dll
-
+ env.IOC.Run(fit => fit.CancelAllTrigger());// 取消所有中断
env.FlowState = RunState.Completion;
env.FlipFlopState = RunState.Completion;
@@ -249,7 +242,7 @@ namespace Serein.NodeFlow
env.FlipFlopState = RunState.Running;
// 如果存在需要启动的触发器,则开始启动
_flipFlopCts = new CancellationTokenSource();
- env.IOC.CustomRegisterInstance(NodeStaticConfig.FlipFlopCtsName, _flipFlopCts,false);
+ env.IOC.RegisterInstance(NodeStaticConfig.FlipFlopCtsName, _flipFlopCts);
// 使用 TaskCompletionSource 创建未启动的触发器任务
var tasks = flipflopNodes.Select(async node =>
@@ -281,39 +274,6 @@ namespace Serein.NodeFlow
#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 dictGlobalFlipflop = [];
///
@@ -403,7 +363,7 @@ namespace Serein.NodeFlow
context.SetPreviousNode(nextNodes[i], singleFlipFlopNode);
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 nextNodes[i].StartFlowAsync(context); // 启动执行触发器后继分支的节点
@@ -421,7 +381,7 @@ namespace Serein.NodeFlow
context.SetPreviousNode(nextNodes[i], singleFlipFlopNode);
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 nextNodes[i].StartFlowAsync(context); // 启动执行触发器后继分支的节点
@@ -448,12 +408,14 @@ namespace Serein.NodeFlow
}
-
+ ///
+ /// 结束流程
+ ///
public void Exit()
{
ExitAction?.Invoke();
- }
+ }
}
}
diff --git a/NodeFlow/Model/SingleFlipflopNode.cs b/NodeFlow/Model/SingleFlipflopNode.cs
index 1f7c764..a8cc1ff 100644
--- a/NodeFlow/Model/SingleFlipflopNode.cs
+++ b/NodeFlow/Model/SingleFlipflopNode.cs
@@ -27,7 +27,7 @@ namespace Serein.NodeFlow.Model
if (DebugSetting.IsInterrupt) // 执行触发前
{
string guid = this.Guid.ToString();
- await this.DebugSetting.GetInterruptTask();
+ await this.DebugSetting.GetInterruptTask.Invoke();
await Console.Out.WriteLineAsync($"[{this.MethodDetails.MethodName}]中断已取消,开始执行后继分支");
}
#endregion
diff --git a/NodeFlow/Model/SingleScriptNode.cs b/NodeFlow/Model/SingleScriptNode.cs
index b1ab425..e0bd450 100644
--- a/NodeFlow/Model/SingleScriptNode.cs
+++ b/NodeFlow/Model/SingleScriptNode.cs
@@ -141,12 +141,23 @@ namespace Serein.NodeFlow.Model
public override async Task ExecutingAsync(IDynamicContext 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]); // 后面再改
mainNode ??= new SereinScriptParser(Script).Parse();
- IScriptInvokeContext scriptContext = new ScriptInvokeContext();
+ IScriptInvokeContext scriptContext = new ScriptInvokeContext(context);
+
var result = await ScriptInterpreter.InterpretAsync(scriptContext, mainNode); // 从入口节点执行
+ //SereinEnv.WriteLine(InfoType.INFO, "FlowContext Guid : " + context.Guid);
return result;
}
diff --git a/NodeFlow/ScriptFlowApi.cs b/NodeFlow/ScriptFlowApi.cs
index 79684df..c6bf14f 100644
--- a/NodeFlow/ScriptFlowApi.cs
+++ b/NodeFlow/ScriptFlowApi.cs
@@ -24,11 +24,7 @@ namespace Serein.NodeFlow
///
public NodeModelBase NodeModel { get; private set; }
- public IDynamicContext? Context{ get; set; }
-
- private string _paramsKey => $"{Context?.Guid}_{NodeModel.Guid}_Params";
-
-
+
///
/// 创建流程脚本接口
@@ -46,9 +42,10 @@ namespace Serein.NodeFlow
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)
{
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)
diff --git a/Serein.Script/SereinScriptInterpreter.cs b/Serein.Script/SereinScriptInterpreter.cs
index 15723e7..a1ecace 100644
--- a/Serein.Script/SereinScriptInterpreter.cs
+++ b/Serein.Script/SereinScriptInterpreter.cs
@@ -26,6 +26,7 @@ namespace Serein.Script
///
public interface IScriptInvokeContext
{
+ IDynamicContext FlowContext { get; }
///
/// 是否该退出了
///
@@ -61,6 +62,13 @@ namespace Serein.Script
public class ScriptInvokeContext : IScriptInvokeContext
{
+ public ScriptInvokeContext(IDynamicContext dynamicContext)
+ {
+ FlowContext = dynamicContext;
+ }
+
+ public IDynamicContext FlowContext{ get; }
+
///
/// 定义的变量
///
@@ -76,6 +84,7 @@ namespace Serein.Script
///
public bool IsCheckNullValue { get; set; }
+
object IScriptInvokeContext.GetVarValue(string varName)
{
_variables.TryGetValue(varName, out var value);
@@ -309,6 +318,11 @@ namespace Serein.Script
}
private async Task InterpretFunctionCallAsync(IScriptInvokeContext context, FunctionCallNode functionCallNode)
{
+ if (functionCallNode.FunctionName.Equals("GetFlowContext", StringComparison.OrdinalIgnoreCase))
+ {
+ return context.FlowContext;
+ }
+
// 评估函数参数
var arguments = new object?[functionCallNode.Arguments.Count];
for (int i = 0; i < functionCallNode.Arguments.Count; i++)
@@ -321,6 +335,7 @@ namespace Serein.Script
object? instance = null; // 静态方法不需要传入实例,所以可以传入null
+
// 查找并执行对应的函数
if (_functionTable.TryGetValue(funcName, out DelegateDetails? function))
{
diff --git a/WorkBench/App.xaml.cs b/WorkBench/App.xaml.cs
index e8b4004..a90c015 100644
--- a/WorkBench/App.xaml.cs
+++ b/WorkBench/App.xaml.cs
@@ -1,36 +1,30 @@
using Newtonsoft.Json;
using Serein.Library;
+using Serein.Library.Utils;
+using System.Diagnostics;
using System.IO;
using System.Windows;
namespace Serein.Workbench
{
-#if DEBUG
- public class People
- {
- public string Name { get; set; }
- public int Id { get; set; }
- public int Age { get; set; }
- }
-#endif
-
-
///
/// Interaction logic for App.xaml
///
public partial class App : Application
{
- void LoadLocalProject()
+ private async Task LoadLocalProjectAsync()
{
+
#if DEBUG
if (1 == 1)
{
- // 这里是我自己的测试代码,你可以删除
+ // 这里是测试代码,可以删除
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\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\test.dnf";
string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
App.FlowProjectData = JsonConvert.DeserializeObject(content);
App.FileDataPath = System.IO.Path.GetDirectoryName(filePath)!; // filePath;//
@@ -42,7 +36,7 @@ namespace Serein.Workbench
public static SereinProjectData? FlowProjectData { 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)
@@ -71,7 +65,7 @@ namespace Serein.Workbench
}
}
- this.LoadLocalProject();
+ await this.LoadLocalProjectAsync();
}
diff --git a/WorkBench/MainWindow.xaml.cs b/WorkBench/MainWindow.xaml.cs
index e4833cd..af87f32 100644
--- a/WorkBench/MainWindow.xaml.cs
+++ b/WorkBench/MainWindow.xaml.cs
@@ -2904,11 +2904,7 @@ namespace Serein.Workbench
//var t = guids.Select(kvp => (kvp.Key, kvp.Value)).ToArray();
//var result = flashText.ReplaceWords(jsonText, t);
-
-
-
-
- StringBuilder sb = new StringBuilder(jsonText);
+ StringBuilder sb = new StringBuilder(jsonText);
foreach (var kv in guids)
{
sb.Replace(kv.Key, kv.Value);