移除了中断相关的后台代码与UI交互(待重写);重写运行时节点获取参数的方法;重写了节点容器的互动;完善了WebSocket远程交互;完善了项目文件的加载;

This commit is contained in:
fengjiayi
2024-12-26 16:42:05 +08:00
parent 56b22be8c0
commit 7a6f8c407b
37 changed files with 880 additions and 1127 deletions

View File

@@ -14,13 +14,13 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Numerics;
using System.Reactive;
using System.Reflection;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.Loader;
using System.Security.AccessControl;
using System.Text;
using System.Xml.Linq;
using static Serein.Library.Utils.ChannelFlowInterrupt;
namespace Serein.NodeFlow.Env
{
@@ -31,7 +31,7 @@ namespace Serein.NodeFlow.Env
/// <summary>
/// 运行环境
/// </summary>
public class FlowEnvironment : IFlowEnvironment, ISereinIOC
public class FlowEnvironment : IFlowEnvironment, ISereinIOC
{
/// <summary>
/// 节点的命名空间
@@ -47,7 +47,6 @@ namespace Serein.NodeFlow.Env
public FlowEnvironment(UIContextOperation uiContextOperation)
{
this.sereinIOC = new SereinIOC();
this.ChannelFlowInterrupt = new ChannelFlowInterrupt();
this.IsGlobalInterrupt = false;
this.flowStarter = null;
this.sereinIOC.OnIOCMembersChanged += e =>
@@ -244,10 +243,10 @@ namespace Serein.NodeFlow.Env
/// </summary>
public bool IsGlobalInterrupt { get; set; }
/// <summary>
/// 流程中断器
/// </summary>
public ChannelFlowInterrupt ChannelFlowInterrupt { get; set; }
///// <summary>
///// 流程中断器
///// </summary>
//public ChannelFlowInterrupt ChannelFlowInterrupt { get; set; }
/// <summary>
/// <para>单例模式IOC容器内部维护了一个实例字典默认使用类型的FullName作为Key如果以“接口-实现类”的方式注册那么将使用接口类型的FullName作为Key。</para>
@@ -377,7 +376,6 @@ namespace Serein.NodeFlow.Env
/// <returns></returns>
public async Task<bool> StartFlowAsync()
{
ChannelFlowInterrupt?.CancelAllTasks();
flowStarter = new FlowStarter();
var nodes = NodeModels.Values.ToList();
@@ -453,7 +451,7 @@ namespace Serein.NodeFlow.Env
/// <returns></returns>
public async Task<object> InvokeNodeAsync(IDynamicContext context, string nodeGuid)
{
object result = true;
object result = new Unit();
if (this.NodeModels.TryGetValue(nodeGuid, out var model))
{
result = await model.ExecutingAsync(context);
@@ -466,7 +464,6 @@ namespace Serein.NodeFlow.Env
/// </summary>
public Task<bool> ExitFlowAsync()
{
ChannelFlowInterrupt?.CancelAllTasks();
flowStarter?.Exit();
UIContextOperation?.Invoke(() => OnFlowRunComplete?.Invoke(new FlowEventArgs()));
flowStarter = null;
@@ -555,8 +552,11 @@ namespace Serein.NodeFlow.Env
LoadLibrary(dllFilePath); // 加载项目文件时加载对应的程序集
}
_ = LoadNodeInfosAsync(projectData.Nodes.ToList());
SetStartNodeAsync(projectData.StartNode);
_ = Task.Run( async () =>
{
await LoadNodeInfosAsync(projectData.Nodes.ToList());
await SetStartNodeAsync(projectData.StartNode);
});
}
@@ -745,7 +745,7 @@ namespace Serein.NodeFlow.Env
/// </summary>
/// <param name="List<NodeInfo>">节点信息</param>
/// <returns></returns>
public Task LoadNodeInfosAsync(List<NodeInfo> nodeInfos)
public async Task LoadNodeInfosAsync(List<NodeInfo> nodeInfos)
{
#region NodeInfo创建NodeModel
foreach (NodeInfo? nodeInfo in nodeInfos)
@@ -779,7 +779,7 @@ namespace Serein.NodeFlow.Env
nodeModel.LoadInfo(nodeInfo); // 创建节点model
TryAddNode(nodeModel); // 加载项目时将节点加载到环境中
UIContextOperation?.Invoke(() =>
await UIContextOperation.InvokeAsync(() =>
OnNodeCreate?.Invoke(new NodeCreateEventArgs(nodeModel, nodeInfo.Position))); // 添加到UI上
}
#endregion
@@ -798,77 +798,92 @@ namespace Serein.NodeFlow.Env
foreach (NodeInfo nodeInfo in needPlaceNodeInfos)
{
if (NodeModels.TryGetValue(nodeInfo.Guid, out var nodeMoel) &&
if (NodeModels.TryGetValue(nodeInfo.Guid, out var nodeModel) &&
NodeModels.TryGetValue(nodeInfo.ParentNodeGuid, out var containerNode)
&& containerNode is INodeContainer nodeContainer)
{
nodeMoel.ContainerNode = containerNode; // 放置节点
containerNode.ChildrenNode.Add(nodeMoel);
nodeContainer.PlaceNode(nodeMoel);
UIContextOperation?.Invoke(() => OnNodePlace?.Invoke(
new NodePlaceEventArgs(nodeMoel.Guid, containerNode.Guid)));
var result = nodeContainer.PlaceNode(nodeModel);
if (result)
{
await UIContextOperation.InvokeAsync(() => OnNodePlace?.Invoke(
new NodePlaceEventArgs(nodeModel.Guid, containerNode.Guid)));
}
}
}
#endregion
_ = Task.Run(async () =>
#region
foreach (var nodeInfo in nodeInfos)
{
await Task.Delay(100);
#region
foreach (var nodeInfo in nodeInfos)
{
if (!NodeModels.TryGetValue(nodeInfo.Guid, out NodeModelBase? fromNode))
{
// 不存在对应的起始节点
continue;
}
List<(ConnectionInvokeType connectionType, string[] guids)> allToNodes = [(ConnectionInvokeType.IsSucceed,nodeInfo.TrueNodes),
var fromNodeModel = GuidToModel(nodeInfo.Guid);
if (fromNodeModel is null) continue;
List<(ConnectionInvokeType connectionType, string[] guids)> allToNodes = [(ConnectionInvokeType.IsSucceed,nodeInfo.TrueNodes),
(ConnectionInvokeType.IsFail, nodeInfo.FalseNodes),
(ConnectionInvokeType.IsError, nodeInfo.ErrorNodes),
(ConnectionInvokeType.Upstream, nodeInfo.UpstreamNodes)];
List<(ConnectionInvokeType, NodeModelBase[])> fromNodes = allToNodes.Where(info => info.guids.Length > 0)
.Select(info => (info.connectionType,
info.guids.Where(guid => NodeModels.ContainsKey(guid)).Select(guid => NodeModels[guid])
.ToArray()))
.ToList();
// 遍历每种类型的节点分支(四种)
foreach ((ConnectionInvokeType connectionType, NodeModelBase[] toNodes) item in fromNodes)
{
// 遍历当前类型分支的节点(确认连接关系)
foreach (var toNode in item.toNodes)
{
_ = ConnectInvokeOfNode(fromNode, toNode, item.connectionType); // 加载时确定节点间的连接关系
}
}
}
#endregion
#region
foreach (var toNode in NodeModels.Values)
foreach ((ConnectionInvokeType connectionType, string[] toNodeGuids) item in allToNodes)
{
if (toNode.MethodDetails.ParameterDetailss == null)
// 遍历当前类型分支的节点(确认连接关系)
foreach (var toNodeGuid in item.toNodeGuids)
{
continue;
}
for (var i = 0; i < toNode.MethodDetails.ParameterDetailss.Length; i++)
{
var pd = toNode.MethodDetails.ParameterDetailss[i];
if (!string.IsNullOrEmpty(pd.ArgDataSourceNodeGuid)
&& NodeModels.TryGetValue(pd.ArgDataSourceNodeGuid, out var fromNode))
{
_ = ConnectArgSourceOfNodeAsync(fromNode, toNode, pd.ArgDataSourceType, pd.Index);
}
var toNodeModel = GuidToModel(toNodeGuid);
if (toNodeModel is null) continue;
var isSuccessful = ConnectInvokeOfNode(fromNodeModel, toNodeModel, item.connectionType); // 加载时确定节点间的连接关系
}
}
#endregion
});
UIContextOperation?.Invoke(() => OnProjectLoaded?.Invoke(new ProjectLoadedEventArgs()));
return Task.CompletedTask;
//List<(ConnectionInvokeType connectionType, string[] guids)> allToNodes = [(ConnectionInvokeType.IsSucceed,nodeInfo.TrueNodes),
// (ConnectionInvokeType.IsFail, nodeInfo.FalseNodes),
// (ConnectionInvokeType.IsError, nodeInfo.ErrorNodes),
// (ConnectionInvokeType.Upstream, nodeInfo.UpstreamNodes)];
//List<(ConnectionInvokeType, NodeModelBase[])> fromNodes = allToNodes.Where(info => info.guids.Length > 0)
// .Select(info => (info.connectionType,
// info.guids.Where(guid => NodeModels.ContainsKey(guid)).Select(guid => NodeModels[guid])
// .ToArray()))
// .ToList();
// 遍历每种类型的节点分支(四种)
//foreach ((ConnectionInvokeType connectionType, NodeModelBase[] toNodes) item in nodeInfo)
//{
// // 遍历当前类型分支的节点(确认连接关系)
// foreach (var toNode in item.toNodes)
// {
// _ = ConnectInvokeOfNode(fromNode, toNode, item.connectionType); // 加载时确定节点间的连接关系
// }
//}
}
#endregion
#region
foreach (var toNode in NodeModels.Values)
{
if (toNode.MethodDetails.ParameterDetailss == null)
{
continue;
}
for (var i = 0; i < toNode.MethodDetails.ParameterDetailss.Length; i++)
{
var pd = toNode.MethodDetails.ParameterDetailss[i];
if (!string.IsNullOrEmpty(pd.ArgDataSourceNodeGuid)
&& NodeModels.TryGetValue(pd.ArgDataSourceNodeGuid, out var fromNode))
{
_ = ConnectArgSourceOfNodeAsync(fromNode, toNode, pd.ArgDataSourceType, pd.Index);
}
}
}
#endregion
await UIContextOperation.InvokeAsync(() =>
{
UIContextOperation?.Invoke(() => OnProjectLoaded?.Invoke(new ProjectLoadedEventArgs()));
});
return;
}
/// <summary>
@@ -925,24 +940,28 @@ namespace Serein.NodeFlow.Env
public async Task<bool> PlaceNodeToContainerAsync(string nodeGuid, string containerNodeGuid)
{
// 获取目标节点与容器节点
var nodeMoel = GuidToModel(nodeGuid);
if (nodeMoel is null ) return false;
var nodeModel = GuidToModel(nodeGuid);
if (nodeModel is null ) return false;
if(nodeMoel.ContainerNode is INodeContainer tmpContainer)
if(nodeModel.ContainerNode is INodeContainer tmpContainer)
{
SereinEnv.WriteLine(InfoType.WARN, $"节点放置失败,节点[{nodeGuid}]已经放置于容器节点[{((NodeModelBase)tmpContainer).Guid}]");
return false;
}
var containerNode = GuidToModel(containerNodeGuid);
var containerNode = GuidToModel(containerNodeGuid); // 获取容器节点
if (containerNode is not INodeContainer nodeContainer) return false;
nodeMoel.ContainerNode = containerNode; // 放置节点
containerNode.ChildrenNode.Add(nodeMoel);
nodeContainer.PlaceNode(nodeMoel);
OnNodePlace?.Invoke(new NodePlaceEventArgs(nodeGuid, containerNodeGuid)); // 通知UI更改节点放置位置
return true;
var result = nodeContainer.PlaceNode(nodeModel); // 放置在容器节点
if (result)
{
_ = UIContextOperation?.InvokeAsync(() =>
{
OnNodePlace?.Invoke(new NodePlaceEventArgs(nodeGuid, containerNodeGuid)); // 通知UI更改节点放置位置
});
}
return result;
}
/// <summary>
@@ -952,18 +971,24 @@ namespace Serein.NodeFlow.Env
public async Task<bool> TakeOutNodeToContainerAsync(string nodeGuid)
{
// 获取目标节点与容器节点
var nodeMoel = GuidToModel(nodeGuid);
if (nodeMoel is null) return false;
var nodeModel = GuidToModel(nodeGuid);
if (nodeModel is null) return false;
if(nodeMoel.ContainerNode is not INodeContainer nodeContainer)
if(nodeModel.ContainerNode is not INodeContainer nodeContainer)
{
return false;
}
nodeContainer.TakeOutNode(nodeMoel); // 从容器节点取出
nodeMoel.ContainerNode = null; // 取消映射关系
OnNodeTakeOut?.Invoke(new NodeTakeOutEventArgs(nodeGuid)); // 重新放置在画布上
return true;
var result = nodeContainer.TakeOutNode(nodeModel); // 从容器节点取出
if (result)
{
_ = UIContextOperation?.InvokeAsync(() =>
{
OnNodeTakeOut?.Invoke(new NodeTakeOutEventArgs(nodeGuid)); // 重新放置在画布上
});
}
return result;
}
@@ -1000,7 +1025,7 @@ namespace Serein.NodeFlow.Env
remoteNode.Guid,
JunctionOfConnectionType.Invoke,
pCType, // 对应的连接关系
NodeConnectChangeEventArgs.ConnectChangeType.Remote))); // 通知UI
NodeConnectChangeEventArgs.ConnectChangeType.Remove))); // 通知UI
}
}
@@ -1240,149 +1265,6 @@ namespace Serein.NodeFlow.Env
return Task.FromResult(StartNode?.Guid ?? string.Empty);
}
/// <summary>
/// 中断指定节点,并指定中断等级。
/// </summary>
/// <param name="nodeGuid">被中断的目标节点Guid</param>
/// <param name="interruptClass">中断级别</param>
/// <returns>操作是否成功</returns>
public Task<bool> SetNodeInterruptAsync(string nodeGuid, bool isInterrupt)
{
var nodeModel = GuidToModel(nodeGuid);
if (nodeModel is null)
return Task.FromResult(false);
if (!isInterrupt)
{
nodeModel.CancelInterrupt();
}
else if (isInterrupt)
{
nodeModel.DebugSetting.CancelInterruptCallback?.Invoke();
nodeModel.DebugSetting.GetInterruptTask = async () =>
{
TriggerInterrupt(nodeGuid, "", InterruptTriggerEventArgs.InterruptTriggerType.Monitor);
var result = await ChannelFlowInterrupt.GetOrCreateChannelAsync(nodeGuid);
return result;
};
nodeModel.DebugSetting.CancelInterruptCallback = () =>
{
//nodeModel.DebugSetting.IsInterrupt = false;
ChannelFlowInterrupt.TriggerSignal(nodeGuid);
};
}
//nodeModel.DebugSetting.IsInterrupt = true;
if (OperatingSystem.IsWindows())
{
UIContextOperation?.Invoke(() => OnNodeInterruptStateChange?.Invoke(new NodeInterruptStateChangeEventArgs(nodeGuid, isInterrupt)));
}
return Task.FromResult(true);
}
/// <summary>
/// 添加表达式中断
/// </summary>
/// <param name="key">如果是节点传入Guid如果是对象传入类型FullName</param>
/// <param name="expression">合法的条件表达式</param>
/// <returns></returns>
public Task<bool> AddInterruptExpressionAsync(string key, string expression)
{
if (string.IsNullOrEmpty(expression)) return Task.FromResult(false);
if (dictMonitorObjExpInterrupt.TryGetValue(key, out var condition))
{
condition.Clear(); // 暂时
condition.Add(expression);// 暂时
}
else
{
var exps = new List<string>();
exps.Add(expression);
dictMonitorObjExpInterrupt.TryAdd(key, exps);
}
return Task.FromResult(true);
}
/// <summary>
/// 要监视的对象,以及与其关联的表达式
/// </summary>
private ConcurrentDictionary<string, List<string>> dictMonitorObjExpInterrupt = [];
/// <summary>
/// 设置对象的监视状态
/// </summary>
/// <param name="key">如果是节点传入Guid如果是对象传入类型FullName</param>
/// <param name="isMonitor">ture监视对象false取消对象监视</param>
/// <returns></returns>
public void SetMonitorObjState(string key, bool isMonitor)
{
if (string.IsNullOrEmpty(key)) { return; }
var isExist = dictMonitorObjExpInterrupt.ContainsKey(key);
if (isExist)
{
if (!isMonitor) // 对象存在且需要不监视
{
dictMonitorObjExpInterrupt.Remove(key, out _);
}
}
else
{
if (isMonitor) // 对象不存在且需要监视,添加在集合中。
{
dictMonitorObjExpInterrupt.TryAdd(key, new List<string>()); ;
}
}
}
/// <summary>
/// 检查一个对象是否处于监听状态如果是则传出与该对象相关的表达式用于中断如果不是则返回false。
/// </summary>
/// <param name="key"></param>
/// <param name="exps"></param>
/// <returns></returns>
public Task<(bool, string[])> CheckObjMonitorStateAsync(string key)
{
if (string.IsNullOrEmpty(key))
{
var data = (false, Array.Empty<string>());
return Task.FromResult(data);
}
else
{
var isMonitor = dictMonitorObjExpInterrupt.TryGetValue(key, out var exps);
if (exps is null)
{
var data = (isMonitor, Array.Empty<string>());
return Task.FromResult(data);
}
else
{
var data = (isMonitor, exps.ToArray());
return Task.FromResult(data);
}
}
//if (exps is null)
//{
// var data = (isMonitor, Array.Empty<string>());
// return Task.FromResult(data);
//}
//else
//{
// var data = (isMonitor, exps.ToArray());
// return Task.FromResult(data);
//}
}
/// <summary>
/// 启动器调用,运行到某个节点时触发了监视对象的更新(对象预览视图将会自动更新)
/// </summary>
@@ -1406,16 +1288,16 @@ namespace Serein.NodeFlow.Env
}
/// <summary>
/// 环境执行中断
/// </summary>
/// <returns></returns>
public async Task<CancelType> GetOrCreateGlobalInterruptAsync()
{
IsGlobalInterrupt = true;
var result = await ChannelFlowInterrupt.GetOrCreateChannelAsync(EnvName);
return result;
}
///// <summary>
///// 环境执行中断
///// </summary>
///// <returns></returns>
//public async Task InterruptNode()
//{
// IsGlobalInterrupt = true;
// var result = await ChannelFlowInterrupt.GetOrCreateChannelAsync(EnvName);
// return result;
//}
/// <summary>
/// 记录节点更改数据,防止重复更改
@@ -1642,7 +1524,7 @@ namespace Serein.NodeFlow.Env
toNode.Guid,
JunctionOfConnectionType.Invoke,
connectionType,
NodeConnectChangeEventArgs.ConnectChangeType.Remote)));
NodeConnectChangeEventArgs.ConnectChangeType.Remove)));
}
return true;
}
@@ -1670,7 +1552,7 @@ namespace Serein.NodeFlow.Env
JunctionOfConnectionType.Arg,
argIndex,
ConnectionArgSourceType.GetPreviousNodeData,
NodeConnectChangeEventArgs.ConnectChangeType.Remote)));
NodeConnectChangeEventArgs.ConnectChangeType.Remove)));
}
return true;
}

