mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-03 00:00:49 +08:00
修改了很多
This commit is contained in:
@@ -30,21 +30,31 @@
|
||||
/// </summary>
|
||||
public const string SetStartNode = nameof(SetStartNode);
|
||||
/// <summary>
|
||||
/// 尝试连接两个节点
|
||||
/// </summary>
|
||||
public const string ConnectNode = nameof(ConnectNode);
|
||||
/// <summary>
|
||||
/// 尝试创建节点
|
||||
/// </summary>
|
||||
public const string CreateNode = nameof(CreateNode);
|
||||
/// <summary>
|
||||
/// 尝试移除节点之间的连接关系
|
||||
/// </summary>
|
||||
public const string RemoveConnect = nameof(RemoveConnect);
|
||||
/// <summary>
|
||||
/// 尝试移除节点
|
||||
/// </summary>
|
||||
public const string RemoveNode = nameof(RemoveNode);
|
||||
/// <summary>
|
||||
/// 尝试连接两个节点的方法调用关系
|
||||
/// </summary>
|
||||
public const string ConnectInvokeNode = nameof(ConnectInvokeNode);
|
||||
/// <summary>
|
||||
/// 尝试移除节点之间的方法调用关系
|
||||
/// </summary>
|
||||
public const string RemoveInvokeConnect = nameof(RemoveInvokeConnect);
|
||||
|
||||
/// <summary>
|
||||
/// 尝试连接两个节点的参数传递关系
|
||||
/// </summary>
|
||||
public const string ConnectArgSourceNode = nameof(ConnectArgSourceNode);
|
||||
/// <summary>
|
||||
/// 尝试移除节点之间的参数传递关系
|
||||
/// </summary>
|
||||
public const string RemoveArgSourceConnect = nameof(RemoveArgSourceConnect);
|
||||
|
||||
/// <summary>
|
||||
/// 激活一个触发器
|
||||
/// </summary>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Newtonsoft.Json;
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.FlowNode;
|
||||
using Serein.Library.Utils;
|
||||
using Serein.Library.Utils.SereinExpression;
|
||||
using Serein.NodeFlow.Model;
|
||||
@@ -9,6 +10,7 @@ using Serein.NodeFlow.Tool;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using System.Xml.Linq;
|
||||
using static Serein.Library.Utils.ChannelFlowInterrupt;
|
||||
|
||||
@@ -78,9 +80,8 @@ namespace Serein.NodeFlow.Env
|
||||
if (clientMsgManage is null)
|
||||
{
|
||||
clientMsgManage = new MsgControllerOfServer(this);
|
||||
//clientMsgManage = new MsgControllerOfServer(this, "token");
|
||||
}
|
||||
await clientMsgManage.StartRemoteServerAsync(port);
|
||||
_ = clientMsgManage.StartRemoteServerAsync(port);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -346,18 +347,11 @@ namespace Serein.NodeFlow.Env
|
||||
List<MethodDetails> initMethods = [];
|
||||
List<MethodDetails> loadMethods = [];
|
||||
List<MethodDetails> exitMethods = [];
|
||||
//foreach(var mds in MethodDetailss.Values)
|
||||
//{
|
||||
// var initMds = mds.Where(it => it.MethodDynamicType == NodeType.Init);
|
||||
// var loadMds = mds.Where(it => it.MethodDynamicType == NodeType.Loading);
|
||||
// var exitMds = mds.Where(it => it.MethodDynamicType == NodeType.Exit);
|
||||
// initMethods.AddRange(initMds);
|
||||
// loadMethods.AddRange(loadMds);
|
||||
// exitMethods.AddRange(exitMds);
|
||||
//}
|
||||
|
||||
var initMds = MethodDetailss.Values.Where(it => it.MethodDynamicType == NodeType.Init);
|
||||
var loadMds = MethodDetailss.Values.Where(it => it.MethodDynamicType == NodeType.Loading);
|
||||
var exitMds = MethodDetailss.Values.Where(it => it.MethodDynamicType == NodeType.Exit);
|
||||
|
||||
initMethods.AddRange(initMds);
|
||||
loadMethods.AddRange(loadMds);
|
||||
exitMethods.AddRange(exitMds);
|
||||
@@ -418,9 +412,11 @@ namespace Serein.NodeFlow.Env
|
||||
/// <returns></returns>
|
||||
public async Task<object> InvokeNodeAsync(string nodeGuid)
|
||||
{
|
||||
|
||||
|
||||
if(this.NodeModels.TryGetValue(nodeGuid, out var model))
|
||||
{
|
||||
return await model.ExecutingAsync(null);
|
||||
return await model.InvokeAsync(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -435,18 +431,7 @@ namespace Serein.NodeFlow.Env
|
||||
{
|
||||
ChannelFlowInterrupt?.CancelAllTasks();
|
||||
flowStarter?.Exit();
|
||||
|
||||
foreach (var node in NodeModels.Values)
|
||||
{
|
||||
if (node is not null)
|
||||
{
|
||||
node.ReleaseFlowData(); // 退出时释放对象计数
|
||||
}
|
||||
}
|
||||
UIContextOperation?.Invoke(() => OnFlowRunComplete?.Invoke(new FlowEventArgs()));
|
||||
|
||||
|
||||
|
||||
GC.Collect();
|
||||
}
|
||||
|
||||
@@ -489,7 +474,6 @@ namespace Serein.NodeFlow.Env
|
||||
/// 获取当前环境信息(远程连接)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
// [AutoSocketHandle]
|
||||
public async Task<FlowEnvInfo> GetEnvInfoAsync()
|
||||
{
|
||||
Dictionary<NodeLibrary, List<MethodDetailsInfo>> LibraryMds = [];
|
||||
@@ -574,12 +558,6 @@ namespace Serein.NodeFlow.Env
|
||||
{
|
||||
MethodDetailss.TryGetValue(nodeInfo.MethodName, out methodDetails);// 加载项目时尝试获取方法信息
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
var nodeModel = FlowFunc.CreateNode(this, controlType, methodDetails); // 加载项目时创建节点
|
||||
nodeModel.LoadInfo(nodeInfo); // 创建节点model
|
||||
if (nodeModel is null)
|
||||
@@ -588,7 +566,6 @@ namespace Serein.NodeFlow.Env
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
TryAddNode(nodeModel); // 加载项目时将节点加载到环境中
|
||||
if (nodeInfo.ChildNodeGuids?.Length > 0)
|
||||
{
|
||||
@@ -643,6 +620,7 @@ namespace Serein.NodeFlow.Env
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(777);
|
||||
#region 方法调用关系
|
||||
foreach (var nodeInfo in projectData.Nodes)
|
||||
{
|
||||
if (!NodeModels.TryGetValue(nodeInfo.Guid, out NodeModelBase? fromNode))
|
||||
@@ -650,8 +628,6 @@ namespace Serein.NodeFlow.Env
|
||||
// 不存在对应的起始节点
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
List<(ConnectionInvokeType connectionType, string[] guids)> allToNodes = [(ConnectionInvokeType.IsSucceed,nodeInfo.TrueNodes),
|
||||
(ConnectionInvokeType.IsFail, nodeInfo.FalseNodes),
|
||||
(ConnectionInvokeType.IsError, nodeInfo.ErrorNodes),
|
||||
@@ -670,8 +646,24 @@ namespace Serein.NodeFlow.Env
|
||||
{
|
||||
_ = ConnectInvokeOfNode(fromNode, toNode, item.connectionType); // 加载时确定节点间的连接关系
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region 参数调用关系
|
||||
foreach (var toNode in NodeModels.Values)
|
||||
{
|
||||
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))
|
||||
{
|
||||
|
||||
ConnectGerResultOfNode(fromNode, toNode, pd.ArgDataSourceType, pd.Index);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
});
|
||||
|
||||
SetStartNode(projectData.StartNode);
|
||||
@@ -686,7 +678,7 @@ namespace Serein.NodeFlow.Env
|
||||
/// <param name="addres">远程环境地址</param>
|
||||
/// <param name="port">远程环境端口</param>
|
||||
/// <param name="token">密码</param>
|
||||
public async Task<(bool, RemoteEnvControl)> ConnectRemoteEnv(string addres, int port, string token)
|
||||
public async Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres, int port, string token)
|
||||
{
|
||||
if (IsLcR)
|
||||
{
|
||||
@@ -695,7 +687,7 @@ namespace Serein.NodeFlow.Env
|
||||
}
|
||||
// 没有连接远程环境,可以重新连接
|
||||
|
||||
var controlConfiguration = new RemoteEnvControl.ControlConfiguration
|
||||
var controlConfiguration = new RemoteMsgUtil.ControlConfiguration
|
||||
{
|
||||
Addres = addres,
|
||||
Port = port,
|
||||
@@ -704,8 +696,8 @@ namespace Serein.NodeFlow.Env
|
||||
MsgIdJsonKey = FlowEnvironment.MsgIdKey,
|
||||
DataJsonKey = FlowEnvironment.DataKey,
|
||||
};
|
||||
var remoteEnvControl = new RemoteEnvControl(controlConfiguration);
|
||||
var result = await remoteEnvControl.ConnectAsync();
|
||||
var remoteMsgUtil = new RemoteMsgUtil(controlConfiguration);
|
||||
var result = await remoteMsgUtil.ConnectAsync();
|
||||
if (!result)
|
||||
{
|
||||
await Console.Out.WriteLineAsync("连接失败,请检查地址与端口是否正确");
|
||||
@@ -713,7 +705,7 @@ namespace Serein.NodeFlow.Env
|
||||
}
|
||||
await Console.Out.WriteLineAsync("连接成功,开始验证Token");
|
||||
IsLcR = true;
|
||||
return (true, remoteEnvControl);
|
||||
return (true, remoteMsgUtil);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -908,19 +900,18 @@ namespace Serein.NodeFlow.Env
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接节点
|
||||
/// 连接节点,创建方法调用关系
|
||||
/// </summary>
|
||||
/// <param name="fromNodeGuid">起始节点</param>
|
||||
/// <param name="toNodeGuid">目标节点</param>
|
||||
/// <param name="fromNodeJunctionType">起始节点控制点</param>
|
||||
/// <param name="toNodeJunctionType">目标节点控制点</param>
|
||||
/// <param name="connectionType">连接关系</param>
|
||||
public async Task<bool> ConnectNodeAsync(string fromNodeGuid,
|
||||
/// <param name="invokeType">连接关系</param>
|
||||
public async Task<bool> ConnectInvokeNodeAsync(string fromNodeGuid,
|
||||
string toNodeGuid,
|
||||
JunctionType fromNodeJunctionType,
|
||||
JunctionType toNodeJunctionType,
|
||||
ConnectionInvokeType connectionType,
|
||||
int argIndex)
|
||||
ConnectionInvokeType invokeType)
|
||||
{
|
||||
|
||||
// 获取起始节点与目标节点
|
||||
@@ -943,22 +934,43 @@ namespace Serein.NodeFlow.Env
|
||||
(fromNode, toNode) = (toNode, fromNode);
|
||||
}
|
||||
// 从起始节点“下一个方法”控制点,连接到目标节点“方法调用”控制点
|
||||
state = ConnectInvokeOfNode(fromNode, toNode, connectionType); // 本地环境进行连接
|
||||
state = ConnectInvokeOfNode(fromNode, toNode, invokeType); // 本地环境进行连接
|
||||
}
|
||||
else if (type == JunctionOfConnectionType.Arg)
|
||||
return state;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建节点之间的参数来源关系
|
||||
/// </summary>
|
||||
/// <param name="fromNodeGuid">起始节点</param>
|
||||
/// <param name="toNodeGuid">目标节点</param>
|
||||
/// <param name="fromNodeJunctionType">起始节点控制点(result控制点)</param>
|
||||
/// <param name="toNodeJunctionType">目标节点控制点(argData控制点)</param>
|
||||
/// <param name="argIndex">目标节点的第几个参数</param>
|
||||
/// <param name="connectionArgSourceType">调用目标节点对应方法时,对应参数来源类型</param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> ConnectArgSourceNodeAsync(string fromNodeGuid,
|
||||
string toNodeGuid,
|
||||
JunctionType fromNodeJunctionType,
|
||||
JunctionType toNodeJunctionType,
|
||||
ConnectionArgSourceType connectionArgSourceType,
|
||||
int argIndex)
|
||||
{
|
||||
|
||||
// 获取起始节点与目标节点
|
||||
var fromNode = GuidToModel(fromNodeGuid);
|
||||
var toNode = GuidToModel(toNodeGuid);
|
||||
if (fromNode is null || toNode is null) return false;
|
||||
(var type, var state) = CheckConnect(fromNode, toNode, fromNodeJunctionType, toNodeJunctionType);
|
||||
if (!state)
|
||||
{
|
||||
ConnectionArgSourceType connectionArgSourceType;
|
||||
Console.WriteLine("出现非预期的连接行为");
|
||||
return false; // 出现不符预期的连接行为,忽略此次连接行为
|
||||
}
|
||||
|
||||
if (fromNode.Guid.Equals(toNode.Guid))
|
||||
{
|
||||
connectionArgSourceType = ConnectionArgSourceType.GetPreviousNodeData;
|
||||
}
|
||||
else
|
||||
{
|
||||
connectionArgSourceType = ConnectionArgSourceType.GetOtherNodeData;
|
||||
}
|
||||
|
||||
// (连接自身的情况下)从上一个节点“返回值”控制点,连接到目标节点“方法入参”控制点
|
||||
if (type == JunctionOfConnectionType.Arg)
|
||||
{
|
||||
// 从起始节点“返回值”控制点,连接到目标节点“方法入参”控制点
|
||||
if (fromNodeJunctionType == JunctionType.ArgData)
|
||||
{
|
||||
@@ -966,32 +978,48 @@ namespace Serein.NodeFlow.Env
|
||||
(fromNode, toNode) = (toNode, fromNode);
|
||||
}
|
||||
|
||||
|
||||
// 确定方法入参关系
|
||||
state = ConnectGerResultOfNode(fromNode, toNode, connectionArgSourceType, argIndex); // 本地环境进行连接
|
||||
}
|
||||
|
||||
return state;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除连接关系
|
||||
/// 移除连接节点之间方法调用的关系
|
||||
/// </summary>
|
||||
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||
/// <param name="connectionType">连接关系</param>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public async Task<bool> RemoveConnectAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
|
||||
public async Task<bool> RemoveConnectInvokeAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
|
||||
{
|
||||
// 获取起始节点与目标节点
|
||||
var fromNode = GuidToModel(fromNodeGuid);
|
||||
var toNode = GuidToModel(toNodeGuid);
|
||||
if (fromNode is null || toNode is null) return false;
|
||||
|
||||
var result = await RemoteConnectAsync(fromNode, toNode, connectionType);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除连接节点之间参数传递的关系
|
||||
/// </summary>
|
||||
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||
/// <param name="argIndex">连接到第几个参数</param>
|
||||
public async Task<bool> RemoveConnectArgSourceAsync(string fromNodeGuid, string toNodeGuid, int argIndex)
|
||||
{
|
||||
// 获取起始节点与目标节点
|
||||
var fromNode = GuidToModel(fromNodeGuid);
|
||||
var toNode = GuidToModel(toNodeGuid);
|
||||
if (fromNode is null || toNode is null) return false;
|
||||
var result = await RemoteConnectAsync(fromNode, toNode, argIndex);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取方法描述
|
||||
/// </summary>
|
||||
@@ -1077,41 +1105,39 @@ namespace Serein.NodeFlow.Env
|
||||
/// <param name="nodeGuid">被中断的目标节点Guid</param>
|
||||
/// <param name="interruptClass">中断级别</param>
|
||||
/// <returns>操作是否成功</returns>
|
||||
public Task<bool> SetNodeInterruptAsync(string nodeGuid, InterruptClass interruptClass)
|
||||
public Task<bool> SetNodeInterruptAsync(string nodeGuid, bool isInterrupt)
|
||||
{
|
||||
|
||||
|
||||
var nodeModel = GuidToModel(nodeGuid);
|
||||
if (nodeModel is null)
|
||||
return Task.FromResult(false);
|
||||
if (interruptClass == InterruptClass.None)
|
||||
if (!isInterrupt)
|
||||
{
|
||||
nodeModel.CancelInterrupt();
|
||||
}
|
||||
else if (interruptClass == InterruptClass.Branch)
|
||||
else if (isInterrupt)
|
||||
{
|
||||
nodeModel.DebugSetting.CancelInterruptCallback?.Invoke();
|
||||
nodeModel.DebugSetting.GetInterruptTask = async () =>
|
||||
{
|
||||
TriggerInterrupt(nodeGuid, "", InterruptTriggerEventArgs.InterruptTriggerType.Monitor);
|
||||
var result = await ChannelFlowInterrupt.GetOrCreateChannelAsync(nodeGuid);
|
||||
var result = await ChannelFlowInterrupt.GetOrCreateChannelAsync(nodeGuid);
|
||||
return result;
|
||||
};
|
||||
nodeModel.DebugSetting.CancelInterruptCallback = () =>
|
||||
{
|
||||
//nodeModel.DebugSetting.IsInterrupt = false;
|
||||
ChannelFlowInterrupt.TriggerSignal(nodeGuid);
|
||||
};
|
||||
|
||||
}
|
||||
else if (interruptClass == InterruptClass.Global) // 全局……做不了omg
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
nodeModel.DebugSetting.InterruptClass = interruptClass;
|
||||
|
||||
//nodeModel.DebugSetting.IsInterrupt = true;
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
|
||||
UIContextOperation?.Invoke(() => OnNodeInterruptStateChange?.Invoke(new NodeInterruptStateChangeEventArgs(nodeGuid, interruptClass)));
|
||||
UIContextOperation?.Invoke(() => OnNodeInterruptStateChange?.Invoke(new NodeInterruptStateChangeEventArgs(nodeGuid, isInterrupt)));
|
||||
}
|
||||
|
||||
return Task.FromResult(true);
|
||||
@@ -1311,10 +1337,6 @@ namespace Serein.NodeFlow.Env
|
||||
|
||||
#region 私有方法
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 加载指定路径的DLL文件
|
||||
/// </summary>
|
||||
@@ -1375,11 +1397,31 @@ namespace Serein.NodeFlow.Env
|
||||
connectionType,
|
||||
NodeConnectChangeEventArgs.ConnectChangeType.Remote)));
|
||||
}
|
||||
//else if (OperatingSystem.IsLinux())
|
||||
//{
|
||||
|
||||
//}
|
||||
return true;
|
||||
}
|
||||
/// <summary>
|
||||
/// 移除连接关系
|
||||
/// </summary>
|
||||
/// <param name="fromNodeGuid">起始节点Model</param>
|
||||
/// <param name="toNodeGuid">目标节点Model</param>
|
||||
/// <param name="connectionType">连接关系</param>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
private async Task<bool> RemoteConnectAsync(NodeModelBase fromNode, NodeModelBase toNode, int argIndex)
|
||||
{
|
||||
|
||||
toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceNodeGuid = null;
|
||||
toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData; // 恢复默认值
|
||||
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
await UIContextOperation.InvokeAsync(() => OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(
|
||||
fromNode.Guid,
|
||||
toNode.Guid,
|
||||
JunctionOfConnectionType.Arg,
|
||||
argIndex,
|
||||
ConnectionArgSourceType.GetPreviousNodeData,
|
||||
NodeConnectChangeEventArgs.ConnectChangeType.Remote)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1479,13 +1521,10 @@ namespace Serein.NodeFlow.Env
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 创建节点
|
||||
/// </summary>
|
||||
/// <param name="nodeBase"></param>
|
||||
|
||||
private bool TryAddNode(NodeModelBase nodeModel)
|
||||
{
|
||||
nodeModel.Guid ??= Guid.NewGuid().ToString();
|
||||
@@ -1503,10 +1542,6 @@ namespace Serein.NodeFlow.Env
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 检查连接
|
||||
/// </summary>
|
||||
@@ -1530,12 +1565,12 @@ namespace Serein.NodeFlow.Env
|
||||
type = JunctionOfConnectionType.Invoke;
|
||||
state = true;
|
||||
}
|
||||
else if (toNodeJunctionType == JunctionType.ArgData && fromNode.Guid.Equals(toNode.Guid))
|
||||
{
|
||||
// “方法执行”控制点拖拽到“方法入参”控制点,且是同一个节点,则添加获取参数关系,表示生成入参参数时自动从该节点的上一节点获取flowdata
|
||||
type = JunctionOfConnectionType.Arg;
|
||||
state = true;
|
||||
}
|
||||
//else if (toNodeJunctionType == JunctionType.ArgData && fromNode.Guid.Equals(toNode.Guid))
|
||||
//{
|
||||
// // “方法执行”控制点拖拽到“方法入参”控制点,且是同一个节点,则添加获取参数关系,表示生成入参参数时自动从该节点的上一节点获取flowdata
|
||||
// type = JunctionOfConnectionType.Arg;
|
||||
// state = true;
|
||||
//}
|
||||
}
|
||||
else if (fromNodeJunctionType == JunctionType.NextStep && !fromNode.Guid.Equals(toNode.Guid))
|
||||
{
|
||||
@@ -1548,12 +1583,12 @@ namespace Serein.NodeFlow.Env
|
||||
}
|
||||
else if (fromNodeJunctionType == JunctionType.ArgData)
|
||||
{
|
||||
if (toNodeJunctionType == JunctionType.Execute && fromNode.Guid.Equals(toNode.Guid)) // 添加获取参数关系
|
||||
{
|
||||
// “方法入参”控制点拖拽到“方法执行”控制点,且是同一个节点,则添加获取参数关系,生成入参参数时自动从该节点的上一节点获取flowdata
|
||||
type = JunctionOfConnectionType.Arg;
|
||||
state = true;
|
||||
}
|
||||
//if (toNodeJunctionType == JunctionType.Execute && fromNode.Guid.Equals(toNode.Guid)) // 添加获取参数关系
|
||||
//{
|
||||
// // “方法入参”控制点拖拽到“方法执行”控制点,且是同一个节点,则添加获取参数关系,生成入参参数时自动从该节点的上一节点获取flowdata
|
||||
// type = JunctionOfConnectionType.Arg;
|
||||
// state = true;
|
||||
//}
|
||||
if(toNodeJunctionType == JunctionType.ReturnData && !fromNode.Guid.Equals(toNode.Guid))
|
||||
{
|
||||
// “”控制点拖拽到“方法返回值”控制点,且不是同一个节点,添加获取参数关系,生成参数时从目标节点获取flowdata
|
||||
@@ -1574,14 +1609,13 @@ namespace Serein.NodeFlow.Env
|
||||
return (type,state);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 连接节点
|
||||
/// </summary>
|
||||
/// <param name="fromNode">起始节点</param>
|
||||
/// <param name="toNode">目标节点</param>
|
||||
/// <param name="connectionType">连接关系</param>
|
||||
private bool ConnectInvokeOfNode(NodeModelBase fromNode, NodeModelBase toNode, ConnectionInvokeType connectionType)
|
||||
/// <param name="invokeType">连接关系</param>
|
||||
private bool ConnectInvokeOfNode(NodeModelBase fromNode, NodeModelBase toNode, ConnectionInvokeType invokeType)
|
||||
{
|
||||
if (fromNode is null || toNode is null || fromNode == toNode)
|
||||
{
|
||||
@@ -1634,17 +1668,19 @@ namespace Serein.NodeFlow.Env
|
||||
}
|
||||
if (isPass)
|
||||
{
|
||||
fromNode.SuccessorNodes[connectionType].Add(toNode); // 添加到起始节点的子分支
|
||||
toNode.PreviousNodes[connectionType].Add(fromNode); // 添加到目标节点的父分支
|
||||
|
||||
fromNode.SuccessorNodes[invokeType].Add(toNode); // 添加到起始节点的子分支
|
||||
toNode.PreviousNodes[invokeType].Add(fromNode); // 添加到目标节点的父分支
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
|
||||
UIContextOperation?.Invoke(() =>
|
||||
OnNodeConnectChange?.Invoke(
|
||||
new NodeConnectChangeEventArgs(
|
||||
fromNode.Guid, // 从哪个节点开始
|
||||
toNode.Guid, // 连接到那个节点
|
||||
JunctionOfConnectionType.Invoke,
|
||||
connectionType, // 连接线的样式类型
|
||||
invokeType, // 连接线的样式类型
|
||||
NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接
|
||||
))); // 通知UI
|
||||
}
|
||||
@@ -1668,8 +1704,13 @@ namespace Serein.NodeFlow.Env
|
||||
/// <param name="connectionArgSourceType"></param>
|
||||
/// <param name="argIndex"></param>
|
||||
/// <returns></returns>
|
||||
private bool ConnectGerResultOfNode(NodeModelBase fromNode, NodeModelBase toNode, ConnectionArgSourceType connectionArgSourceType,int argIndex)
|
||||
private bool ConnectGerResultOfNode(NodeModelBase fromNode,
|
||||
NodeModelBase toNode,
|
||||
ConnectionArgSourceType connectionArgSourceType,
|
||||
int argIndex)
|
||||
{
|
||||
toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceNodeGuid = fromNode.Guid;
|
||||
toNode.MethodDetails.ParameterDetailss[argIndex].ArgDataSourceType = connectionArgSourceType;
|
||||
UIContextOperation?.Invoke(() =>
|
||||
OnNodeConnectChange?.Invoke(
|
||||
new NodeConnectChangeEventArgs(
|
||||
@@ -1680,7 +1721,7 @@ namespace Serein.NodeFlow.Env
|
||||
connectionArgSourceType,
|
||||
NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接
|
||||
))); // 通知UI
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.FlowNode;
|
||||
using Serein.Library.Utils;
|
||||
|
||||
namespace Serein.NodeFlow.Env
|
||||
@@ -33,22 +34,22 @@ namespace Serein.NodeFlow.Env
|
||||
private IFlowEnvironment currentFlowEnvironment;
|
||||
|
||||
|
||||
private int _flag = 0; // 使用原子自增代替锁
|
||||
private int _loadingProjectFlag = 0; // 使用原子自增代替锁
|
||||
/// <summary>
|
||||
/// 传入false时,将停止数据通知。传入true时,
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public void SetFlag(bool value)
|
||||
public void SetProjectLoadingFlag(bool value)
|
||||
{
|
||||
Interlocked.Exchange(ref _flag, value ? 1 : 0);
|
||||
Interlocked.Exchange(ref _loadingProjectFlag, value ? 1 : 0);
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// 判断是否正在加载项目
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsFlagSet()
|
||||
public bool IsLoadingProject()
|
||||
{
|
||||
return Interlocked.CompareExchange(ref _flag, 1, 1) == 1;
|
||||
return Interlocked.CompareExchange(ref _loadingProjectFlag, 1, 1) == 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -180,34 +181,69 @@ namespace Serein.NodeFlow.Env
|
||||
currentFlowEnvironment.ClearAll();
|
||||
}
|
||||
|
||||
public async Task<bool> ConnectNodeAsync(string fromNodeGuid,
|
||||
/// <summary>
|
||||
/// 在两个节点之间创建连接关系
|
||||
/// </summary>
|
||||
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||
/// <param name="fromNodeJunctionType">起始节点控制点</param>
|
||||
/// <param name="toNodeJunctionType">目标节点控制点</param>
|
||||
/// <param name="invokeType">决定了方法执行后的后继行为</param>
|
||||
public async Task<bool> ConnectInvokeNodeAsync(string fromNodeGuid,
|
||||
string toNodeGuid,
|
||||
JunctionType fromNodeJunctionType,
|
||||
JunctionType toNodeJunctionType,
|
||||
ConnectionInvokeType connectionType,
|
||||
int argIndex)
|
||||
ConnectionInvokeType invokeType)
|
||||
{
|
||||
return await currentFlowEnvironment.ConnectNodeAsync(fromNodeGuid, toNodeGuid, fromNodeJunctionType, toNodeJunctionType, connectionType, argIndex);
|
||||
return await currentFlowEnvironment.ConnectInvokeNodeAsync(fromNodeGuid, toNodeGuid, fromNodeJunctionType, toNodeJunctionType, invokeType);
|
||||
}
|
||||
|
||||
public async Task<(bool, RemoteEnvControl)> ConnectRemoteEnv(string addres, int port, string token)
|
||||
|
||||
/// <summary>
|
||||
/// 在两个节点之间创建连接关系
|
||||
/// </summary>
|
||||
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||
/// <param name="fromNodeJunctionType">起始节点控制点</param>
|
||||
/// <param name="toNodeJunctionType">目标节点控制点</param>
|
||||
/// <param name="argSourceType">决定了方法参数来源</param>
|
||||
/// <param name="argIndex">设置第几个参数</param>
|
||||
public async Task<bool> ConnectArgSourceNodeAsync(string fromNodeGuid,
|
||||
string toNodeGuid,
|
||||
JunctionType fromNodeJunctionType,
|
||||
JunctionType toNodeJunctionType,
|
||||
ConnectionArgSourceType argSourceType,
|
||||
int argIndex)
|
||||
{
|
||||
return await currentFlowEnvironment.ConnectArgSourceNodeAsync(fromNodeGuid, toNodeGuid, fromNodeJunctionType, toNodeJunctionType, argSourceType, argIndex);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 连接远程环境并自动切换环境
|
||||
/// </summary>
|
||||
/// <param name="addres"></param>
|
||||
/// <param name="port"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres, int port, string token)
|
||||
{
|
||||
// 连接成功,切换远程环境
|
||||
(var isConnect, var remoteEnvControl) = await currentFlowEnvironment.ConnectRemoteEnv(addres, port, token);
|
||||
(var isConnect, var remoteMsgUtil) = await currentFlowEnvironment.ConnectRemoteEnv(addres, port, token);
|
||||
if (isConnect)
|
||||
{
|
||||
|
||||
remoteFlowEnvironment ??= new RemoteFlowEnvironment(remoteEnvControl, this.UIContextOperation);
|
||||
remoteFlowEnvironment ??= new RemoteFlowEnvironment(remoteMsgUtil, this.UIContextOperation);
|
||||
currentFlowEnvironment = remoteFlowEnvironment;
|
||||
}
|
||||
return (isConnect, remoteEnvControl);
|
||||
return (isConnect, remoteMsgUtil);
|
||||
}
|
||||
|
||||
public async Task<NodeInfo> CreateNodeAsync(NodeControlType nodeBase, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null)
|
||||
{
|
||||
SetFlag(false);
|
||||
SetProjectLoadingFlag(false);
|
||||
var result = await currentFlowEnvironment.CreateNodeAsync(nodeBase, position, methodDetailsInfo); // 装饰器调用
|
||||
SetFlag(true);
|
||||
SetProjectLoadingFlag(true);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -249,9 +285,9 @@ namespace Serein.NodeFlow.Env
|
||||
public void LoadProject(FlowEnvInfo flowEnvInfo, string filePath)
|
||||
{
|
||||
if (flowEnvInfo is null) return;
|
||||
SetFlag(false);
|
||||
SetProjectLoadingFlag(false);
|
||||
currentFlowEnvironment.LoadProject(flowEnvInfo, filePath);
|
||||
SetFlag(true);
|
||||
SetProjectLoadingFlag(true);
|
||||
}
|
||||
|
||||
public void MonitorObjectNotification(string nodeGuid, object monitorData, MonitorObjectEventArgs.ObjSourceType sourceType)
|
||||
@@ -275,9 +311,21 @@ namespace Serein.NodeFlow.Env
|
||||
return currentFlowEnvironment.RemoteDll(assemblyFullName);
|
||||
}
|
||||
|
||||
public async Task<bool> RemoveConnectAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
|
||||
public async Task<bool> RemoveConnectInvokeAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
|
||||
{
|
||||
return await currentFlowEnvironment.RemoveConnectAsync(fromNodeGuid, toNodeGuid, connectionType);
|
||||
return await currentFlowEnvironment.RemoveConnectInvokeAsync(fromNodeGuid, toNodeGuid, connectionType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除连接节点之间参数传递的关系
|
||||
/// </summary>
|
||||
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||
/// <param name="argIndex">连接到第几个参数</param>
|
||||
/// <param name="connectionArgSourceType">参数来源类型</param>
|
||||
public async Task<bool> RemoveConnectArgSourceAsync(string fromNodeGuid, string toNodeGuid, int argIndex)
|
||||
{
|
||||
return await currentFlowEnvironment.RemoveConnectArgSourceAsync(fromNodeGuid, toNodeGuid, argIndex);
|
||||
}
|
||||
|
||||
public async Task<bool> RemoveNodeAsync(string nodeGuid)
|
||||
@@ -296,9 +344,9 @@ namespace Serein.NodeFlow.Env
|
||||
currentFlowEnvironment.SetMonitorObjState(key, isMonitor);
|
||||
}
|
||||
|
||||
public async Task<bool> SetNodeInterruptAsync(string nodeGuid, InterruptClass interruptClass)
|
||||
public async Task<bool> SetNodeInterruptAsync(string nodeGuid, bool isInterrupt)
|
||||
{
|
||||
return await currentFlowEnvironment.SetNodeInterruptAsync(nodeGuid, interruptClass);
|
||||
return await currentFlowEnvironment.SetNodeInterruptAsync(nodeGuid, isInterrupt);
|
||||
}
|
||||
|
||||
public void SetStartNode(string nodeGuid)
|
||||
@@ -359,11 +407,11 @@ namespace Serein.NodeFlow.Env
|
||||
|
||||
public async Task NotificationNodeValueChangeAsync(string nodeGuid, string path, object value)
|
||||
{
|
||||
if (!IsFlagSet())
|
||||
if (!IsLoadingProject())
|
||||
{
|
||||
return;
|
||||
}
|
||||
await currentFlowEnvironment.NotificationNodeValueChangeAsync(nodeGuid, path, value);
|
||||
await currentFlowEnvironment.NotificationNodeValueChangeAsync(nodeGuid, path, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
using Serein.Library;
|
||||
using Newtonsoft.Json;
|
||||
using Serein.Library;
|
||||
using Serein.Library.Network.WebSocketCommunication;
|
||||
using Serein.Library.Network.WebSocketCommunication.Handle;
|
||||
using Serein.Library.Utils;
|
||||
|
||||
namespace Serein.NodeFlow.Env
|
||||
{
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 客户端的消息管理(用于处理服务端的响应)
|
||||
/// </summary>
|
||||
@@ -28,6 +26,14 @@ namespace Serein.NodeFlow.Env
|
||||
this.remoteFlowEnvironment = remoteFlowEnvironment;
|
||||
SendCommandFunc = func;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理需要返回的消息
|
||||
/// </summary>
|
||||
/// <param name="msgId"></param>
|
||||
/// <param name="theme"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
private async Task SendCommandAsync(string msgId, string theme, object? data)
|
||||
{
|
||||
await SendCommandFunc.Invoke(msgId, theme, data);
|
||||
@@ -40,15 +46,12 @@ namespace Serein.NodeFlow.Env
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException">超时触发</exception>
|
||||
public async Task SendAsync(string signal, object? data = null, int overtimeInMs = 100)
|
||||
public async Task SendAsync(string theme, object? data = null, int overtimeInMs = 100)
|
||||
{
|
||||
//Console.WriteLine($"指令[{signal}],value:{JsonConvert.SerializeObject(sendData)}");
|
||||
if (!DebounceHelper.CanExecute(signal, overtimeInMs))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var msgId = MsgIdHelper.GenerateId().ToString();
|
||||
await SendCommandAsync(msgId, signal, data);
|
||||
Console.WriteLine($"[{msgId}] => {theme}");
|
||||
await SendCommandAsync(msgId, theme, data); // 客户端发送消息
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -58,33 +61,13 @@ namespace Serein.NodeFlow.Env
|
||||
/// <exception cref="NotImplementedException">超时触发</exception>
|
||||
public async Task<TResult> SendAndWaitDataAsync<TResult>(string theme, object? data = null, int overtimeInMs = 50)
|
||||
{
|
||||
//Console.WriteLine($"指令[{signal}],value:{JsonConvert.SerializeObject(sendData)}");
|
||||
|
||||
var msgId = MsgIdHelper.GenerateId().ToString();
|
||||
_ = SendCommandAsync(msgId, theme, data);
|
||||
//_ = Task.Run(async () =>
|
||||
//{
|
||||
// await Task.Delay(500);
|
||||
//});
|
||||
await SendCommandAsync(msgId, theme, data); // 客户端发送消息
|
||||
return await remoteFlowEnvironment.WaitData<TResult>(msgId);
|
||||
|
||||
//if (DebounceHelper.CanExecute(signal, overtimeInMs))
|
||||
//{
|
||||
// _ = SendCommandAsync.Invoke(signal, sendData);
|
||||
// return await remoteFlowEnvironment.WaitData<TResult>(signal);
|
||||
|
||||
// //(var type, var result) = await remoteFlowEnvironment.WaitDataWithTimeoutAsync<TResult>(signal, TimeSpan.FromSeconds(150));
|
||||
// //if (type == TriggerType.Overtime)
|
||||
// //{
|
||||
// // throw new NotImplementedException("超时触发");
|
||||
// //}
|
||||
// //else
|
||||
// //{
|
||||
// // return result;
|
||||
// //}
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// return default;
|
||||
//}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -139,15 +122,26 @@ namespace Serein.NodeFlow.Env
|
||||
remoteFlowEnvironment.TriggerSignal(msgId, state);
|
||||
}
|
||||
|
||||
|
||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.ConnectNode)]
|
||||
public void ConnectNode([UseMsgId] string msgId, bool state)
|
||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.ConnectInvokeNode)]
|
||||
public void ConnectInvokeNode([UseMsgId] string msgId, bool state)
|
||||
{
|
||||
remoteFlowEnvironment.TriggerSignal(msgId, state);
|
||||
}
|
||||
|
||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveConnect)]
|
||||
public void RemoveConnect([UseMsgId] string msgId, bool state)
|
||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveInvokeConnect)]
|
||||
public void RemoveInvokeConnect([UseMsgId] string msgId, bool state)
|
||||
{
|
||||
remoteFlowEnvironment.TriggerSignal(msgId, state);
|
||||
}
|
||||
|
||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.ConnectArgSourceNode)]
|
||||
public void ConnectArgSourceNode([UseMsgId] string msgId, bool state)
|
||||
{
|
||||
remoteFlowEnvironment.TriggerSignal(msgId, state);
|
||||
}
|
||||
|
||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveArgSourceConnect)]
|
||||
public void RemoveArgSourceConnect([UseMsgId] string msgId, bool state)
|
||||
{
|
||||
remoteFlowEnvironment.TriggerSignal(msgId, state);
|
||||
}
|
||||
|
||||
@@ -227,7 +227,8 @@ namespace Serein.NodeFlow.Env
|
||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.GetEnvInfo)]
|
||||
private async Task<FlowEnvInfo> GetEnvInfoAsync()
|
||||
{
|
||||
return await environment.GetEnvInfoAsync();
|
||||
var envInfo = await environment.GetEnvInfoAsync();
|
||||
return envInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -248,7 +249,7 @@ namespace Serein.NodeFlow.Env
|
||||
/// <param name="port">远程环境端口</param>
|
||||
/// <param name="token">密码</param>
|
||||
// [AutoSocketHandle]
|
||||
public async Task<(bool, RemoteEnvControl)> ConnectRemoteEnv(string addres, int port, string token)
|
||||
public async Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres, int port, string token)
|
||||
{
|
||||
return await environment.ConnectRemoteEnv(addres, port, token);
|
||||
}
|
||||
@@ -314,7 +315,7 @@ namespace Serein.NodeFlow.Env
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从远程环境移除节点
|
||||
/// 远程从远程环境移除节点
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid"></param>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
@@ -324,56 +325,178 @@ namespace Serein.NodeFlow.Env
|
||||
//var result = environment.RemoveNodeAsync(nodeGuid).GetAwaiter().GetResult();
|
||||
var result = await environment.RemoveNodeAsync(nodeGuid);
|
||||
//return result;
|
||||
return new
|
||||
{
|
||||
state = result
|
||||
};
|
||||
return new { state = result };
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 连接节点
|
||||
/// 远程连接节点的方法调用关系
|
||||
/// </summary>
|
||||
/// <param name="fromNodeGuid">起始节点</param>
|
||||
/// <param name="toNodeGuid">目标节点</param>
|
||||
/// <param name="connectionType">连接关系</param>
|
||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.ConnectNode)]
|
||||
public async Task<object> ConnectNode(string fromNodeGuid, string toNodeGuid, string connectionType)
|
||||
/// <param name="fromJunctionType">起始节点控制点</param>
|
||||
/// <param name="toJunctionType">目标节点控制点</param>
|
||||
/// <param name="invokeType">连接关系</param>
|
||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.ConnectInvokeNode)]
|
||||
public async Task<object> ConnectInvokeNode(string fromNodeGuid,
|
||||
string toNodeGuid,
|
||||
string fromJunctionType,
|
||||
string toJunctionType,
|
||||
string invokeType)
|
||||
{
|
||||
if (!EnumHelper.TryConvertEnum<ConnectionInvokeType>(connectionType, out var tmpConnectionType))
|
||||
if (!EnumHelper.TryConvertEnum<ConnectionInvokeType>(invokeType, out var tmpConnectionType))
|
||||
{
|
||||
return new
|
||||
{
|
||||
state = false
|
||||
};
|
||||
return new{ state = false};
|
||||
}
|
||||
//environment.ConnectNodeAsync(fromNodeGuid, toNodeGuid, tmpConnectionType);
|
||||
var result = await environment.ConnectNodeAsync(fromNodeGuid, toNodeGuid,0,0, tmpConnectionType,0);
|
||||
return new
|
||||
if (!EnumHelper.TryConvertEnum<JunctionType>(fromJunctionType, out var tmpFromJunctionType))
|
||||
{
|
||||
state = result
|
||||
};
|
||||
return new{ state = false};
|
||||
}
|
||||
if (!EnumHelper.TryConvertEnum<JunctionType>(toJunctionType, out var tmpToJunctionType))
|
||||
{
|
||||
return new{ state = false};
|
||||
}
|
||||
|
||||
// 检查控制点类别,判断此次连接请求是否符合预期
|
||||
if (tmpFromJunctionType == JunctionType.Execute)
|
||||
{
|
||||
if (tmpToJunctionType == JunctionType.NextStep)
|
||||
{
|
||||
(fromNodeGuid, toNodeGuid) = (toNodeGuid, fromNodeGuid); // 需要反转
|
||||
}
|
||||
else
|
||||
{
|
||||
return new { state = false }; // 非预期的控制点连接
|
||||
}
|
||||
}
|
||||
else if (tmpFromJunctionType == JunctionType.NextStep)
|
||||
{
|
||||
if (tmpToJunctionType == JunctionType.Execute)
|
||||
{
|
||||
// 顺序正确无须反转
|
||||
}
|
||||
else
|
||||
{
|
||||
return new { state = false }; // 非预期的控制点连接
|
||||
}
|
||||
}
|
||||
else // 其它类型的控制点,排除
|
||||
{
|
||||
return new { state = false }; // 非预期的控制点连接
|
||||
}
|
||||
Console.WriteLine();
|
||||
Console.WriteLine($"起始节点:{fromNodeGuid}");
|
||||
Console.WriteLine($"目标节点:{toNodeGuid}");
|
||||
Console.WriteLine($"链接请求:{(tmpFromJunctionType, tmpToJunctionType)}");
|
||||
|
||||
var result = await environment.ConnectInvokeNodeAsync(fromNodeGuid, toNodeGuid, tmpFromJunctionType, tmpToJunctionType, tmpConnectionType);
|
||||
return new { state = result };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除连接关系
|
||||
/// 远程移除节点的方法调用关系
|
||||
/// </summary>
|
||||
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||
/// <param name="connectionType">连接关系</param>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveConnect)]
|
||||
public async Task<object> RemoveConnect(string fromNodeGuid, string toNodeGuid, string connectionType)
|
||||
/// <param name="invokeType">连接关系</param>
|
||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveInvokeConnect)]
|
||||
public async Task<object> RemoveInvokeConnect(string fromNodeGuid, string toNodeGuid, string invokeType)
|
||||
{
|
||||
if (!EnumHelper.TryConvertEnum<ConnectionInvokeType>(connectionType, out var tmpConnectionType))
|
||||
if (!EnumHelper.TryConvertEnum<ConnectionInvokeType>(invokeType, out var tmpConnectionType))
|
||||
{
|
||||
return new
|
||||
{
|
||||
state = false
|
||||
};
|
||||
}
|
||||
var result = await environment.RemoveConnectInvokeAsync(fromNodeGuid, toNodeGuid, tmpConnectionType);
|
||||
return new { state = result };
|
||||
}
|
||||
|
||||
var result = await environment.RemoveConnectAsync(fromNodeGuid, toNodeGuid, tmpConnectionType);
|
||||
|
||||
/// <summary>
|
||||
/// 远程连接节点的参数传递关系
|
||||
/// </summary>
|
||||
/// <param name="fromNodeGuid">起始节点</param>
|
||||
/// <param name="toNodeGuid">目标节点</param>
|
||||
/// <param name="fromJunctionType">起始节点控制点</param>
|
||||
/// <param name="toJunctionType">目标节点控制点</param>
|
||||
/// <param name="argSourceType">入参参数来源类型</param>
|
||||
/// <param name="argIndex">第几个参数</param>
|
||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.ConnectArgSourceNode)]
|
||||
public async Task<object> ConnectArgSourceNode(string fromNodeGuid,
|
||||
string toNodeGuid,
|
||||
string fromJunctionType,
|
||||
string toJunctionType,
|
||||
string argSourceType,
|
||||
int argIndex)
|
||||
{
|
||||
if (argIndex < 0 || argIndex > 65535) // 下标不合法
|
||||
{
|
||||
return new { state = false };
|
||||
}
|
||||
// 检查字面量是否可转换枚举类型
|
||||
if (!EnumHelper.TryConvertEnum<ConnectionArgSourceType>(argSourceType, out var tmpArgSourceType))
|
||||
{
|
||||
return new { state = false };
|
||||
}
|
||||
if (!EnumHelper.TryConvertEnum<JunctionType>(fromJunctionType, out var tmpFromJunctionType))
|
||||
{
|
||||
return new { state = false };
|
||||
}
|
||||
if (!EnumHelper.TryConvertEnum<JunctionType>(toJunctionType, out var tmpToJunctionType))
|
||||
{
|
||||
return new { state = false };
|
||||
}
|
||||
|
||||
// 检查控制点类别,判断此次连接请求是否符合预期
|
||||
if (tmpFromJunctionType == JunctionType.ArgData)
|
||||
{
|
||||
if (tmpToJunctionType == JunctionType.ReturnData)
|
||||
{
|
||||
(fromNodeGuid, toNodeGuid) = (toNodeGuid, fromNodeGuid);// 需要反转
|
||||
}
|
||||
else
|
||||
{
|
||||
return new { state = false }; // 非预期的控制点连接
|
||||
}
|
||||
}
|
||||
else if (tmpFromJunctionType == JunctionType.ReturnData)
|
||||
{
|
||||
if (tmpToJunctionType == JunctionType.ArgData)
|
||||
{
|
||||
// 顺序正确无须反转
|
||||
}
|
||||
else
|
||||
{
|
||||
return new { state = false }; // 非预期的控制点连接
|
||||
}
|
||||
}
|
||||
else // 其它类型的控制点,排除
|
||||
{
|
||||
return new { state = false }; // 非预期的控制点连接
|
||||
}
|
||||
//Console.WriteLine();
|
||||
//Console.WriteLine($"起始节点:{fromNodeGuid}");
|
||||
//Console.WriteLine($"目标节点:{toNodeGuid}");
|
||||
//Console.WriteLine($"链接请求:{(tmpFromJunctionType, tmpToJunctionType)}");
|
||||
// 调用环境接口进行连接
|
||||
var result = await environment.ConnectArgSourceNodeAsync(fromNodeGuid, toNodeGuid, tmpFromJunctionType, tmpToJunctionType, tmpArgSourceType, argIndex);
|
||||
return new { state = result };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 远程移除节点的参数传递关系
|
||||
/// </summary>
|
||||
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||
/// <param name="argIndex">目标节点的第几个参数</param>
|
||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveArgSourceConnect)]
|
||||
public async Task<object> RemoveArgSourceConnect(string fromNodeGuid, string toNodeGuid, int argIndex)
|
||||
{
|
||||
|
||||
|
||||
var result = await environment.RemoveConnectArgSourceAsync(fromNodeGuid, toNodeGuid, argIndex);
|
||||
return new
|
||||
{
|
||||
state = result
|
||||
@@ -408,18 +531,14 @@ namespace Serein.NodeFlow.Env
|
||||
/// 中断指定节点,并指定中断等级。
|
||||
/// </summary>
|
||||
/// <param name="nodeGuid">被中断的目标节点Guid</param>
|
||||
/// <param name="interruptClass">中断级别</param>
|
||||
/// <param name="isInterrupt">是否中断</param>
|
||||
/// <returns>操作是否成功</returns>
|
||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.SetNodeInterrupt)]
|
||||
public async Task<bool> SetNodeInterruptAsync(string nodeGuid, string interruptClass)
|
||||
public async Task<bool> SetNodeInterruptAsync(string nodeGuid, bool isInterrupt)
|
||||
{
|
||||
|
||||
if (!EnumHelper.TryConvertEnum<InterruptClass>(interruptClass, out var @class))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return await this.environment.SetNodeInterruptAsync(nodeGuid, @class);
|
||||
|
||||
return await this.environment.SetNodeInterruptAsync(nodeGuid, isInterrupt);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.FlowNode;
|
||||
using Serein.Library.Utils;
|
||||
using Serein.NodeFlow.Tool;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Security.AccessControl;
|
||||
using System.Threading.Channels;
|
||||
|
||||
namespace Serein.NodeFlow.Env
|
||||
{
|
||||
@@ -16,21 +19,21 @@ namespace Serein.NodeFlow.Env
|
||||
/// <summary>
|
||||
/// 连接到远程环境后切换到的环境接口实现
|
||||
/// </summary>
|
||||
/// <param name="RemoteEnvControl">连接到远程环境后,本地环境自动切换到对应的环境实体</param>
|
||||
/// <param name="remoteMsgUtil">连接到远程环境后,本地环境自动切换到对应的环境实体</param>
|
||||
/// <param name="uIContextOperation">远程环境下需要操作UI线程时,所提供的线程上下文封装工具</param>
|
||||
public RemoteFlowEnvironment(RemoteEnvControl RemoteEnvControl, UIContextOperation uIContextOperation)
|
||||
public RemoteFlowEnvironment(RemoteMsgUtil remoteMsgUtil, UIContextOperation uIContextOperation)
|
||||
{
|
||||
this.UIContextOperation = uIContextOperation;
|
||||
remoteEnvControl = RemoteEnvControl;
|
||||
msgClient = new MsgControllerOfClient(this, RemoteEnvControl.SendAsync);
|
||||
RemoteEnvControl.EnvClient.MsgHandleHelper.AddModule(msgClient, (ex, send) =>
|
||||
RemoteMsgUtil = remoteMsgUtil;
|
||||
msgClient = new MsgControllerOfClient(this, remoteMsgUtil.SendAsync); // 这里提供的是主动发送消息的方法
|
||||
remoteMsgUtil.EnvClient.MsgHandleHelper.AddModule(msgClient, (ex, send) =>
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
});
|
||||
}
|
||||
|
||||
//private readonly Func<string, object?, Task> SendCommandAsync;
|
||||
private readonly RemoteEnvControl remoteEnvControl;
|
||||
private readonly RemoteMsgUtil RemoteMsgUtil;
|
||||
private readonly MsgControllerOfClient msgClient;
|
||||
private readonly ConcurrentDictionary<string, MethodDetails> MethodDetailss = [];
|
||||
|
||||
@@ -70,6 +73,12 @@ namespace Serein.NodeFlow.Env
|
||||
|
||||
public IFlowEnvironment CurrentEnv => this;
|
||||
public UIContextOperation UIContextOperation { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 标示是否正在加载项目
|
||||
/// </summary>
|
||||
private bool IsLoadingProject = false;
|
||||
|
||||
public void SetConsoleOut()
|
||||
{
|
||||
var logTextWriter = new LogTextWriter(msg =>
|
||||
@@ -102,9 +111,9 @@ namespace Serein.NodeFlow.Env
|
||||
|
||||
public void LoadProject(FlowEnvInfo flowEnvInfo, string filePath)
|
||||
{
|
||||
//Console.WriteLine("远程环境尚未实现的接口:LoadProject");
|
||||
|
||||
// dll面板
|
||||
Console.WriteLine("加载远程环境");
|
||||
IsLoadingProject = true;
|
||||
#region DLL功能区创建
|
||||
var libmds = flowEnvInfo.LibraryMds;
|
||||
foreach (var lib in libmds)
|
||||
{
|
||||
@@ -114,21 +123,18 @@ namespace Serein.NodeFlow.Env
|
||||
FilePath = "Remote",
|
||||
};
|
||||
var mdInfos = lib.Mds.ToList();
|
||||
//OnDllLoad?.Invoke(new LoadDllEventArgs(nodeLibrary, mdInfos)); // 通知UI创建dll面板显示
|
||||
UIContextOperation?.Invoke(() => OnDllLoad?.Invoke(new LoadDllEventArgs(nodeLibrary, mdInfos))); // 通知UI创建dll面板显示
|
||||
foreach (var mdInfo in mdInfos)
|
||||
{
|
||||
MethodDetailss.TryAdd(mdInfo.MethodName, new MethodDetails(mdInfo)); // 从DLL读取时生成元数据
|
||||
}
|
||||
}
|
||||
//flowSemaphore.
|
||||
#endregion
|
||||
|
||||
#region 加载节点数据,如果是区域控件,提前加载区域
|
||||
var projectData = flowEnvInfo.Project;
|
||||
|
||||
|
||||
List<(NodeModelBase, string[])> regionChildNodes = new List<(NodeModelBase, string[])>();
|
||||
List<(NodeModelBase, PositionOfUI)> ordinaryNodes = new List<(NodeModelBase, PositionOfUI)>();
|
||||
|
||||
// 加载节点
|
||||
foreach (var nodeInfo in projectData.Nodes)
|
||||
{
|
||||
@@ -139,7 +145,6 @@ namespace Serein.NodeFlow.Env
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
MethodDetails? methodDetails = null;
|
||||
if (!string.IsNullOrEmpty(nodeInfo.MethodName))
|
||||
{
|
||||
@@ -167,7 +172,9 @@ namespace Serein.NodeFlow.Env
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 加载区域中的节点
|
||||
// 加载区域子项
|
||||
foreach ((NodeModelBase region, string[] childNodeGuids) item in regionChildNodes)
|
||||
{
|
||||
@@ -183,7 +190,9 @@ namespace Serein.NodeFlow.Env
|
||||
UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(childNode, true, item.region.Guid)));
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 加载普通的节点
|
||||
// 加载节点
|
||||
foreach ((NodeModelBase nodeModel, PositionOfUI position) item in ordinaryNodes)
|
||||
{
|
||||
@@ -202,60 +211,84 @@ namespace Serein.NodeFlow.Env
|
||||
//OnNodeCreate?.Invoke(new NodeCreateEventArgs(item.nodeModel, item.position));
|
||||
UIContextOperation?.Invoke(() => OnNodeCreate?.Invoke(new NodeCreateEventArgs(item.nodeModel, item.position)));
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
// 确定节点之间的连接关系
|
||||
#region 确定节点之间的连接关系
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(250);
|
||||
foreach (var nodeInfo in projectData.Nodes)
|
||||
{
|
||||
if (!NodeModels.TryGetValue(nodeInfo.Guid, out NodeModelBase? fromNode))
|
||||
await Task.Delay(500);
|
||||
#region 连接节点的调用关系
|
||||
foreach (var nodeInfo in projectData.Nodes)
|
||||
{
|
||||
// 不存在对应的起始节点
|
||||
continue;
|
||||
}
|
||||
if (!NodeModels.TryGetValue(nodeInfo.Guid, out NodeModelBase? fromNode))
|
||||
{
|
||||
// 不存在对应的起始节点
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
List<(ConnectionInvokeType connectionType, string[] guids)> allToNodes = [(ConnectionInvokeType.IsSucceed,nodeInfo.TrueNodes),
|
||||
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)
|
||||
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)
|
||||
{
|
||||
|
||||
UIContextOperation?.Invoke(() => OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNode.Guid,
|
||||
toNode.Guid,
|
||||
JunctionOfConnectionType.Invoke,
|
||||
item.connectionType,
|
||||
NodeConnectChangeEventArgs.ConnectChangeType.Create))); // 通知UI连接节点
|
||||
//OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNode.Guid,
|
||||
// toNode.Guid,
|
||||
// item.connectionType,
|
||||
// NodeConnectChangeEventArgs.ConnectChangeType.Create)); //
|
||||
|
||||
// 遍历当前类型分支的节点(确认连接关系)
|
||||
foreach (var toNode in item.toNodes)
|
||||
{
|
||||
UIContextOperation?.Invoke(() => OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNode.Guid,
|
||||
toNode.Guid,
|
||||
JunctionOfConnectionType.Invoke,
|
||||
item.connectionType,
|
||||
NodeConnectChangeEventArgs.ConnectChangeType.Create))); // 通知UI连接节点
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
#endregion
|
||||
|
||||
SetStartNode(projectData.StartNode);
|
||||
#region 连接节点的传参关系
|
||||
foreach (var toNode in NodeModels.Values)
|
||||
{
|
||||
if(toNode.MethodDetails.ParameterDetailss is 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))
|
||||
{
|
||||
UIContextOperation?.Invoke(() =>
|
||||
OnNodeConnectChange?.Invoke(
|
||||
new NodeConnectChangeEventArgs(
|
||||
fromNode.Guid, // 从哪个节点开始
|
||||
toNode.Guid, // 连接到那个节点
|
||||
JunctionOfConnectionType.Arg,
|
||||
(int)pd.Index, // 连接线的样式类型
|
||||
pd.ArgDataSourceType,
|
||||
NodeConnectChangeEventArgs.ConnectChangeType.Create // 是创建连接还是删除连接
|
||||
))); // 通知UI
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
});
|
||||
#endregion
|
||||
|
||||
SetStartNode(projectData.StartNode); // 设置流程起点
|
||||
UIContextOperation?.Invoke(() =>
|
||||
{
|
||||
OnProjectLoaded?.Invoke(new ProjectLoadedEventArgs());
|
||||
OnProjectLoaded?.Invoke(new ProjectLoadedEventArgs()); // 加载完成
|
||||
});
|
||||
|
||||
IsLoadingProject = false;
|
||||
}
|
||||
private bool TryAddNode(NodeModelBase nodeModel)
|
||||
{
|
||||
@@ -339,15 +372,12 @@ namespace Serein.NodeFlow.Env
|
||||
|
||||
public async Task<FlowEnvInfo> GetEnvInfoAsync()
|
||||
{
|
||||
|
||||
var envInfo = await msgClient.SendAndWaitDataAsync<FlowEnvInfo>(EnvMsgTheme.GetEnvInfo);
|
||||
|
||||
return envInfo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task<(bool, RemoteEnvControl)> ConnectRemoteEnv(string addres, int port, string token)
|
||||
public async Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres, int port, string token)
|
||||
{
|
||||
await Console.Out.WriteLineAsync("远程环境尚未实现的接口:ConnectRemoteEnv");
|
||||
return (false, null);
|
||||
@@ -436,32 +466,204 @@ namespace Serein.NodeFlow.Env
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<bool> ConnectNodeAsync(string fromNodeGuid,
|
||||
string toNodeGuid,
|
||||
JunctionType fromNodeJunctionType,
|
||||
JunctionType toNodeJunctionType,
|
||||
ConnectionInvokeType connectionType,
|
||||
int argIndex = 0)
|
||||
/// <summary>
|
||||
/// 在两个节点之间创建方法调用关系
|
||||
/// </summary>
|
||||
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||
/// <param name="fromNodeJunctionType">起始节点控制点</param>
|
||||
/// <param name="toNodeJunctionType">目标节点控制点</param>
|
||||
/// <param name="invokeType">决定了方法执行后的后继行为</param>
|
||||
public async Task<bool> ConnectInvokeNodeAsync(string fromNodeGuid,
|
||||
string toNodeGuid,
|
||||
JunctionType fromNodeJunctionType,
|
||||
JunctionType toNodeJunctionType,
|
||||
ConnectionInvokeType invokeType)
|
||||
{
|
||||
var result = await msgClient.SendAndWaitDataAsync<bool>(EnvMsgTheme.ConnectNode, new
|
||||
if (fromNodeJunctionType == JunctionType.Execute)
|
||||
{
|
||||
fromNodeGuid,
|
||||
toNodeGuid,
|
||||
fromNodeJunctionType = fromNodeJunctionType.ToString(),
|
||||
toNodeJunctionType = toNodeJunctionType.ToString(),
|
||||
connectionType = connectionType.ToString(),
|
||||
});
|
||||
if (toNodeJunctionType == JunctionType.NextStep)
|
||||
{
|
||||
(fromNodeGuid, toNodeGuid) = (toNodeGuid, fromNodeGuid);// 需要反转
|
||||
}
|
||||
else
|
||||
{
|
||||
return false; // 非预期的控制点连接
|
||||
}
|
||||
}
|
||||
else if (fromNodeJunctionType == JunctionType.NextStep)
|
||||
{
|
||||
if (toNodeJunctionType == JunctionType.Execute)
|
||||
{
|
||||
// 顺序正确无须反转
|
||||
}
|
||||
else
|
||||
{
|
||||
return false; // 非预期的控制点连接
|
||||
}
|
||||
}
|
||||
else // 其它类型的控制点,排除
|
||||
{
|
||||
return false; // 非预期的控制点连接
|
||||
}
|
||||
|
||||
|
||||
var sendObj = new
|
||||
{
|
||||
fromNodeGuid = fromNodeGuid,
|
||||
toNodeGuid = toNodeGuid,
|
||||
fromJunctionType = fromNodeJunctionType.ToString(),
|
||||
toJunctionType = toNodeJunctionType.ToString(),
|
||||
invokeType = invokeType.ToString(),
|
||||
};
|
||||
var result = await msgClient.SendAndWaitDataAsync<bool>(EnvMsgTheme.ConnectInvokeNode, sendObj);
|
||||
if (result)
|
||||
{
|
||||
OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid,
|
||||
toNodeGuid,
|
||||
JunctionOfConnectionType.Invoke,
|
||||
connectionType,
|
||||
invokeType,
|
||||
NodeConnectChangeEventArgs.ConnectChangeType.Create)); // 通知UI
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在两个节点之间创建参数传递关系
|
||||
/// </summary>
|
||||
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||
/// <param name="fromNodeJunctionType">起始节点控制点</param>
|
||||
/// <param name="toNodeJunctionType">目标节点控制点</param>
|
||||
/// <param name="argSourceType">决定了方法参数来源</param>
|
||||
/// <param name="argIndex">设置第几个参数</param>
|
||||
public async Task<bool> ConnectArgSourceNodeAsync(string fromNodeGuid,
|
||||
string toNodeGuid,
|
||||
JunctionType fromNodeJunctionType,
|
||||
JunctionType toNodeJunctionType,
|
||||
ConnectionArgSourceType argSourceType,
|
||||
int argIndex = 0)
|
||||
{
|
||||
|
||||
// 正确的顺序:起始节点[返回值控制点] 向 目标节点[入参控制点] 发起连接
|
||||
//Console.WriteLine();
|
||||
//Console.WriteLine($"起始节点:{fromNodeGuid}");
|
||||
//Console.WriteLine($"目标节点:{toNodeGuid}");
|
||||
//Console.WriteLine($"链接请求:{(fromNodeJunctionType, toNodeJunctionType)}");
|
||||
//Console.WriteLine((fromNodeJunctionType, toNodeJunctionType));
|
||||
|
||||
if (fromNodeJunctionType == JunctionType.ArgData)
|
||||
{
|
||||
if (toNodeJunctionType == JunctionType.ReturnData)
|
||||
{
|
||||
(fromNodeGuid, toNodeGuid) = (toNodeGuid, fromNodeGuid);// 需要反转
|
||||
}
|
||||
else
|
||||
{
|
||||
return false; // 非预期的控制点连接
|
||||
}
|
||||
}
|
||||
else if (fromNodeJunctionType == JunctionType.ReturnData)
|
||||
{
|
||||
if (toNodeJunctionType == JunctionType.ArgData)
|
||||
{
|
||||
// 顺序正确无须反转
|
||||
}
|
||||
else
|
||||
{
|
||||
return false; // 非预期的控制点连接
|
||||
}
|
||||
}
|
||||
else // 其它类型的控制点,排除
|
||||
{
|
||||
return false; // 非预期的控制点连接
|
||||
}
|
||||
|
||||
var sendObj = new
|
||||
{
|
||||
fromNodeGuid = fromNodeGuid,
|
||||
toNodeGuid = toNodeGuid,
|
||||
fromJunctionType = fromNodeJunctionType.ToString(),
|
||||
toJunctionType = toNodeJunctionType.ToString(),
|
||||
argSourceType = argSourceType.ToString(),
|
||||
argIndex = argIndex,
|
||||
};
|
||||
var result = await msgClient.SendAndWaitDataAsync<bool>(EnvMsgTheme.ConnectArgSourceNode, sendObj);
|
||||
if (result)
|
||||
{
|
||||
OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid,
|
||||
toNodeGuid,
|
||||
JunctionOfConnectionType.Arg,
|
||||
argIndex,
|
||||
argSourceType,
|
||||
NodeConnectChangeEventArgs.ConnectChangeType.Create)); // 通知UI
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 移除两个节点之间的方法调用关系
|
||||
/// </summary>
|
||||
/// <param name="fromNodeGuid">起始节点</param>
|
||||
/// <param name="toNodeGuid">目标节点</param>
|
||||
/// <param name="invokeType">连接类型</param>
|
||||
public async Task<bool> RemoveConnectInvokeAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType invokeType)
|
||||
{
|
||||
var result = await msgClient.SendAndWaitDataAsync<bool>(EnvMsgTheme.RemoveInvokeConnect, new
|
||||
{
|
||||
fromNodeGuid = fromNodeGuid,
|
||||
toNodeGuid = toNodeGuid,
|
||||
invokeType = invokeType.ToString(),
|
||||
});
|
||||
if (result)
|
||||
{
|
||||
UIContextOperation.Invoke(() =>
|
||||
{
|
||||
OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid,
|
||||
toNodeGuid,
|
||||
JunctionOfConnectionType.Invoke,
|
||||
invokeType,
|
||||
NodeConnectChangeEventArgs.ConnectChangeType.Remote));
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/// <summary>
|
||||
/// 移除连接节点之间参数传递的关系
|
||||
/// </summary>
|
||||
/// <param name="fromNodeGuid">起始节点Guid</param>
|
||||
/// <param name="toNodeGuid">目标节点Guid</param>
|
||||
/// <param name="argIndex">连接到第几个参数</param>
|
||||
public async Task<bool> RemoveConnectArgSourceAsync(string fromNodeGuid, string toNodeGuid, int argIndex)
|
||||
{
|
||||
var result = await msgClient.SendAndWaitDataAsync<bool>(EnvMsgTheme.RemoveArgSourceConnect, new
|
||||
{
|
||||
fromNodeGuid = fromNodeGuid,
|
||||
toNodeGuid = toNodeGuid,
|
||||
argIndex = argIndex,
|
||||
});
|
||||
if (result)
|
||||
{
|
||||
UIContextOperation.Invoke(() =>
|
||||
{
|
||||
OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid,
|
||||
toNodeGuid,
|
||||
JunctionOfConnectionType.Arg,
|
||||
argIndex,
|
||||
ConnectionArgSourceType.GetPreviousNodeData,
|
||||
NodeConnectChangeEventArgs.ConnectChangeType.Remote)); // 通知UI
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建节点/区域/基础控件
|
||||
/// </summary>
|
||||
/// <param name="nodeType">节点/区域/基础控件类型</param>
|
||||
/// <param name="position">节点在画布上的位置(</param>
|
||||
/// <param name="methodDetailsInfo">节点绑定的方法说明</param>
|
||||
public async Task<NodeInfo> CreateNodeAsync(NodeControlType nodeControlType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null)
|
||||
{
|
||||
var nodeInfo = await msgClient.SendAndWaitDataAsync<NodeInfo>(EnvMsgTheme.CreateNode, new
|
||||
@@ -489,29 +691,6 @@ namespace Serein.NodeFlow.Env
|
||||
});
|
||||
return nodeInfo;
|
||||
}
|
||||
|
||||
public async Task<bool> RemoveConnectAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
|
||||
{
|
||||
var result = await msgClient.SendAndWaitDataAsync<bool>(EnvMsgTheme.RemoveConnect, new
|
||||
{
|
||||
fromNodeGuid,
|
||||
toNodeGuid,
|
||||
connectionType = connectionType.ToString(),
|
||||
});
|
||||
if (result)
|
||||
{
|
||||
UIContextOperation.Invoke(() =>
|
||||
{
|
||||
OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid,
|
||||
toNodeGuid,
|
||||
JunctionOfConnectionType.Invoke,
|
||||
connectionType,
|
||||
NodeConnectChangeEventArgs.ConnectChangeType.Remote));
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<bool> RemoveNodeAsync(string nodeGuid)
|
||||
{
|
||||
var result = await msgClient.SendAndWaitDataAsync<bool>(EnvMsgTheme.RemoveNode, new
|
||||
@@ -548,13 +727,13 @@ namespace Serein.NodeFlow.Env
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<bool> SetNodeInterruptAsync(string nodeGuid, InterruptClass interruptClass)
|
||||
public async Task<bool> SetNodeInterruptAsync(string nodeGuid, bool isInterrupt)
|
||||
{
|
||||
var state = await msgClient.SendAndWaitDataAsync<bool>(EnvMsgTheme.SetNodeInterrupt, // 设置节点中断
|
||||
new
|
||||
{
|
||||
nodeGuid,
|
||||
interruptClass = interruptClass.ToString(),
|
||||
isInterrupt,
|
||||
});
|
||||
return state;
|
||||
}
|
||||
@@ -638,12 +817,13 @@ namespace Serein.NodeFlow.Env
|
||||
public async Task NotificationNodeValueChangeAsync(string nodeGuid, string path, object value)
|
||||
{
|
||||
//Console.WriteLine($"通知远程环境修改节点数据:{nodeGuid},name:{path},value:{value}");
|
||||
_ = msgClient.SendAsync(EnvMsgTheme.ValueNotification, new
|
||||
{
|
||||
nodeGuid = nodeGuid,
|
||||
path = path,
|
||||
value = value.ToString(),
|
||||
});
|
||||
|
||||
//_ = msgClient.SendAsync(EnvMsgTheme.ValueNotification, new
|
||||
//{
|
||||
// nodeGuid = nodeGuid,
|
||||
// path = path,
|
||||
// value = value.ToString(),
|
||||
//});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,13 +46,27 @@ namespace Serein.NodeFlow
|
||||
/// <returns></returns>
|
||||
public async Task StartFlowInSelectNodeAsync(IFlowEnvironment env, NodeModelBase startNode)
|
||||
{
|
||||
IDynamicContext Context;
|
||||
IDynamicContext context;
|
||||
#if NET6_0_OR_GREATER
|
||||
Context = new Serein.Library.Core.NodeFlow.DynamicContext(env); // 从起始节点启动流程时创建上下文
|
||||
context = new Serein.Library.Core.NodeFlow.DynamicContext(env); // 从起始节点启动流程时创建上下文
|
||||
#else
|
||||
Context = new Serein.Library.Framework.NodeFlow.DynamicContext(env);
|
||||
#endif
|
||||
await startNode.StartFlowAsync(Context); // 开始运行时从选定节点开始运行
|
||||
await startNode.StartFlowAsync(context); // 开始运行时从选定节点开始运行
|
||||
context.Exit();
|
||||
|
||||
/*
|
||||
|
||||
foreach (var node in NodeModels.Values)
|
||||
{
|
||||
if (node is not null)
|
||||
{
|
||||
node.ReleaseFlowData(); // 退出时释放对象
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
@@ -360,7 +374,7 @@ namespace Serein.NodeFlow
|
||||
if (nextNodes[i].DebugSetting.IsEnable)
|
||||
{
|
||||
nextNodes[i].PreviousNode = singleFlipFlopNode;
|
||||
if (nextNodes[i].DebugSetting.InterruptClass != InterruptClass.None) // 执行触发前
|
||||
if (nextNodes[i].DebugSetting.IsInterrupt) // 执行触发前
|
||||
{
|
||||
var cancelType = await nextNodes[i].DebugSetting.GetInterruptTask();
|
||||
await Console.Out.WriteLineAsync($"[{nextNodes[i].MethodDetails.MethodName}]中断已{cancelType},开始执行后继分支");
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
|
||||
namespace Serein.NodeFlow.Model
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 组合动作节点(用于动作区域)
|
||||
/// </summary>
|
||||
public class CompositeActionNode : NodeModelBase
|
||||
{
|
||||
public List<SingleActionNode> ActionNodes;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 组合动作节点(用于动作区域)
|
||||
/// </summary>
|
||||
public CompositeActionNode(IFlowEnvironment environment, List<SingleActionNode> actionNodes):base(environment)
|
||||
{
|
||||
ActionNodes = actionNodes;
|
||||
}
|
||||
|
||||
//public override async Task<object?> Executing(IDynamicContext context)
|
||||
public override Task<object?> ExecutingAsync(IDynamicContext context)
|
||||
{
|
||||
throw new NotImplementedException("动作区域暂未实现");
|
||||
}
|
||||
|
||||
public override Parameterdata[] GetParameterdatas()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public override NodeInfo? ToInfo()
|
||||
{
|
||||
if (MethodDetails is null) return null;
|
||||
|
||||
var trueNodes = SuccessorNodes[ConnectionInvokeType.IsSucceed].Select(item => item.Guid); // 真分支
|
||||
var falseNodes = SuccessorNodes[ConnectionInvokeType.IsFail].Select(item => item.Guid);// 假分支
|
||||
var errorNodes = SuccessorNodes[ConnectionInvokeType.IsError].Select(item => item.Guid);// 异常分支
|
||||
var upstreamNodes = SuccessorNodes[ConnectionInvokeType.Upstream].Select(item => item.Guid);// 上游分支
|
||||
// 生成参数列表
|
||||
Parameterdata[] parameterData = GetParameterdatas();
|
||||
|
||||
return new NodeInfo
|
||||
{
|
||||
Guid = Guid,
|
||||
MethodName = MethodDetails?.MethodName,
|
||||
Label = DisplayName ?? "",
|
||||
Type = this.GetType().ToString(),
|
||||
TrueNodes = trueNodes.ToArray(),
|
||||
FalseNodes = falseNodes.ToArray(),
|
||||
UpstreamNodes = upstreamNodes.ToArray(),
|
||||
ParameterData = parameterData.ToArray(),
|
||||
ErrorNodes = errorNodes.ToArray(),
|
||||
ChildNodeGuids = ActionNodes.Select(node => node.Guid).ToArray(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -58,7 +58,8 @@ namespace Serein.NodeFlow.Model
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Task.FromResult( PreviousNode?.GetFlowData()); // 条件区域透传上一节点的数据
|
||||
|
||||
return Task.FromResult(context.GetFlowData(PreviousNode.Guid)); // 条件区域透传上一节点的数据
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +79,7 @@ namespace Serein.NodeFlow.Model
|
||||
}
|
||||
}
|
||||
|
||||
public override Parameterdata[] GetParameterdatas()
|
||||
public override ParameterData[] GetParameterdatas()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
@@ -97,7 +98,7 @@ namespace Serein.NodeFlow.Model
|
||||
var upstreamNodes = SuccessorNodes[ConnectionInvokeType.Upstream].Select(item => item.Guid);// 上游分支
|
||||
|
||||
// 生成参数列表
|
||||
Parameterdata[] parameterData = GetParameterdatas();
|
||||
ParameterData[] parameterData = GetParameterdatas();
|
||||
|
||||
return new NodeInfo
|
||||
{
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Serein.NodeFlow.Model
|
||||
{
|
||||
//public class CompositeLoopNode : NodeBase
|
||||
//{
|
||||
//}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library;
|
||||
using System.Security.AccessControl;
|
||||
|
||||
namespace Serein.NodeFlow.Model
|
||||
{
|
||||
@@ -12,13 +13,15 @@ namespace Serein.NodeFlow.Model
|
||||
{
|
||||
|
||||
}
|
||||
public override Parameterdata[] GetParameterdatas()
|
||||
public override ParameterData[] GetParameterdatas()
|
||||
{
|
||||
if (base.MethodDetails.ParameterDetailss.Length > 0)
|
||||
{
|
||||
return MethodDetails.ParameterDetailss
|
||||
.Select(it => new Parameterdata
|
||||
.Select(it => new ParameterData
|
||||
{
|
||||
SourceNodeGuid = it.ArgDataSourceNodeGuid,
|
||||
SourceType = it.ArgDataSourceType.ToString(),
|
||||
State = it.IsExplicitData,
|
||||
Value = it.DataValue,
|
||||
})
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace Serein.NodeFlow.Model
|
||||
{
|
||||
// 接收上一节点参数or自定义参数内容
|
||||
object? parameter;
|
||||
object? result = PreviousNode?.GetFlowData(); // 条件节点透传上一节点的数据
|
||||
object? result = context.GetFlowData(PreviousNode.Guid); // 条件节点透传上一节点的数据
|
||||
if (IsCustomData) // 是否使用自定义参数
|
||||
{
|
||||
// 表达式获取上一节点数据
|
||||
@@ -88,7 +88,7 @@ namespace Serein.NodeFlow.Model
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
public override Parameterdata[] GetParameterdatas()
|
||||
public override ParameterData[] GetParameterdatas()
|
||||
{
|
||||
var value = CustomData switch
|
||||
{
|
||||
@@ -99,7 +99,7 @@ namespace Serein.NodeFlow.Model
|
||||
Type when CustomData.GetType() == typeof(bool) => ((bool)CustomData).ToString(),
|
||||
_ => CustomData?.ToString()!,
|
||||
};
|
||||
return [new Parameterdata
|
||||
return [new ParameterData
|
||||
{
|
||||
State = IsCustomData,
|
||||
Expression = Expression,
|
||||
@@ -114,11 +114,10 @@ namespace Serein.NodeFlow.Model
|
||||
this.Position = nodeInfo.Position;// 加载位置信息
|
||||
for (int i = 0; i < nodeInfo.ParameterData.Length; i++)
|
||||
{
|
||||
Parameterdata? pd = nodeInfo.ParameterData[i];
|
||||
ParameterData? pd = nodeInfo.ParameterData[i];
|
||||
node.IsCustomData = pd.State;
|
||||
node.CustomData = pd.Value;
|
||||
node.Expression = pd.Expression;
|
||||
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Serein.NodeFlow.Model
|
||||
//public override async Task<object?> Executing(IDynamicContext context)
|
||||
public override Task<object?> ExecutingAsync(IDynamicContext context)
|
||||
{
|
||||
var data = PreviousNode?.GetFlowData(); // 表达式节点使用上一节点数据
|
||||
var data = context.GetFlowData(PreviousNode.Guid); // 表达式节点使用上一节点数据
|
||||
|
||||
try
|
||||
{
|
||||
@@ -59,9 +59,9 @@ namespace Serein.NodeFlow.Model
|
||||
|
||||
}
|
||||
|
||||
public override Parameterdata[] GetParameterdatas()
|
||||
public override ParameterData[] GetParameterdatas()
|
||||
{
|
||||
return [new Parameterdata { Expression = Expression }];
|
||||
return [new ParameterData { Expression = Expression }];
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Serein.NodeFlow.Model
|
||||
public override async Task<object?> ExecutingAsync(IDynamicContext context)
|
||||
{
|
||||
#region 执行前中断
|
||||
if (DebugSetting.InterruptClass != InterruptClass.None) // 执行触发前
|
||||
if (DebugSetting.IsInterrupt) // 执行触发前
|
||||
{
|
||||
string guid = this.Guid.ToString();
|
||||
var cancelType = await this.DebugSetting.GetInterruptTask();
|
||||
@@ -82,13 +82,15 @@ namespace Serein.NodeFlow.Model
|
||||
/// 获取触发器参数
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override Parameterdata[] GetParameterdatas()
|
||||
public override ParameterData[] GetParameterdatas()
|
||||
{
|
||||
if (base.MethodDetails.ParameterDetailss.Length > 0)
|
||||
{
|
||||
return MethodDetails.ParameterDetailss
|
||||
.Select(it => new Parameterdata
|
||||
.Select(it => new ParameterData
|
||||
{
|
||||
SourceNodeGuid = it.ArgDataSourceNodeGuid,
|
||||
SourceType = it.ArgDataSourceType.ToString(),
|
||||
State = it.IsExplicitData,
|
||||
Value = it.DataValue
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>1.0.17</Version>
|
||||
<Version>1.0.18</Version>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
@@ -60,11 +60,6 @@
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="System.Collections.NonGeneric" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Serein.Library.MyGenerator\Serein.Library.NodeGenerator.csproj" OutputItemType="Analyzer" />
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using Serein.Library.Utils;
|
||||
using Serein.Library;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Reflection;
|
||||
using Serein.Library.FlowNode;
|
||||
|
||||
namespace Serein.NodeFlow.Tool;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user