View File

@@ -196,16 +196,7 @@ namespace Serein.NodeFlow.Env
currentFlowEnvironment.ActivateFlipflopNode(nodeGuid);
}
public async Task<bool> AddInterruptExpressionAsync(string key, string expression)
{
return await currentFlowEnvironment.AddInterruptExpressionAsync(key, expression);
}
public async Task<(bool, string[])> CheckObjMonitorStateAsync(string key)
{
return await currentFlowEnvironment.CheckObjMonitorStateAsync(key);
}
/// <summary>
@@ -329,11 +320,7 @@ namespace Serein.NodeFlow.Env
return await currentFlowEnvironment.GetEnvInfoAsync();
}
public async Task<ChannelFlowInterrupt.CancelType> GetOrCreateGlobalInterruptAsync()
{
return await currentFlowEnvironment.GetOrCreateGlobalInterruptAsync();
}
public async Task<SereinProjectData> GetProjectInfoAsync()
{
return await currentFlowEnvironment.GetProjectInfoAsync();
@@ -439,6 +426,24 @@ namespace Serein.NodeFlow.Env
currentFlowEnvironment.WriteLine(type, message, @class);
}
#region MyRegion
#if false
public async Task<bool> AddInterruptExpressionAsync(string key, string expression)
{
return await currentFlowEnvironment.AddInterruptExpressionAsync(key, expression);
}
public async Task<(bool, string[])> CheckObjMonitorStateAsync(string key)
{
return await currentFlowEnvironment.CheckObjMonitorStateAsync(key);
}
public async Task<ChannelFlowInterrupt.CancelType> GetOrCreateGlobalInterruptAsync()
{
return await currentFlowEnvironment.InterruptNode();
}
public void SetMonitorObjState(string key, bool isMonitor)
{
currentFlowEnvironment.SetMonitorObjState(key, isMonitor);
@@ -447,8 +452,10 @@ namespace Serein.NodeFlow.Env
public async Task<bool> SetNodeInterruptAsync(string nodeGuid, bool isInterrupt)
{
return await currentFlowEnvironment.SetNodeInterruptAsync(nodeGuid, isInterrupt);
}
}
#endif
#endregion
public async Task<string> SetStartNodeAsync(string nodeGuid)
{
return await currentFlowEnvironment.SetStartNodeAsync(nodeGuid);

View File

@@ -188,6 +188,27 @@ namespace Serein.NodeFlow.Env
{
_ = remoteFlowEnvironment.InvokeTriggerAsync(msgId, state);
}
/// <summary>
/// 放置节点
/// </summary>
/// <param name="msgId"></param>
/// <param name="state"></param>
[AutoSocketHandle(ThemeValue = EnvMsgTheme.PlaceNode, IsReturnValue = false)]
public void PlaceNode([UseMsgId] string msgId, bool state)
{
_ = remoteFlowEnvironment.InvokeTriggerAsync(msgId, state);
}
/// <summary>
/// 取出节点
/// </summary>
/// <param name="msgId"></param>
/// <param name="state"></param>
[AutoSocketHandle(ThemeValue = EnvMsgTheme.TakeOutNode, IsReturnValue = false)]
public void TakeOutNode([UseMsgId] string msgId, bool state)
{
_ = remoteFlowEnvironment.InvokeTriggerAsync(msgId, state);
}
/// <summary>
/// 创建节点之间的调用关系

View File

@@ -4,6 +4,7 @@ using Serein.Library.Api;
using Serein.Library.Network.WebSocketCommunication;
using Serein.Library.Network.WebSocketCommunication.Handle;
using Serein.Library.Utils;
using System.Diagnostics.CodeAnalysis;
namespace Serein.NodeFlow.Env
{
@@ -267,7 +268,6 @@ namespace Serein.NodeFlow.Env
}
/// <summary>
/// 退出远程环境
/// </summary>
@@ -298,6 +298,7 @@ namespace Serein.NodeFlow.Env
public void LoadDll(string dllPath)
{
}
/// <summary>
/// 移除DLL
/// </summary>
@@ -334,9 +335,30 @@ namespace Serein.NodeFlow.Env
[AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveNode)]
public async Task<object> RemoveNode(string nodeGuid)
{
//var result = environment.RemoveNodeAsync(nodeGuid).GetAwaiter().GetResult();
var result = await environment.RemoveNodeAsync(nodeGuid);
//return result;
return new { state = result };
}
/// <summary>
/// 远程从远程环境移除节点
/// </summary>
/// <param name="nodeGuid"></param>
/// <param name="containerNodeGuid"></param>
/// <exception cref="NotImplementedException"></exception>
[AutoSocketHandle(ThemeValue = EnvMsgTheme.PlaceNode)]
public async Task<object> PlaceNode(string nodeGuid, string containerNodeGuid)
{
var result = await environment.PlaceNodeToContainerAsync(nodeGuid, containerNodeGuid);
return new { state = result };
}
/// <summary>
/// 远程从远程环境移除节点
/// </summary>
/// <param name="nodeGuid"></param>
/// <exception cref="NotImplementedException"></exception>
[AutoSocketHandle(ThemeValue = EnvMsgTheme.TakeOutNode)]
public async Task<object> TakeOutNode(string nodeGuid)
{
var result = await environment.TakeOutNodeToContainerAsync(nodeGuid);
return new { state = result };
}
@@ -528,12 +550,13 @@ namespace Serein.NodeFlow.Env
/// </summary>
/// <param name="nodeGuid"></param>
[AutoSocketHandle(ThemeValue = EnvMsgTheme.SetStartNode)]
public void SetStartNode(string nodeGuid)
public async Task<string> SetStartNode([NotNull]string nodeGuid)
{
environment.SetStartNodeAsync(nodeGuid);
return await environment.SetStartNodeAsync(nodeGuid);
}
#if false
/// <summary>
/// 中断指定节点,并指定中断等级。
@@ -544,10 +567,9 @@ namespace Serein.NodeFlow.Env
[AutoSocketHandle(ThemeValue = EnvMsgTheme.SetNodeInterrupt)]
public async Task<bool> SetNodeInterruptAsync(string nodeGuid, bool isInterrupt)
{
return await this.environment.SetNodeInterruptAsync(nodeGuid, isInterrupt);
return false;
// return await this.environment.SetNodeInterruptAsync(nodeGuid, isInterrupt);
}
@@ -573,7 +595,8 @@ namespace Serein.NodeFlow.Env
public void SetMonitorObjState(string key, bool isMonitor)
{
environment.SetMonitorObjState(key, isMonitor);
}
}
#endif
/// <summary>

View File

@@ -12,8 +12,6 @@ using System.Threading.Channels;
namespace Serein.NodeFlow.Env
{
/// <summary>
/// 远程流程环境
/// </summary>
@@ -638,7 +636,7 @@ namespace Serein.NodeFlow.Env
toNodeGuid,
JunctionOfConnectionType.Invoke,
invokeType,
NodeConnectChangeEventArgs.ConnectChangeType.Remote));
NodeConnectChangeEventArgs.ConnectChangeType.Remove));
});
}
return result;
@@ -667,7 +665,7 @@ namespace Serein.NodeFlow.Env
JunctionOfConnectionType.Arg,
argIndex,
ConnectionArgSourceType.GetPreviousNodeData,
NodeConnectChangeEventArgs.ConnectChangeType.Remote)); // 通知UI
NodeConnectChangeEventArgs.ConnectChangeType.Remove)); // 通知UI
});
}
return result;
@@ -819,7 +817,20 @@ namespace Serein.NodeFlow.Env
});
if (isSuuccess)
{
OnNodePlace?.Invoke(new NodePlaceEventArgs(nodeGuid, containerNodeGuid)); // 通知UI更改节点放置位置
var nodeModel = GuidToModel(nodeGuid); // 获取目标节点
if (nodeModel is null) return false;
var containerNode = GuidToModel(containerNodeGuid); // 获取容器节点
if (containerNode is not INodeContainer nodeContainer) return false;
var result = nodeContainer.PlaceNode(nodeModel);
if (result)
{
// 通知UI更改
UIContextOperation.Invoke(() =>
{
OnNodePlace?.Invoke(new NodePlaceEventArgs(nodeGuid, containerNodeGuid)); // 通知UI更改节点放置位置
});
}
return result;
}
return isSuuccess;
}
@@ -836,7 +847,22 @@ namespace Serein.NodeFlow.Env
});
if (isSuuccess)
{
OnNodeTakeOut?.Invoke(new NodeTakeOutEventArgs(nodeGuid)); // 重新放置在画布上
var nodeModel = GuidToModel(nodeGuid); // 获取目标节点
if (nodeModel is null) return false;
if (nodeModel.ContainerNode is not INodeContainer nodeContainer)
{
return false;
}
var result = nodeContainer.TakeOutNode(nodeModel); // 从容器节点取出
if (result)
{
// 通知UI更改
UIContextOperation.Invoke(() =>
{
OnNodeTakeOut?.Invoke(new NodeTakeOutEventArgs(nodeGuid)); // 重新放置在画布上
});
}
return result;
}
return isSuuccess;
}
@@ -1027,7 +1053,20 @@ namespace Serein.NodeFlow.Env
#region
private NodeModelBase? GuidToModel(string nodeGuid)
{
if (string.IsNullOrEmpty(nodeGuid))
{
//throw new ArgumentNullException("not contains - Guid没有对应节点:" + (nodeGuid));
return null;
}
if (!NodeModels.TryGetValue(nodeGuid, out NodeModelBase? nodeModel) || nodeModel is null)
{
//throw new ArgumentNullException("null - Guid存在对应节点,但节点为null:" + (nodeGuid));
return null;
}
return nodeModel;
}
private bool TryAddNode(NodeModelBase nodeModel)
{
NodeModels[nodeModel.Guid] = nodeModel;
@@ -1190,11 +1229,7 @@ namespace Serein.NodeFlow.Env
return null;
}
public async Task<ChannelFlowInterrupt.CancelType> GetOrCreateGlobalInterruptAsync()
{
this.WriteLine(InfoType.INFO, "远程环境尚未实现的接口GetOrCreateGlobalInterruptAsync");
return ChannelFlowInterrupt.CancelType.Error;
}
public bool TryGetMethodDetailsInfo(string libraryName, string methodName, out MethodDetailsInfo mdInfo)
{

View File

@@ -403,8 +403,8 @@ namespace Serein.NodeFlow
context.SetPreviousNode(nextNodes[i], singleFlipFlopNode);
if (nextNodes[i].DebugSetting.IsInterrupt) // 执行触发前
{
var cancelType = await nextNodes[i].DebugSetting.GetInterruptTask();
await Console.Out.WriteLineAsync($"[{nextNodes[i].MethodDetails.MethodName}]中断已{cancelType},开始执行后继分支");
await nextNodes[i].DebugSetting.GetInterruptTask();
await Console.Out.WriteLineAsync($"[{nextNodes[i].MethodDetails.MethodName}]中断已取消,开始执行后继分支");
}
await nextNodes[i].StartFlowAsync(context); // 启动执行触发器后继分支的节点
}
@@ -421,8 +421,8 @@ namespace Serein.NodeFlow
context.SetPreviousNode(nextNodes[i], singleFlipFlopNode);
if (nextNodes[i].DebugSetting.IsInterrupt) // 执行触发前
{
var cancelType = await nextNodes[i].DebugSetting.GetInterruptTask();
await Console.Out.WriteLineAsync($"[{nextNodes[i].MethodDetails.MethodName}]中断已{cancelType},开始执行后继分支");
await nextNodes[i].DebugSetting.GetInterruptTask();
await Console.Out.WriteLineAsync($"[{nextNodes[i].MethodDetails.MethodName}]中断已取消,开始执行后继分支");
}
await nextNodes[i].StartFlowAsync(context); // 启动执行触发器后继分支的节点
}
@@ -442,7 +442,7 @@ namespace Serein.NodeFlow
catch (Exception ex)
{
SereinEnv.WriteLine(InfoType.ERROR, $"触发器[{singleFlipFlopNode.Guid}]异常。"+ ex.Message);
await Task.Delay(100);
await Task.Delay(1000);
}
}

View File

@@ -14,14 +14,5 @@ namespace Serein.NodeFlow.Model
}
/// <summary>
/// 执行方法
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override Task<object> ExecutingAsync(IDynamicContext context)
{
return base.ExecutingAsync(context);
}
}
}

View File

@@ -1,7 +1,6 @@
using Serein.Library.Api;
using Serein.Library;
using Serein.Library.Utils;
using static Serein.Library.Utils.ChannelFlowInterrupt;
namespace Serein.NodeFlow.Model
{
@@ -28,8 +27,8 @@ namespace Serein.NodeFlow.Model
if (DebugSetting.IsInterrupt) // 执行触发前
{
string guid = this.Guid.ToString();
var cancelType = await this.DebugSetting.GetInterruptTask();
await Console.Out.WriteLineAsync($"[{this.MethodDetails.MethodName}]中断已{cancelType},开始执行后继分支");
await this.DebugSetting.GetInterruptTask();
await Console.Out.WriteLineAsync($"[{this.MethodDetails.MethodName}]中断已取消,开始执行后继分支");
}
#endregion
@@ -40,7 +39,7 @@ namespace Serein.NodeFlow.Model
}
object instance = md.ActingInstance;
var args = await GetParametersAsync(context, this);
var args = await GetParametersAsync(context);
// 因为这里会返回不确定的泛型 IFlipflopContext<TRsult>
// 而我们只需要获取到 State 和 Value返回的数据
// 所以使用 dynamic 类型接收

View File

@@ -23,7 +23,7 @@ namespace Serein.NodeFlow.Model
/// <summary>
/// 表达式
/// </summary>
[PropertyInfo(IsNotification = true, CustomCodeAtStart = "ChangeName(value);")]
[PropertyInfo(IsNotification = true, CustomCodeAtStart = "// ChangeName(value);")]
private string _keyName;
}
@@ -52,42 +52,51 @@ namespace Serein.NodeFlow.Model
private NodeModelBase? DataNode;
public void PlaceNode(NodeModelBase nodeModel)
public bool PlaceNode(NodeModelBase nodeModel)
{
// 全局数据节点只有一个子控件
if (DataNode is not null)
if(DataNode is null)
{
_ = Task.Run(async () =>
{
await this.Env.RemoveNodeAsync(DataNode?.Guid);
DataNode = nodeModel;
});
// 放置节点
nodeModel.ContainerNode = this;
ChildrenNode.Add(nodeModel);
DataNode = nodeModel;
return true;
}
else
{
DataNode = nodeModel;
// 全局数据节点只有一个子控件
return false;
}
}
public void TakeOutAll()
public bool TakeOutNode(NodeModelBase nodeModel)
{
if (ChildrenNode.Contains(nodeModel))
{
ChildrenNode.Remove(nodeModel);
nodeModel.ContainerNode = null;
DataNode = null;
return true;
}
else
{
return false;
}
}
public async void TakeOutAll()
{
foreach (var nodeModel in ChildrenNode)
{
await nodeModel.Env.TakeOutNodeToContainerAsync(nodeModel.Guid);
}
DataNode = null;
}
public void TakeOutNode(NodeModelBase nodeModel)
{
DataNode = null;
}
/// <summary>
/// 设置数据节点
/// </summary>
/// <param name="dataNode"></param>
//public void SetDataNode(NodeModelBase dataNode)
//{
// DataNodeGuid = dataNode.Guid;
//}
private void ChangeName(string newName)
{
if(SereinEnv.GetFlowGlobalData(_keyName) == null)

View File

@@ -140,7 +140,7 @@ namespace Serein.NodeFlow.Model
/// <returns></returns>
public override async Task<object?> ExecutingAsync(IDynamicContext context)
{
var @params = await NodeModelBase.GetParametersAsync(context, this);
var @params = await GetParametersAsync(context);
ScriptFlowApi.Context= context;
context.AddOrUpdate($"{context.Guid}_{this.Guid}_Params", @params[0]); // 后面再改