From cb2553ac69e1152ab11f451f5d14c4eb8ac646bf Mon Sep 17 00:00:00 2001
From: fengjiayi <12821976+ning_xi@user.noreply.gitee.com>
Date: Sun, 27 Oct 2024 00:54:10 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86=E5=BE=88=E5=A4=9A?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../SereinFlowRemoteControl.cs | 3 -
FlowStartTool/Program.cs | 12 +-
FlowStartTool/Properties/launchSettings.json | 6 +-
FlowStartTool/Serein.FlowStartTool.csproj | 36 +-
Library.Core/NodeFlow/DynamicContext.cs | 16 +-
Library.Core/Serein.Library.Core.csproj | 2 +-
Library.Framework/NodeFlow/DynamicContext.cs | 15 +-
Library.Framework/Properties/AssemblyInfo.cs | 2 +-
Library/Api/IDynamicContext.cs | 3 +-
Library/Api/IFlowEnvironment.cs | 79 +++-
Library/Extension/SereinExtension.cs | 78 ++++
.../{Entity => FlowNode}/DelegateDetails.cs | 18 +-
Library/FlowNode/NodeDebugSetting.cs | 52 +--
Library/FlowNode/NodeModelBaseData.cs | 70 ++--
Library/FlowNode/NodeModelBaseFunc.cs | 96 +++--
Library/FlowNode/ParameterDetails.cs | 44 +-
Library/FlowNode/ParameterDetailsInfo.cs | 3 +-
Library/FlowNode/SereinProjectData.cs | 19 +-
Library/Network/Http/Router.cs | 194 +++------
Library/Network/Http/SereinExtension.cs | 64 +++
.../WebSocket/Handle/JsonMsgHandleConfig.cs | 68 +---
.../WebSocket/Handle/WebSocketHandleModule.cs | 15 +-
.../Handle/WebSocketMsgHandleHelper.cs | 15 +-
.../Network/WebSocket/SocketControlBase.cs | 24 --
Library/Network/WebSocket/TestExtension.cs | 73 ++++
Library/Network/WebSocket/WebSocketClient.cs | 164 +++++---
Library/Network/WebSocket/WebSocketServer.cs | 109 ++---
Library/Serein.Library.csproj | 3 +-
Library/Utils/ChannelFlowTrigger.cs | 10 +
.../{RemoteEnvControl.cs => RemoteMsgUtil.cs} | 16 +-
NodeFlow/Env/EnvMsgTheme.cs | 26 +-
NodeFlow/Env/FlowEnvironment.cs | 251 +++++++-----
NodeFlow/Env/FlowEnvironmentDecorator.cs | 96 +++--
NodeFlow/Env/MsgControllerOfClient.cs | 76 ++--
NodeFlow/Env/MsgControllerOfServer.cs | 191 +++++++--
NodeFlow/Env/RemoteFlowEnvironment.cs | 382 +++++++++++++-----
NodeFlow/FlowStarter.cs | 22 +-
NodeFlow/Model/CompositeActionNode.cs | 61 ---
NodeFlow/Model/CompositeConditionNode.cs | 7 +-
NodeFlow/Model/CompositeLoopNode.cs | 6 -
NodeFlow/Model/SingleActionNode.cs | 7 +-
NodeFlow/Model/SingleConditionNode.cs | 9 +-
NodeFlow/Model/SingleExpOpNode.cs | 6 +-
NodeFlow/Model/SingleFlipflopNode.cs | 8 +-
NodeFlow/Serein.NodeFlow.csproj | 7 +-
NodeFlow/Tool/NodeMethodDetailsHelper.cs | 1 +
Serein.Library.MyGenerator/Attribute.cs | 7 +-
.../ParameterDetailsPropertyGenerator.cs | 22 +-
.../Serein.Library.NodeGenerator.csproj | 7 +
WorkBench/App.xaml.cs | 2 +-
WorkBench/MainWindow.xaml | 33 +-
WorkBench/MainWindow.xaml.cs | 316 ++++++++-------
WorkBench/MainWindowViewModel.cs | 53 ++-
WorkBench/Node/NodeControlViewModelBase.cs | 38 +-
WorkBench/Node/View/ActionNodeControl.xaml | 20 +-
WorkBench/Serein.WorkBench.csproj | 2 +
WorkBench/Themes/MethodDetailsControl.xaml | 25 +-
Workbench/Extension/LineExtension.cs | 53 +++
.../{BezierLine.cs => ConnectionLineShape.cs} | 82 ++--
.../Node/Junction/JunctionControlBase.cs | 136 ++++++-
Workbench/Node/Junction/JunctionData.cs | 103 +++--
.../Node/Junction/View/ArgJunctionControl.cs | 18 +-
.../Junction/View/ExecuteJunctionControl.cs | 14 +-
.../Junction/View/NextStepJunctionControl.cs | 15 +-
.../Junction/View/ResultJunctionControl.cs | 14 +-
Workbench/Node/View/ConnectionControl.cs | 192 ++++-----
66 files changed, 2215 insertions(+), 1402 deletions(-)
create mode 100644 Library/Extension/SereinExtension.cs
rename Library/{Entity => FlowNode}/DelegateDetails.cs (86%)
create mode 100644 Library/Network/Http/SereinExtension.cs
create mode 100644 Library/Network/WebSocket/TestExtension.cs
rename Library/Utils/{RemoteEnvControl.cs => RemoteMsgUtil.cs} (91%)
delete mode 100644 NodeFlow/Model/CompositeActionNode.cs
delete mode 100644 NodeFlow/Model/CompositeLoopNode.cs
create mode 100644 Workbench/Extension/LineExtension.cs
rename Workbench/Node/Junction/{BezierLine.cs => ConnectionLineShape.cs} (79%)
diff --git a/Extend.FlowRemoteManagement/SereinFlowRemoteControl.cs b/Extend.FlowRemoteManagement/SereinFlowRemoteControl.cs
index 90071a3..7a7722a 100644
--- a/Extend.FlowRemoteManagement/SereinFlowRemoteControl.cs
+++ b/Extend.FlowRemoteManagement/SereinFlowRemoteControl.cs
@@ -1,13 +1,10 @@
using Serein.Library;
using Serein.Library.Api;
-using Serein.Library.Attributes;
-using Serein.Library.Enums;
using Serein.Library.Network.WebSocketCommunication;
using System.Security.Cryptography.X509Certificates;
using Serein.NodeFlow;
using Serein.Library.Core.NodeFlow;
-using Serein.Library.NodeFlow.Tool;
using Serein.Library.Utils;
using Serein.FlowRemoteManagement.Model;
using System.Reflection;
diff --git a/FlowStartTool/Program.cs b/FlowStartTool/Program.cs
index 8dd7e9c..7994ae7 100644
--- a/FlowStartTool/Program.cs
+++ b/FlowStartTool/Program.cs
@@ -13,6 +13,11 @@ namespace Serein.FlowStartTool
{
public static void Main(string[] args)
{
+#if true
+ args = [@"F:\临时\project\linux\project.dnf"];
+#endif
+
+
Console.WriteLine("Hello :) ");
Console.WriteLine($"args : {string.Join(" , ", args)}");
string filePath;
@@ -57,10 +62,10 @@ namespace Serein.FlowStartTool
}
IsRuning = true;
- StartFlow(flowProjectData, fileDataPath).GetAwaiter().GetResult();
+ _ = StartFlow(flowProjectData, fileDataPath);
while (IsRuning)
{
-
+ Console.ReadKey();
}
}
@@ -88,13 +93,12 @@ namespace Serein.FlowStartTool
// this.window = window;
//}
- Env = new FlowEnvironmentDecorator(uIContextOperation); // Linux 环境下没有线程上下文(暂时没有写)
+ Env = new FlowEnvironmentDecorator(uIContextOperation);
Env.LoadProject(new FlowEnvInfo { Project = flowProjectData }, fileDataPath); // 加载项目
await Env.StartRemoteServerAsync(7525); // 启动 web socket 监听远程请求
//await Env.StartAsync();
-
IsRuning = false;
}
diff --git a/FlowStartTool/Properties/launchSettings.json b/FlowStartTool/Properties/launchSettings.json
index a742007..28541c4 100644
--- a/FlowStartTool/Properties/launchSettings.json
+++ b/FlowStartTool/Properties/launchSettings.json
@@ -1,10 +1,10 @@
{
"profiles": {
- "Serein.FlowStartTool": {
- "commandName": "Project"
- },
"配置文件 1": {
"commandName": "DebugRoslynComponent"
+ },
+ "Serein.FlowStartTool": {
+ "commandName": "Project"
}
}
}
\ No newline at end of file
diff --git a/FlowStartTool/Serein.FlowStartTool.csproj b/FlowStartTool/Serein.FlowStartTool.csproj
index 1d48b61..8a1227c 100644
--- a/FlowStartTool/Serein.FlowStartTool.csproj
+++ b/FlowStartTool/Serein.FlowStartTool.csproj
@@ -9,34 +9,34 @@
enable
prompt
starter
+ AnyCPU
+ False
+ True
+
+
+
+ False
+ True
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+ -->
diff --git a/Library.Core/NodeFlow/DynamicContext.cs b/Library.Core/NodeFlow/DynamicContext.cs
index 7315912..436e9f3 100644
--- a/Library.Core/NodeFlow/DynamicContext.cs
+++ b/Library.Core/NodeFlow/DynamicContext.cs
@@ -47,6 +47,10 @@ namespace Serein.Library.Core.NodeFlow
///
public object? GetFlowData(string nodeGuid)
{
+ if (string.IsNullOrEmpty(nodeGuid))
+ {
+ return null;
+ }
if(dictNodeFlowData.TryGetValue(nodeGuid,out var data))
{
return data;
@@ -70,8 +74,18 @@ namespace Serein.Library.Core.NodeFlow
///
/// 结束流程
///
- public void EndCurrentBranch()
+ public void Exit()
{
+ foreach (var nodeObj in dictNodeFlowData.Values)
+ {
+ if (nodeObj is not null)
+ {
+ if (typeof(IDisposable).IsAssignableFrom(nodeObj?.GetType()) && nodeObj is IDisposable disposable)
+ {
+ disposable?.Dispose();
+ }
+ }
+ }
this.dictNodeFlowData?.Clear();
RunState = RunState.Completion;
}
diff --git a/Library.Core/Serein.Library.Core.csproj b/Library.Core/Serein.Library.Core.csproj
index 8c80e4b..e4daf39 100644
--- a/Library.Core/Serein.Library.Core.csproj
+++ b/Library.Core/Serein.Library.Core.csproj
@@ -1,7 +1,7 @@
- 1.0.14
+ 1.0.15
net8.0
enable
enable
diff --git a/Library.Framework/NodeFlow/DynamicContext.cs b/Library.Framework/NodeFlow/DynamicContext.cs
index 711a87b..2e1ad96 100644
--- a/Library.Framework/NodeFlow/DynamicContext.cs
+++ b/Library.Framework/NodeFlow/DynamicContext.cs
@@ -1,4 +1,5 @@
using Serein.Library.Api;
+using System;
using System.Collections.Concurrent;
namespace Serein.Library.Framework.NodeFlow
@@ -46,8 +47,6 @@ namespace Serein.Library.Framework.NodeFlow
///
public object GetFlowData(string nodeGuid)
{
-
-
if (dictNodeFlowData.TryGetValue(nodeGuid, out var data))
{
return data;
@@ -71,8 +70,18 @@ namespace Serein.Library.Framework.NodeFlow
///
/// 结束流程
///
- public void EndCurrentBranch()
+ public void Exit()
{
+ foreach (var nodeObj in dictNodeFlowData.Values)
+ {
+ if (nodeObj != null)
+ {
+ if (typeof(IDisposable).IsAssignableFrom(nodeObj?.GetType()) && nodeObj is IDisposable disposable)
+ {
+ disposable?.Dispose();
+ }
+ }
+ }
this.dictNodeFlowData?.Clear();
RunState = RunState.Completion;
}
diff --git a/Library.Framework/Properties/AssemblyInfo.cs b/Library.Framework/Properties/AssemblyInfo.cs
index 67817af..c3ce276 100644
--- a/Library.Framework/Properties/AssemblyInfo.cs
+++ b/Library.Framework/Properties/AssemblyInfo.cs
@@ -34,5 +34,5 @@ using System.Runtime.InteropServices;
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.1.4")]
-[assembly: AssemblyFileVersion("1.0.1.4")]
+[assembly: AssemblyFileVersion("1.0.1.5")]
[assembly: NeutralResourcesLanguage("")]
diff --git a/Library/Api/IDynamicContext.cs b/Library/Api/IDynamicContext.cs
index 925356a..f097dc4 100644
--- a/Library/Api/IDynamicContext.cs
+++ b/Library/Api/IDynamicContext.cs
@@ -42,7 +42,8 @@ namespace Serein.Library.Api
///
/// 用以提前结束分支运行
///
- void EndCurrentBranch();
+ void Exit();
+
/*///
/// 定时循环触发
diff --git a/Library/Api/IFlowEnvironment.cs b/Library/Api/IFlowEnvironment.cs
index c89a419..64017da 100644
--- a/Library/Api/IFlowEnvironment.cs
+++ b/Library/Api/IFlowEnvironment.cs
@@ -1,5 +1,6 @@
+using Serein.Library.FlowNode;
using Serein.Library.Utils;
using System;
using System.Collections.Generic;
@@ -176,6 +177,15 @@ namespace Serein.Library.Api
///
Remote,
}
+
+ ///
+ /// 更改方法调用关系
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
public NodeConnectChangeEventArgs(string fromNodeGuid,
string toNodeGuid,
JunctionOfConnectionType junctionOfConnectionType, // 指示需要创建什么类型的连接线
@@ -189,6 +199,15 @@ namespace Serein.Library.Api
this.JunctionOfConnectionType = junctionOfConnectionType;
}
+ ///
+ /// 更改参数传递关系
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
public NodeConnectChangeEventArgs(string fromNodeGuid,
string toNodeGuid,
JunctionOfConnectionType junctionOfConnectionType, // 指示需要创建什么类型的连接线
@@ -228,6 +247,9 @@ namespace Serein.Library.Api
/// 节点对应的方法入参所需参数来源
///
public ConnectionArgSourceType ConnectionArgSourceType { get; protected set; }
+ ///
+ /// 第几个参数
+ ///
public int ArgIndex { get; protected set; }
@@ -350,17 +372,19 @@ namespace Serein.Library.Api
///
public class NodeInterruptStateChangeEventArgs : FlowEventArgs
{
- public NodeInterruptStateChangeEventArgs(string nodeGuid, InterruptClass @class)
+ public NodeInterruptStateChangeEventArgs(string nodeGuid,bool isInterrupt)
{
NodeGuid = nodeGuid;
- Class = @class;
+ // Class = @class;
+ IsInterrupt = isInterrupt;
}
///
/// 中断的节点Guid
///
public string NodeGuid { get; protected set; }
- public InterruptClass Class { get; protected set; }
+ public bool IsInterrupt { get; protected set; }
+ // public InterruptClass Class { get; protected set; }
}
///
/// 节点触发了中断事件参数
@@ -638,7 +662,7 @@ namespace Serein.Library.Api
/// 远程环境地址
/// 远程环境端口
/// 密码
- Task<(bool, RemoteEnvControl)> ConnectRemoteEnv(string addres,int port, string token);
+ Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres,int port, string token);
///
/// 退出远程环境
@@ -705,30 +729,53 @@ namespace Serein.Library.Api
/// 目标节点Guid
/// 起始节点控制点
/// 目标节点控制点
- /// 决定了方法执行后的后继行为
- /// 决定了方法入参来源
- Task ConnectNodeAsync(string fromNodeGuid,
+ /// 决定了方法执行后的后继行为
+ Task ConnectInvokeNodeAsync(string fromNodeGuid,
string toNodeGuid,
JunctionType fromNodeJunctionType,
JunctionType toNodeJunctionType,
- ConnectionInvokeType connectionType,
- int argIndex);
+ ConnectionInvokeType invokeType);
///
+ /// 在两个节点之间创建连接关系
+ ///
+ /// 起始节点Guid
+ /// 目标节点Guid
+ /// 起始节点控制点
+ /// 目标节点控制点
+ /// 决定了方法参数来源
+ /// 设置第几个参数
+ Task ConnectArgSourceNodeAsync(string fromNodeGuid,
+ string toNodeGuid,
+ JunctionType fromNodeJunctionType,
+ JunctionType toNodeJunctionType,
+ ConnectionArgSourceType argSourceType,
+ int argIndex);
+ ///
/// 创建节点/区域/基础控件
///
/// 节点/区域/基础控件类型
/// 节点在画布上的位置(
- /// 节点绑定的方法说明(
+ /// 节点绑定的方法说明
Task CreateNodeAsync(NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null);
///
- /// 移除两个节点之间的连接关系
+ /// 移除两个节点之间的方法调用关系
///
/// 起始节点
/// 目标节点
/// 连接类型
- Task RemoveConnectAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType);
+ Task RemoveConnectInvokeAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType);
+
+ ///
+ /// 移除连接节点之间参数传递的关系
+ ///
+ /// 起始节点Guid
+ /// 目标节点Guid
+ /// 连接到第几个参数
+ /// 参数来源类型
+ Task RemoveConnectArgSourceAsync(string fromNodeGuid, string toNodeGuid, int argIndex);
+
///
/// 移除节点/区域/基础控件
@@ -750,12 +797,12 @@ namespace Serein.Library.Api
///
- /// 设置节点中断级别
+ /// 设置节点中断
///
- /// 被中断的节点Guid
- /// 新的中断级别
+ /// 更改中断状态的节点Guid
+ /// 是否中断
///
- Task SetNodeInterruptAsync(string nodeGuid, InterruptClass interruptClass);
+ Task SetNodeInterruptAsync(string nodeGuid,bool isInterrup);
///
/// 添加作用于某个对象的中断表达式
diff --git a/Library/Extension/SereinExtension.cs b/Library/Extension/SereinExtension.cs
new file mode 100644
index 0000000..84e1c95
--- /dev/null
+++ b/Library/Extension/SereinExtension.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Serein.Library
+{
+ ///
+ /// 拓展方法
+ ///
+ public static partial class SereinExtension
+ {
+ ///
+ /// 判断连接类型
+ ///
+ ///
+ ///
+ public static JunctionOfConnectionType ToConnectyionType(this JunctionType start)
+ {
+ if (start == JunctionType.Execute
+ || start == JunctionType.NextStep)
+ {
+ return JunctionOfConnectionType.Invoke;
+ }
+ else
+ {
+ return JunctionOfConnectionType.Arg;
+ }
+ }
+ ///
+ /// 判断是否运行连接
+ ///
+ ///
+ ///
+ ///
+ public static bool IsCanConnection(this JunctionType start,JunctionType end)
+ {
+ if(start == end)
+ {
+ return false;
+ }
+
+ var startType = start.ToConnectyionType();
+ if (startType == JunctionOfConnectionType.Invoke)
+ {
+ return (end == JunctionType.Execute && start == JunctionType.NextStep)
+ || (start == JunctionType.Execute && end == JunctionType.NextStep);
+ }
+ else // if (startType == JunctionOfConnectionType.Arg)
+ {
+ return (end == JunctionType.ArgData && start == JunctionType.ReturnData)
+ || (start == JunctionType.ArgData && end == JunctionType.ReturnData);
+ }
+
+ //var endType = end.ToConnectyionType();
+ //if (startType != endType
+ // || startType == JunctionOfConnectionType.None
+ // || endType == JunctionOfConnectionType.None)
+ //{
+ // return false;
+ //}
+ //else
+ //{
+ // if (startType == JunctionOfConnectionType.Invoke)
+ // {
+
+ // return end == JunctionType.NextStep;
+ // }
+ // else // if (startType == JunctionOfConnectionType.Arg)
+ // {
+ // return end == JunctionType.ReturnData;
+ // }
+ //}
+ }
+
+ }
+}
diff --git a/Library/Entity/DelegateDetails.cs b/Library/FlowNode/DelegateDetails.cs
similarity index 86%
rename from Library/Entity/DelegateDetails.cs
rename to Library/FlowNode/DelegateDetails.cs
index edd7d9e..8da348a 100644
--- a/Library/Entity/DelegateDetails.cs
+++ b/Library/FlowNode/DelegateDetails.cs
@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using static Serein.Library.Utils.EmitHelper;
@@ -14,6 +15,17 @@ namespace Serein.Library
///
public class DelegateDetails
{
+ ///
+ /// 根据方法信息构建Emit委托
+ ///
+ ///
+ public DelegateDetails(MethodInfo methodInfo)
+ {
+ var emitMethodType = EmitHelper.CreateDynamicMethod(methodInfo, out var emitDelegate);
+ _emitMethodType = emitMethodType;
+ _emitDelegate = emitDelegate;
+ }
+
///
/// 记录Emit委托
///
@@ -21,8 +33,8 @@ namespace Serein.Library
///
public DelegateDetails(EmitMethodType EmitMethodType, Delegate EmitDelegate)
{
- this._emitMethodType = EmitMethodType;
- this._emitDelegate = EmitDelegate;
+ _emitMethodType = EmitMethodType;
+ _emitDelegate = EmitDelegate;
}
///
/// 更新委托方法
@@ -56,7 +68,7 @@ namespace Serein.Library
/// void方法自动返回null
public async Task
///
- public abstract Parameterdata[] GetParameterdatas();
+ public abstract ParameterData[] GetParameterdatas();
///
/// 导出为节点信息
@@ -47,7 +47,7 @@ namespace Serein.Library
var upstreamNodes = SuccessorNodes[ConnectionInvokeType.Upstream].Select(item => item.Guid);// 上游分支
// 生成参数列表
- Parameterdata[] parameterData = GetParameterdatas();
+ ParameterData[] parameterData = GetParameterdatas();
return new NodeInfo
{
@@ -82,9 +82,13 @@ namespace Serein.Library
{
for (int i = 0; i < nodeInfo.ParameterData.Length; i++)
{
- Parameterdata pd = nodeInfo.ParameterData[i];
- this.MethodDetails.ParameterDetailss[i].IsExplicitData = pd.State;
- this.MethodDetails.ParameterDetailss[i].DataValue = pd.Value;
+ var mdPd = this.MethodDetails.ParameterDetailss[i];
+ ParameterData pd = nodeInfo.ParameterData[i];
+ mdPd.IsExplicitData = pd.State;
+ mdPd.DataValue = pd.Value;
+ mdPd.ArgDataSourceType = EnumHelper.ConvertEnum(pd.SourceType);
+ mdPd.ArgDataSourceNodeGuid = pd.SourceNodeGuid;
+
}
}
return this;
@@ -93,13 +97,12 @@ namespace Serein.Library
#region 调试中断
-
///
/// 不再中断
///
public void CancelInterrupt()
{
- this.DebugSetting.InterruptClass = InterruptClass.None;
+ this.DebugSetting.IsInterrupt = false;
DebugSetting.CancelInterruptCallback?.Invoke();
}
@@ -165,7 +168,7 @@ namespace Serein.Library
NodeModelBase upstreamNode = upstreamNodes[index];
if (!(upstreamNode is null) && upstreamNode.DebugSetting.IsEnable)
{
- if (upstreamNode.DebugSetting.InterruptClass != InterruptClass.None) // 执行触发前
+ if (upstreamNode.DebugSetting.IsInterrupt) // 执行触发前
{
var cancelType = await upstreamNode.DebugSetting.GetInterruptTask();
await Console.Out.WriteLineAsync($"[{upstreamNode.MethodDetails?.MethodName}]中断已{cancelType},开始执行后继分支");
@@ -220,7 +223,7 @@ namespace Serein.Library
{
#region 调试中断
- if (DebugSetting.InterruptClass != InterruptClass.None) // 执行触发检查是否需要中断
+ if (DebugSetting.IsInterrupt) // 执行触发检查是否需要中断
{
var cancelType = await this.DebugSetting.GetInterruptTask(); // 等待中断结束
await Console.Out.WriteLineAsync($"[{this.MethodDetails?.MethodName}]中断已{cancelType},开始执行后继分支");
@@ -312,8 +315,9 @@ namespace Serein.Library
}
object[] parameters = new object[md.ParameterDetailss.Length];
- var previousFlowData = nodeModel.PreviousNode?.FlowData; // 当前传递的数据
- var previousDataType = previousFlowData?.GetType(); // 当前传递数据的类型
+
+ //var previousFlowData = nodeModel.PreviousNode?.FlowData; // 当前传递的数据
+
for (int i = 0; i < parameters.Length; i++)
{
@@ -336,41 +340,48 @@ namespace Serein.Library
object inputParameter; // 存放解析的临时参数
if (ed.IsExplicitData) // 判断是否使用显示的输入参数
{
- if (ed.DataValue.StartsWith("@get", StringComparison.OrdinalIgnoreCase) && !(previousFlowData is null))
+ if (ed.DataValue.StartsWith("@get", StringComparison.OrdinalIgnoreCase))
{
+ var previousFlowData = context.GetFlowData(nodeModel?.PreviousNode?.Guid); // 当前传递的数据
// 执行表达式从上一节点获取对象
inputParameter = SerinExpressionEvaluator.Evaluate(ed.DataValue, previousFlowData, out _);
}
else
{
// 使用输入的固定值
- inputParameter = ed.DataValue;
+ inputParameter = ed.DataValue;
}
}
else
{
if (ed.ArgDataSourceType == ConnectionArgSourceType.GetPreviousNodeData)
{
- inputParameter = previousFlowData; // 使用运行时上一节点的返回值
+ inputParameter = context.GetFlowData(nodeModel?.PreviousNode?.Guid); // 当前传递的数据
}
- else if (ed.ArgDataSourceType == ConnectionArgSourceType.GetPreviousNodeData)
+ else if (ed.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
{
// 获取指定节点的数据
// 如果指定节点没有被执行,会返回null
// 如果执行过,会获取上一次执行结果作为预入参数据
- inputParameter = ed.ArgDataSourceNodeMoels[i].FlowData;
+ inputParameter = context.GetFlowData(ed.ArgDataSourceNodeGuid);
}
else if (ed.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke)
{
// 立刻调用对应节点获取数据。
- var result = await ed.ArgDataSourceNodeMoels[i].InvokeAsync(nodeModel.Env);
+
+ var result = await context.Env.InvokeNodeAsync(ed.ArgDataSourceNodeGuid);
inputParameter = result;
}
else
{
throw new Exception("节点执行方法获取入参参数时,ConnectionArgSourceType枚举是意外的枚举值");
}
- }
+ }
+ if (inputParameter is null)
+ {
+ throw new Exception($"[arg{ed.Index}][{ed.Name}][{ed.DataType}]参数不能为null");
+ }
+
#endregion
#region 入参存在取值转换器,调用对应的转换器获取入参数据
@@ -418,7 +429,7 @@ namespace Serein.Library
#endregion
#region 对入参数据尝试进行转换
-
+
if (inputParameter.GetType() == ed.DataType)
{
parameters[i] = inputParameter; // 类型一致无需转换,直接装入入参数组
@@ -506,8 +517,8 @@ namespace Serein.Library
{
await MonitorObjExpInterrupt(context, nodeModel, newData, 0); // 首先监视对象
await MonitorObjExpInterrupt(context, nodeModel, newData, 1); // 然后监视节点
- nodeModel.FlowData = newData; // 替换数据
- context.AddOrUpdate(guid, nodeModel); // 上下文中更新数据
+ //nodeModel.FlowData = newData; // 替换数据
+ context.AddOrUpdate(guid, newData); // 上下文中更新数据
}
}
@@ -548,12 +559,13 @@ namespace Serein.Library
if (isExpInterrupt) // 触发中断
{
- InterruptClass interruptClass = InterruptClass.Branch; // 分支中断
- if (await context.Env.SetNodeInterruptAsync(nodeModel.Guid, interruptClass))
+ nodeModel.DebugSetting.IsInterrupt = true;
+ if (await context.Env.SetNodeInterruptAsync(nodeModel.Guid,true))
{
context.Env.TriggerInterrupt(nodeModel.Guid, exp, InterruptTriggerEventArgs.InterruptTriggerType.Exp);
var cancelType = await nodeModel.DebugSetting.GetInterruptTask();
await Console.Out.WriteLineAsync($"[{data}]中断已{cancelType},开始执行后继分支");
+ nodeModel.DebugSetting.IsInterrupt = false;
}
}
}
@@ -561,26 +573,26 @@ namespace Serein.Library
}
}
- ///
- /// 释放对象
- ///
- public void ReleaseFlowData()
- {
- if (typeof(IDisposable).IsAssignableFrom(FlowData?.GetType()) && FlowData is IDisposable disposable)
- {
- disposable?.Dispose();
- }
- this.FlowData = null;
- }
+ /////
+ ///// 释放对象
+ /////
+ //public void ReleaseFlowData()
+ //{
+ // if (typeof(IDisposable).IsAssignableFrom(FlowData?.GetType()) && FlowData is IDisposable disposable)
+ // {
+ // disposable?.Dispose();
+ // }
+ // this.FlowData = null;
+ //}
- ///
- /// 获取节点数据
- ///
- ///
- public object GetFlowData()
- {
- return this.FlowData;
- }
+ /////
+ ///// 获取节点数据
+ /////
+ /////
+ //public object GetFlowData()
+ //{
+ // return this.FlowData;
+ //}
#endregion
}
diff --git a/Library/FlowNode/ParameterDetails.cs b/Library/FlowNode/ParameterDetails.cs
index b5dbce2..683edc5 100644
--- a/Library/FlowNode/ParameterDetails.cs
+++ b/Library/FlowNode/ParameterDetails.cs
@@ -1,4 +1,5 @@
using Serein.Library.Api;
+using Serein.Library.Utils;
using System;
using System.Linq;
@@ -62,11 +63,10 @@ namespace Serein.Library
///
/// 当 ArgDataSourceType 不为 GetPreviousNodeData 时(从运行时上一节点获取数据)。
- /// 则通过该集合对应的节点,获取其 FlowData 作为预处理的入参参数。
+ /// 则通过当前上下文,获取该Guid对应的数据作为预处理的入参参数。
///
- [PropertyInfo(IsProtection = true)]
- public NodeModelBase[] _argDataSourceNodeMoels;
-
+ [PropertyInfo]
+ private string _argDataSourceNodeGuid;
///
@@ -97,6 +97,16 @@ namespace Serein.Library
public partial class ParameterDetails
{
+
+ ///
+ /// 用于创建元数据
+ ///
+ public ParameterDetails()
+ {
+
+ }
+
+
///
/// 为节点实例化新的入参描述
///
@@ -112,27 +122,15 @@ namespace Serein.Library
/// 参数信息
public ParameterDetails(ParameterDetailsInfo info)
{
- //this.env = env;
Index = info.Index;
Name = info.Name;
DataType = Type.GetType(info.DataTypeFullName);
ExplicitType = Type.GetType(info.ExplicitTypeFullName);
ExplicitTypeName = info.ExplicitTypeName;
Items = info.Items;
- }
-
- ///
- /// 用于创建元数据
- ///
- public ParameterDetails()
- {
}
-
-
-
-
///
/// 转为描述
///
@@ -141,12 +139,12 @@ namespace Serein.Library
{
return new ParameterDetailsInfo
{
- Index = Index,
- DataTypeFullName = DataType.FullName,
- Name = Name,
- ExplicitTypeFullName = ExplicitType.FullName,
- ExplicitTypeName = ExplicitTypeName,
- Items = Items,
+ Index = this.Index,
+ DataTypeFullName = this.DataType.FullName,
+ Name = this.Name,
+ ExplicitTypeFullName = this.ExplicitType.FullName,
+ ExplicitTypeName = this.ExplicitTypeName,
+ Items = this.Items.Select(it => it).ToArray(),
};
}
@@ -154,7 +152,7 @@ namespace Serein.Library
/// 为某个节点拷贝方法描述的入参描述
///
/// 运行环境
- /// 运行环境
+ /// 对应的节点
///
public ParameterDetails CloneOfClone(IFlowEnvironment env, NodeModelBase nodeModel)
{
diff --git a/Library/FlowNode/ParameterDetailsInfo.cs b/Library/FlowNode/ParameterDetailsInfo.cs
index 3f8380f..c1feb54 100644
--- a/Library/FlowNode/ParameterDetailsInfo.cs
+++ b/Library/FlowNode/ParameterDetailsInfo.cs
@@ -8,7 +8,7 @@ namespace Serein.Library
{
///
- /// 方法入参描述
+ /// 方法入参描述(远程用)
///
public class ParameterDetailsInfo
{
@@ -26,6 +26,7 @@ namespace Serein.Library
/// 方法入参参数名称
///
public string Name { get; set; }
+
///
/// 显式类型
///
diff --git a/Library/FlowNode/SereinProjectData.cs b/Library/FlowNode/SereinProjectData.cs
index 708dd41..84d1f78 100644
--- a/Library/FlowNode/SereinProjectData.cs
+++ b/Library/FlowNode/SereinProjectData.cs
@@ -202,14 +202,13 @@ namespace Serein.Library
///
/// 参数
///
- public Parameterdata[] ParameterData { get; set; }
+ public ParameterData[] ParameterData { get; set; }
///
/// 如果是区域控件,则会存在子项。
///
public string[] ChildNodeGuids { get; set; }
-
///
/// 于画布中的位置
///
@@ -223,14 +222,26 @@ namespace Serein.Library
}
///
- /// 显示参数,项目文件相关
+ /// 参数信息,项目文件相关
///
- public class Parameterdata
+ public class ParameterData
{
///
/// 参数类型,true时使用自定义的入参,false时由运行环境自动传参
///
public bool State { get; set; }
+
+ ///
+ /// 参数来源节点
+ ///
+ public string SourceNodeGuid { get; set; }
+
+ ///
+ /// 来源类型
+ ///
+ public string SourceType { get; set; }
+
+
///
/// 自定义入参
///
diff --git a/Library/Network/Http/Router.cs b/Library/Network/Http/Router.cs
index d99d594..a2967ee 100644
--- a/Library/Network/Http/Router.cs
+++ b/Library/Network/Http/Router.cs
@@ -17,28 +17,58 @@ using Type = System.Type;
namespace Serein.Library.Web
{
+ ///
+ /// 路由接口
+ ///
public interface IRouter
{
+ ///
+ /// 添加处理模块
+ ///
+ ///
void AddHandle(Type controllerType);
+ ///
+ /// 路由解析开始处理
+ ///
+ ///
+ ///
Task ProcessingAsync(HttpListenerContext context);
}
-
+ ///
+ /// api请求处理模块
+ ///
public class ApiHandleConfig
{
- private readonly Delegate EmitDelegate;
- private readonly EmitHelper.EmitMethodType EmitMethodType;
+ private readonly DelegateDetails delegateDetails;
+ ///
+ /// Post请求处理方法中,入参参数类型
+ ///
public enum PostArgType
{
+ ///
+ /// 不做处理
+ ///
None,
+ ///
+ /// 使用Url参数
+ ///
IsUrlData,
+ ///
+ /// 使用整体的Boby参数
+ ///
IsBobyData,
}
+
+ ///
+ /// 添加处理配置
+ ///
+ ///
public ApiHandleConfig(MethodInfo methodInfo)
{
- EmitMethodType = EmitHelper.CreateDynamicMethod(methodInfo, out EmitDelegate);
+ delegateDetails = new DelegateDetails(methodInfo);
var parameterInfos = methodInfo.GetParameters();
ParameterType = parameterInfos.Select(t => t.ParameterType).ToArray();
ParameterName = parameterInfos.Select(t => t.Name.ToLower()).ToArray();
@@ -68,7 +98,12 @@ namespace Serein.Library.Web
private readonly string[] ParameterName;
private readonly Type[] ParameterType;
-
+ ///
+ /// 处理Get请求
+ ///
+ ///
+ ///
+ ///
public async Task HandleGet(object instance, Dictionary routeData)
{
object[] args = new object[ParameterType.Length];
@@ -93,40 +128,20 @@ namespace Serein.Library.Web
}
}
-
- object result;
+ object result = null;
try
{
- if (EmitMethodType == EmitHelper.EmitMethodType.HasResultTask && EmitDelegate is Func> hasResultTask)
- {
- result = await hasResultTask(instance, args);
- }
- else if (EmitMethodType == EmitHelper.EmitMethodType.Task && EmitDelegate is Func task)
- {
- await task.Invoke(instance, args);
- result = null;
- }
- else if (EmitMethodType == EmitHelper.EmitMethodType.Func && EmitDelegate is Func func)
- {
- result = func.Invoke(instance, args);
- }
- else
- {
- result = null;
- }
+ result = await delegateDetails.InvokeAsync(instance, args);
}
catch (Exception ex)
{
result = null;
await Console.Out.WriteLineAsync(ex.Message);
-
}
return result;
-
}
-
-
+ ///
public async Task HandlePost(object instance, JObject jsonObject, Dictionary routeData)
{
object[] args = new object[ParameterType.Length];
@@ -173,26 +188,10 @@ namespace Serein.Library.Web
}
- object result;
+ object result = null;
try
{
- if (EmitMethodType == EmitHelper.EmitMethodType.HasResultTask && EmitDelegate is Func> hasResultTask)
- {
- result = await hasResultTask(instance, args);
- }
- else if (EmitMethodType == EmitHelper.EmitMethodType.Task && EmitDelegate is Func task)
- {
- await task.Invoke(instance, args);
- result = null;
- }
- else if (EmitMethodType == EmitHelper.EmitMethodType.Func && EmitDelegate is Func func)
- {
- result = func.Invoke(instance, args);
- }
- else
- {
- result = null;
- }
+ result = await delegateDetails.InvokeAsync(instance, args);
}
catch (Exception ex)
{
@@ -567,107 +566,6 @@ namespace Serein.Library.Web
}
-
- internal static class WebFunc
- {
- public static bool ToBool(this JToken token, bool defult = false)
- {
- var value = token?.ToString();
- if (string.IsNullOrWhiteSpace(value))
- {
- return defult;
- }
- if (!bool.TryParse(value, out bool result))
- {
- return defult;
- }
- else
- {
- return result;
- }
- }
- public static int ToInt(this JToken token, int defult = 0)
- {
- var value = token?.ToString();
- if (string.IsNullOrWhiteSpace(value))
- {
- return defult;
- }
- if (!int.TryParse(value, out int result))
- {
- return defult;
- }
- else
- {
- return result;
- }
- }
- public static double ToDouble(this JToken token, double defult = 0)
- {
- var value = token?.ToString();
- if (string.IsNullOrWhiteSpace(value))
- {
- return defult;
- }
- if (!int.TryParse(value, out int result))
- {
- return defult;
- }
- else
- {
- return result;
- }
- }
- }
-
- #region 已经注释
-
- // private readonly ConcurrentDictionary _controllerAutoHosting; // 存储是否实例化
- // private readonly ConcurrentDictionary _controllerInstances;
-
- //public void CollectRoutes(Type controllerType)
- //{
- // string controllerName = controllerType.Name.Replace("Controller", "").ToLower(); // 获取控制器名称并转换为小写
- // foreach (var method in controllerType.GetMethods()) // 遍历控制器类型的所有方法
- // {
- // var routeAttribute = method.GetCustomAttribute(); // 获取方法上的 WebAPIAttribute 自定义属性
- // if (routeAttribute != null) // 如果存在 WebAPIAttribute 属性
- // {
- // var customUrl = routeAttribute.Url; // 获取自定义 URL
- // string url;
- // if (string.IsNullOrEmpty(customUrl)) // 如果自定义 URL 为空
- // {
- // url = $"/api/{controllerName}/{method.Name}".ToLower(); // 构建默认 URL
- // }
- // else
- // {
- // customUrl = CleanUrl(customUrl);
- // url = $"/api/{controllerName}/{method.Name}/{customUrl}".ToLower();// 清理自定义 URL,并构建新的 URL
- // }
- // var httpMethod = routeAttribute.Http; // 获取 HTTP 方法
- // _routes[httpMethod.ToString()].TryAdd(url, method); // 将 URL 和方法添加到对应的路由字典中
- // }
- // }
- //}
-
- //public void RegisterRoute(T controllerInstance) // 方法声明,用于动态注册路由
- //{
- // Type controllerType = controllerInstance.GetType(); // 获取控制器实例的类型
- // var autoHostingAttribute = controllerType.GetCustomAttribute();
- // foreach (var method in controllerType.GetMethods()) // 遍历控制器类型的所有方法
- // {
- // var webAttribute = method.GetCustomAttribute(); // 获取方法上的 WebAPIAttribute 自定义属性
- // if (webAttribute != null) // 如果存在 WebAPIAttribute 属性
- // {
- // var url = AddRoutesUrl(autoHostingAttribute, webAttribute, controllerType, method);
- // if (url == null) continue;
- // _controllerInstances[url] = controllerInstance;
- // _controllerAutoHosting[url] = false;
- // }
-
- // }
- //}
-
- #endregion
+
}
diff --git a/Library/Network/Http/SereinExtension.cs b/Library/Network/Http/SereinExtension.cs
new file mode 100644
index 0000000..cafaa6f
--- /dev/null
+++ b/Library/Network/Http/SereinExtension.cs
@@ -0,0 +1,64 @@
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Serein.Library.Network.Http
+{
+ internal static partial class SereinExtension
+ {
+ #region JSON相关
+
+ public static bool ToBool(this JToken token, bool defult = false)
+ {
+ var value = token?.ToString();
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ return defult;
+ }
+ if (!bool.TryParse(value, out bool result))
+ {
+ return defult;
+ }
+ else
+ {
+ return result;
+ }
+ }
+ public static int ToInt(this JToken token, int defult = 0)
+ {
+ var value = token?.ToString();
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ return defult;
+ }
+ if (!int.TryParse(value, out int result))
+ {
+ return defult;
+ }
+ else
+ {
+ return result;
+ }
+ }
+ public static double ToDouble(this JToken token, double defult = 0)
+ {
+ var value = token?.ToString();
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ return defult;
+ }
+ if (!int.TryParse(value, out int result))
+ {
+ return defult;
+ }
+ else
+ {
+ return result;
+ }
+ }
+ #endregion
+ }
+}
diff --git a/Library/Network/WebSocket/Handle/JsonMsgHandleConfig.cs b/Library/Network/WebSocket/Handle/JsonMsgHandleConfig.cs
index 5bbc321..7ffdd2e 100644
--- a/Library/Network/WebSocket/Handle/JsonMsgHandleConfig.cs
+++ b/Library/Network/WebSocket/Handle/JsonMsgHandleConfig.cs
@@ -31,7 +31,7 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
Action> onExceptionTracking,
bool ArgNotNull)
{
- EmitMethodType = EmitHelper.CreateDynamicMethod(methodInfo,out EmitDelegate);
+ DelegateDetails = new DelegateDetails(methodInfo);
this.Module = model;
Instance = instance;
var parameterInfos = methodInfo.GetParameters();
@@ -72,15 +72,10 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
/// 参数不能为空
///
private bool ArgNotNull;
-
///
/// Emit委托
///
- private readonly Delegate EmitDelegate;
- ///
- /// Emit委托类型
- ///
- private readonly EmitHelper.EmitMethodType EmitMethodType;
+ private readonly DelegateDetails DelegateDetails;
///
/// 未捕获的异常跟踪
///
@@ -114,29 +109,26 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
///
private readonly bool[] IsCheckArgNotNull;
- //private object ConvertArg(Type type, string argName )
- //{
-
- //}
-
public async void Handle(Func SendAsync,string msgId, JObject jsonObject)
{
object[] args = new object[ParameterType.Length];
bool isCanInvoke = true;; // 表示是否可以调用方法
for (int i = 0; i < ParameterType.Length; i++)
{
- var type = ParameterType[i];
- var argName = ParameterName[i];
- #region DATA JSON数据
- if (useData[i])
- {
- args[i] = jsonObject.ToObject(type);
- }
- #endregion
- else if (useMsgId[i])
+ var type = ParameterType[i]; // 入参变量类型
+ var argName = ParameterName[i]; // 入参参数名称
+ #region 传递消息ID
+ if (useMsgId[i])
{
args[i] = msgId;
}
+ #endregion
+ #region DATA JSON数据
+ else if (useData[i])
+ {
+ args[i] = jsonObject.ToObject(type);
+ }
+ #endregion
#region 值类型参数
else if (type.IsValueType)
{
@@ -229,23 +221,7 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
object result;
try
{
- if (EmitMethodType == EmitHelper.EmitMethodType.HasResultTask && EmitDelegate is Func> hasResultTask)
- {
- result = await hasResultTask(Instance, args);
- }
- else if (EmitMethodType == EmitHelper.EmitMethodType.Task && EmitDelegate is Func task)
- {
- await task.Invoke(Instance, args);
- result = null;
- }
- else if (EmitMethodType == EmitHelper.EmitMethodType.Func && EmitDelegate is Func func)
- {
- result = func.Invoke(Instance, args);
- }
- else
- {
- result = null;
- }
+ result = await DelegateDetails.InvokeAsync(Instance, args);
}
catch (Exception ex)
{
@@ -256,25 +232,11 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
await SendAsync.Invoke(exData);
}));
}
- //sw.Stop();
- //Console.WriteLine($"Emit Invoke:{sw.ElapsedTicks * 1000000F / Stopwatch.Frequency:n3}μs");
-
-
+
if (Module.IsReturnValue)
{
- if (result is null)
- {
- result = "null";
- }
_ = SendAsync.Invoke(result);
}
- //if( && result != null && result.GetType().IsClass)
- //{
- // //var reusltJsonText = JsonConvert.SerializeObject(result);
-
- // //_ = SendAsync.Invoke($"{reusltJsonText}");
- //}
-
}
diff --git a/Library/Network/WebSocket/Handle/WebSocketHandleModule.cs b/Library/Network/WebSocket/Handle/WebSocketHandleModule.cs
index 4db7922..ea92151 100644
--- a/Library/Network/WebSocket/Handle/WebSocketHandleModule.cs
+++ b/Library/Network/WebSocket/Handle/WebSocketHandleModule.cs
@@ -91,6 +91,8 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
MyHandleConfigs.Clear();
}
+ private HashSet _myMsgIdHash = new HashSet();
+
///
/// 处理JSON数据
///
@@ -106,11 +108,15 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
return;
}
string msgId = jsonObject.GetValue(MsgIdJsonKey)?.ToString();
-
+ if (_myMsgIdHash.Contains(msgId))
+ {
+ Console.WriteLine($"[{msgId}]{theme} 消息重复");
+ return;
+ }
+ _myMsgIdHash.Add(msgId);
try
{
-
JObject dataObj = jsonObject.GetValue(DataJsonKey)?.ToObject();
handldConfig.Handle(async (data) =>
{
@@ -170,9 +176,8 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
}
var msg = jsonData.ToString();
- //Console.WriteLine(msg);
- //Console.WriteLine();
-
+
+
await sendAsync.Invoke(msg);
}
diff --git a/Library/Network/WebSocket/Handle/WebSocketMsgHandleHelper.cs b/Library/Network/WebSocket/Handle/WebSocketMsgHandleHelper.cs
index 1a4bc78..24b2c63 100644
--- a/Library/Network/WebSocket/Handle/WebSocketMsgHandleHelper.cs
+++ b/Library/Network/WebSocket/Handle/WebSocketMsgHandleHelper.cs
@@ -155,21 +155,16 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
///
/// 异步处理消息
///
- ///
+ ///
///
///
- public async Task HandleMsgAsync(Func SendAsync, string message)
+ public void HandleMsg(Func sendAsync, string message)
{
- //Console.WriteLine(message);
JObject json = JObject.Parse(message);
- await Task.Run(() =>
+ foreach (var module in MyHandleModuleDict.Values)
{
- foreach (var module in MyHandleModuleDict.Values)
- {
- module.HandleSocketMsg(SendAsync, json);
-
- }
- });
+ module.HandleSocketMsg(sendAsync, json);
+ }
}
diff --git a/Library/Network/WebSocket/SocketControlBase.cs b/Library/Network/WebSocket/SocketControlBase.cs
index a736bbf..e194fae 100644
--- a/Library/Network/WebSocket/SocketControlBase.cs
+++ b/Library/Network/WebSocket/SocketControlBase.cs
@@ -8,28 +8,4 @@ namespace Serein.Library.Network.WebSocketCommunication
}
- //[AutoRegister(RegisterSequence.FlowLoading)]
- //[AutoSocketModule(JsonThemeField = "theme", JsonDataField = "data")]
- //public class UserService : ISocketControlBase
- //{
- // public Guid HandleGuid { get; } = new Guid();
-
- // // Action 类型是特殊的,会用一个委托代替,这个委托可以将文本信息发送到客户端
- // // Action 类型是特殊的,会用一个委托代替,这个委托可以将对象转成json发送到客户端
-
- // [AutoSocketHandle]
- // public void AddUser(User user,Action Recover)
- // {
- // Console.WriteLine(user.ToString());
- // Recover("ok");
- // }
-
- // [AutoSocketHandle(ThemeValue = "Remote")]
- // public void DeleteUser(User user, Action Recover)
- // {
- // Console.WriteLine(user.ToString());
- // }
-
- //}
-
}
diff --git a/Library/Network/WebSocket/TestExtension.cs b/Library/Network/WebSocket/TestExtension.cs
new file mode 100644
index 0000000..02acb67
--- /dev/null
+++ b/Library/Network/WebSocket/TestExtension.cs
@@ -0,0 +1,73 @@
+using Serein.Library.Utils;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.WebSockets;
+using System.Text;
+using System.Threading;
+using System.Threading.Channels;
+using System.Threading.Tasks;
+
+namespace Serein.Library.Network.WebSocketCommunication
+{
+ public class MsgQueueUtil
+ {
+ public ConcurrentQueue Msgs = new ConcurrentQueue();
+
+ private readonly Channel _msgChannel;
+ public MsgQueueUtil()
+ {
+ _msgChannel = CreateChannel();
+ }
+
+ private Channel CreateChannel()
+ {
+ return Channel.CreateBounded(new BoundedChannelOptions(100)
+ {
+ FullMode = BoundedChannelFullMode.Wait
+ });
+ }
+
+ ///
+ /// 等待消息
+ ///
+ ///
+ public async Task WaitMsgAsync()
+ {
+ var state = await _msgChannel.Reader.ReadAsync();
+ return state;
+ }
+
+ public void WriteMsg(string msg)
+ {
+ //Msgs.Enqueue(msg);
+ Console.WriteLine($"{DateTime.Now}{msg}{Environment.NewLine}");
+ _ = _msgChannel.Writer.WriteAsync(msg);
+ }
+
+ public bool TryGetMsg(out string msg)
+ {
+ return Msgs.TryDequeue(out msg);
+ }
+
+
+ }
+
+
+
+ public class SocketExtension
+ {
+ ///
+ /// 发送消息
+ ///
+ ///
+ ///
+ ///
+ public static async Task SendAsync(WebSocket webSocket, string message)
+ {
+ var buffer = Encoding.UTF8.GetBytes(message);
+ await webSocket.SendAsync(new ArraySegment(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
+ }
+ }
+}
diff --git a/Library/Network/WebSocket/WebSocketClient.cs b/Library/Network/WebSocket/WebSocketClient.cs
index 23f1af5..ba72748 100644
--- a/Library/Network/WebSocket/WebSocketClient.cs
+++ b/Library/Network/WebSocket/WebSocketClient.cs
@@ -1,10 +1,13 @@
using Serein.Library.Network.WebSocketCommunication.Handle;
using System;
using System.Diagnostics;
+using System.IO.Compression;
+using System.IO;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using static System.Net.Mime.MediaTypeNames;
namespace Serein.Library.Network.WebSocketCommunication
{
@@ -38,7 +41,6 @@ namespace Serein.Library.Network.WebSocketCommunication
{
try
{
-
await _client.ConnectAsync(new Uri(uri), CancellationToken.None);
_ = ReceiveAsync();
return true;
@@ -58,8 +60,12 @@ namespace Serein.Library.Network.WebSocketCommunication
///
public async Task SendAsync(string message)
{
- var buffer = Encoding.UTF8.GetBytes(message);
- await _client.SendAsync(new ArraySegment(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
+ Console.WriteLine("发送消息");
+ await Task.Delay(2000);
+ await SocketExtension.SendAsync(this._client, message); // 回复客户端
+ Console.WriteLine();
+ //var buffer = Encoding.UTF8.GetBytes(message);
+ //await _client.SendAsync(new ArraySegment(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
}
///
@@ -68,13 +74,21 @@ namespace Serein.Library.Network.WebSocketCommunication
///
private async Task ReceiveAsync()
{
- var buffer = new byte[1024];
+
+ var msgQueueUtil = new MsgQueueUtil();
+ _ = Task.Run(async () =>
+ {
+ await HandleMsgAsync(_client, msgQueueUtil);
+ });
+
+
var receivedMessage = new StringBuilder(); // 用于拼接长消息
while (_client.State == WebSocketState.Open)
{
try
{
+ var buffer = new byte[1024];
WebSocketReceiveResult result;
do
@@ -86,21 +100,22 @@ namespace Serein.Library.Network.WebSocketCommunication
receivedMessage.Append(partialMessage);
} while (!result.EndOfMessage); // 判断是否已经收到完整消息
-
+ var message = receivedMessage.ToString();
+ msgQueueUtil.WriteMsg(message);
+ receivedMessage.Clear(); // 清空 StringBuilder 为下一条消息做准备
// 处理收到的完整消息
if (result.MessageType == WebSocketMessageType.Close)
{
await _client.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
}
- else
- {
- var completeMessage = receivedMessage.ToString();
- _ = MsgHandleHelper.HandleMsgAsync(SendAsync, completeMessage); // 处理消息
- //Debug.WriteLine($"Received: {completeMessage}");
- }
-
- // 清空 StringBuilder 为下一条消息做准备
- receivedMessage.Clear();
+ //else
+ //{
+ // var completeMessage = receivedMessage.ToString();
+ // MsgHandleHelper.HandleMsg(SendAsync, completeMessage); // 处理消息,如果方法入参是需要发送消息委托时,将 SendAsync 作为委托参数提供
+ // //Debug.WriteLine($"Received: {completeMessage}");
+ //}
+
+
}
catch (Exception ex)
{
@@ -110,65 +125,86 @@ namespace Serein.Library.Network.WebSocketCommunication
}
- /* #region 消息处理
- private readonly string ThemeField;
- private readonly ConcurrentDictionary ThemeConfigs = new ConcurrentDictionary();
-
- public async Task HandleSocketMsg(string jsonStr)
+ public async Task HandleMsgAsync(WebSocket webSocket,
+ MsgQueueUtil msgQueueUtil)
{
- JObject json;
- try
- {
- json = JObject.Parse(jsonStr);
- }
- catch (Exception ex)
- {
- await SendAsync(_client, ex.Message);
- return;
- }
- // 获取到消息
- string themeName = json[ThemeField]?.ToString();
- if (!ThemeConfigs.TryGetValue(themeName, out var handldConfig))
- {
- return;
- }
- object dataValue;
- if (string.IsNullOrEmpty(handldConfig.DataField))
+ while (true)
{
- dataValue = json.ToObject(handldConfig.DataType);
- }
- else
- {
- dataValue = json[handldConfig.DataField].ToObject(handldConfig.DataType);
- }
- await handldConfig.Invoke(dataValue, SendAsync);
- }
-
- public void AddConfig(string themeName, Type dataType, MsgHandler msgHandler)
- {
- if (!ThemeConfigs.TryGetValue(themeName, out var handldConfig))
- {
- handldConfig = new HandldConfig
+ var message = await msgQueueUtil.WaitMsgAsync(); // 有消息时通知
+ //if (!msgQueueUtil.TryGetMsg(out var message)) // 获取消息
+ //{
+ // return;
+ //}
+ // 消息处理
+ MsgHandleHelper.HandleMsg(async (text) =>
{
- DataField = themeName,
- DataType = dataType
- };
- ThemeConfigs.TryAdd(themeName, handldConfig);
+ await SocketExtension.SendAsync(webSocket, text); // 回复客户端,处理方法中入参如果需要发送消息委托,则将该回调方法作为委托参数传入
+ }, message); // 处理消息
+
}
- handldConfig.HandldAsync += msgHandler;
- }
- public void RemoteConfig(string themeName, MsgHandler msgHandler)
- {
- if (ThemeConfigs.TryGetValue(themeName, out var handldConfig))
+
+
+ /* #region 消息处理
+ private readonly string ThemeField;
+ private readonly ConcurrentDictionary ThemeConfigs = new ConcurrentDictionary();
+
+ public async Task HandleSocketMsg(string jsonStr)
{
- handldConfig.HandldAsync -= msgHandler;
- if (!handldConfig.HasSubscribers)
+ JObject json;
+ try
{
- ThemeConfigs.TryRemove(themeName, out _);
+ json = JObject.Parse(jsonStr);
+ }
+ catch (Exception ex)
+ {
+ await SendAsync(_client, ex.Message);
+ return;
+ }
+ // 获取到消息
+ string themeName = json[ThemeField]?.ToString();
+ if (!ThemeConfigs.TryGetValue(themeName, out var handldConfig))
+ {
+ return;
+ }
+
+ object dataValue;
+ if (string.IsNullOrEmpty(handldConfig.DataField))
+ {
+ dataValue = json.ToObject(handldConfig.DataType);
+ }
+ else
+ {
+ dataValue = json[handldConfig.DataField].ToObject(handldConfig.DataType);
+ }
+ await handldConfig.Invoke(dataValue, SendAsync);
+ }
+
+ public void AddConfig(string themeName, Type dataType, MsgHandler msgHandler)
+ {
+ if (!ThemeConfigs.TryGetValue(themeName, out var handldConfig))
+ {
+ handldConfig = new HandldConfig
+ {
+ DataField = themeName,
+ DataType = dataType
+ };
+ ThemeConfigs.TryAdd(themeName, handldConfig);
+ }
+ handldConfig.HandldAsync += msgHandler;
+ }
+ public void RemoteConfig(string themeName, MsgHandler msgHandler)
+ {
+ if (ThemeConfigs.TryGetValue(themeName, out var handldConfig))
+ {
+ handldConfig.HandldAsync -= msgHandler;
+ if (!handldConfig.HasSubscribers)
+ {
+ ThemeConfigs.TryRemove(themeName, out _);
+ }
}
}
+ #endregion*/
}
- #endregion*/
}
}
diff --git a/Library/Network/WebSocket/WebSocketServer.cs b/Library/Network/WebSocket/WebSocketServer.cs
index e65c58f..6c1da9c 100644
--- a/Library/Network/WebSocket/WebSocketServer.cs
+++ b/Library/Network/WebSocket/WebSocketServer.cs
@@ -180,67 +180,46 @@ namespace Serein.Library.Network.WebSocketCommunication
return;
}
+ var msgQueueUtil = new MsgQueueUtil();
+ _ = Task.Run(async () =>
+ {
+ await HandleMsgAsync(webSocket,msgQueueUtil, authorizedHelper);
+ });
+
//Func SendAsync = async (text) =>
//{
// await WebSocketServer.SendAsync(webSocket, text);
//};
- var buffer = new byte[1024];
var receivedMessage = new StringBuilder(); // 用于拼接长消息
- while (webSocket.State == WebSocketState.Open)
+ while ( webSocket.State == WebSocketState.Open)
{
- WebSocketReceiveResult result;
-
+
try
{
+ WebSocketReceiveResult result;
+ var buffer = new byte[1024];
do
{
result = await webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None);
-
+ if (result.MessageType == WebSocketMessageType.Close)
+ {
+ await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
+ if (IsCheckToken)
+ {
+ AuthorizedClients.TryRemove(authorizedHelper.AddresPort, out var _);
+ }
+ }
// 将接收到的部分消息解码并拼接
var partialMessage = Encoding.UTF8.GetString(buffer, 0, result.Count);
receivedMessage.Append(partialMessage);
} while (!result.EndOfMessage); // 循环直到接收到完整的消息
-
// 完整消息已经接收到,准备处理
- var message = receivedMessage.ToString();
-
- if (result.MessageType == WebSocketMessageType.Close)
- {
- //SendAsync = null;
- await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
- if (IsCheckToken)
- {
- AuthorizedClients.TryRemove(authorizedHelper.AddresPort, out var _);
- }
- }
- else
- {
- if (IsCheckToken)
- {
- var authorizedResult = await authorizedHelper.HandleAuthorized(message); // 尝试检测授权
- if (!authorizedResult) // 授权失败
- {
- await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
- if (IsCheckToken)
- {
- AuthorizedClients.TryRemove(authorizedHelper.AddresPort, out var _);
- }
- continue;
- }
- }
-
- // 消息处理
- _ = MsgHandleHelper.HandleMsgAsync(async (text) =>
- {
- await WebSocketServer.SendAsync(webSocket, text);
- }, message); // 处理消息
- }
-
- // 清空 StringBuilder 为下一条消息做准备
- receivedMessage.Clear();
+ var message = receivedMessage.ToString(); // 获取消息文本
+ receivedMessage.Clear(); // 清空 StringBuilder 为下一条消息做准备
+ msgQueueUtil.WriteMsg(message); // 处理消息
}
catch (Exception ex)
{
@@ -249,17 +228,45 @@ namespace Serein.Library.Network.WebSocketCommunication
}
}
}
- ///
- /// 发送消息
- ///
- ///
- ///
- ///
- public static async Task SendAsync(WebSocket webSocket, string message)
+
+
+ public async Task HandleMsgAsync(WebSocket webSocket,
+ MsgQueueUtil msgQueueUtil,
+ WebSocketAuthorizedHelper authorizedHelper)
{
- var buffer = Encoding.UTF8.GetBytes(message);
- await webSocket.SendAsync(new ArraySegment(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
+
+ while (true)
+ {
+ var message = await msgQueueUtil.WaitMsgAsync(); // 有消息时通知
+ //if (!msgQueueUtil.TryGetMsg(out var message)) // 获取消息
+ //{
+ // return;
+ //}
+ if (IsCheckToken)
+ {
+ var authorizedResult = await authorizedHelper.HandleAuthorized(message); // 尝试检测授权
+ if (!authorizedResult) // 授权失败
+ {
+ await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
+ if (IsCheckToken)
+ {
+ AuthorizedClients.TryRemove(authorizedHelper.AddresPort, out var _);
+ }
+ return;
+ }
+ }
+ // 消息处理
+ MsgHandleHelper.HandleMsg(async (text) =>
+ {
+ await SocketExtension.SendAsync(webSocket, text); // 回复客户端,处理方法中入参如果需要发送消息委托,则将该回调方法作为委托参数传入
+ }, message); // 处理消息
+
+ }
+
}
}
+
+
+
}
diff --git a/Library/Serein.Library.csproj b/Library/Serein.Library.csproj
index b62df21..be41dc9 100644
--- a/Library/Serein.Library.csproj
+++ b/Library/Serein.Library.csproj
@@ -1,7 +1,7 @@
- 1.0.17
+ 1.0.18
net8.0;net462
D:\Project\C#\DynamicControl\SereinFlow\.Output
@@ -37,7 +37,6 @@
-
diff --git a/Library/Utils/ChannelFlowTrigger.cs b/Library/Utils/ChannelFlowTrigger.cs
index fe63503..34a5d5e 100644
--- a/Library/Utils/ChannelFlowTrigger.cs
+++ b/Library/Utils/ChannelFlowTrigger.cs
@@ -100,4 +100,14 @@ namespace Serein.Library.Utils
return _channels.GetOrAdd(signal, _ => Channel.CreateUnbounded<(TriggerType, object)>());
}
}
+
+
+
+
+
+
+
+
+
+
}
diff --git a/Library/Utils/RemoteEnvControl.cs b/Library/Utils/RemoteMsgUtil.cs
similarity index 91%
rename from Library/Utils/RemoteEnvControl.cs
rename to Library/Utils/RemoteMsgUtil.cs
index 15e8cab..deb7b06 100644
--- a/Library/Utils/RemoteEnvControl.cs
+++ b/Library/Utils/RemoteMsgUtil.cs
@@ -13,7 +13,7 @@ namespace Serein.Library.Utils
///
/// 管理远程环境,具备连接、发送消息、停止的功能
///
- public class RemoteEnvControl
+ public class RemoteMsgUtil
{
///
/// 远程环境配置
@@ -52,7 +52,7 @@ namespace Serein.Library.Utils
///
/// 配置远程连接IP端口
///
- public RemoteEnvControl(ControlConfiguration controlConfiguration)
+ public RemoteMsgUtil(ControlConfiguration controlConfiguration)
{
Config = controlConfiguration;
}
@@ -120,13 +120,6 @@ namespace Serein.Library.Utils
///
public async Task SendAsync(string msgId , string theme, object data)
{
- //var sendMsg = new
- //{
- // theme = theme,
- // token = this.Token,
- // data = data,
- //};
- //var msg = JsonConvert.SerializeObject(sendMsg);
JObject jsonData;
if (data is null)
@@ -156,11 +149,8 @@ namespace Serein.Library.Utils
[Config.DataJsonKey] = dataToken
};
}
-
var msg = jsonData.ToString();
- //Console.WriteLine(msg);
- //Console.WriteLine();
-
+ Console.WriteLine($"[{msgId}] => {theme}");
await EnvClient.SendAsync(msg);
}
diff --git a/NodeFlow/Env/EnvMsgTheme.cs b/NodeFlow/Env/EnvMsgTheme.cs
index 04fe42a..c1f8afc 100644
--- a/NodeFlow/Env/EnvMsgTheme.cs
+++ b/NodeFlow/Env/EnvMsgTheme.cs
@@ -30,21 +30,31 @@
///
public const string SetStartNode = nameof(SetStartNode);
///
- /// 尝试连接两个节点
- ///
- public const string ConnectNode = nameof(ConnectNode);
- ///
/// 尝试创建节点
///
public const string CreateNode = nameof(CreateNode);
///
- /// 尝试移除节点之间的连接关系
- ///
- public const string RemoveConnect = nameof(RemoveConnect);
- ///
/// 尝试移除节点
///
public const string RemoveNode = nameof(RemoveNode);
+ ///
+ /// 尝试连接两个节点的方法调用关系
+ ///
+ public const string ConnectInvokeNode = nameof(ConnectInvokeNode);
+ ///
+ /// 尝试移除节点之间的方法调用关系
+ ///
+ public const string RemoveInvokeConnect = nameof(RemoveInvokeConnect);
+
+ ///
+ /// 尝试连接两个节点的参数传递关系
+ ///
+ public const string ConnectArgSourceNode = nameof(ConnectArgSourceNode);
+ ///
+ /// 尝试移除节点之间的参数传递关系
+ ///
+ public const string RemoveArgSourceConnect = nameof(RemoveArgSourceConnect);
+
///
/// 激活一个触发器
///
diff --git a/NodeFlow/Env/FlowEnvironment.cs b/NodeFlow/Env/FlowEnvironment.cs
index 9309e25..10f3f94 100644
--- a/NodeFlow/Env/FlowEnvironment.cs
+++ b/NodeFlow/Env/FlowEnvironment.cs
@@ -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);
}
///
@@ -346,18 +347,11 @@ namespace Serein.NodeFlow.Env
List initMethods = [];
List loadMethods = [];
List 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
///
public async Task 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
/// 获取当前环境信息(远程连接)
///
///
- // [AutoSocketHandle]
public async Task GetEnvInfoAsync()
{
Dictionary> 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
/// 远程环境地址
/// 远程环境端口
/// 密码
- 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);
}
///
@@ -908,19 +900,18 @@ namespace Serein.NodeFlow.Env
}
///
- /// 连接节点
+ /// 连接节点,创建方法调用关系
///
/// 起始节点
/// 目标节点
/// 起始节点控制点
/// 目标节点控制点
- /// 连接关系
- public async Task ConnectNodeAsync(string fromNodeGuid,
+ /// 连接关系
+ public async Task 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;
+
+ }
+
+ ///
+ /// 创建节点之间的参数来源关系
+ ///
+ /// 起始节点
+ /// 目标节点
+ /// 起始节点控制点(result控制点)
+ /// 目标节点控制点(argData控制点)
+ /// 目标节点的第几个参数
+ /// 调用目标节点对应方法时,对应参数来源类型
+ ///
+ public async Task 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;
}
///
- /// 移除连接关系
+ /// 移除连接节点之间方法调用的关系
///
/// 起始节点Guid
/// 目标节点Guid
/// 连接关系
///
- public async Task RemoveConnectAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
+ public async Task 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;
}
+ ///
+ /// 移除连接节点之间参数传递的关系
+ ///
+ /// 起始节点Guid
+ /// 目标节点Guid
+ /// 连接到第几个参数
+ public async Task 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;
+ }
+
+
///
/// 获取方法描述
///
@@ -1077,41 +1105,39 @@ namespace Serein.NodeFlow.Env
/// 被中断的目标节点Guid
/// 中断级别
/// 操作是否成功
- public Task SetNodeInterruptAsync(string nodeGuid, InterruptClass interruptClass)
+ public Task 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 私有方法
-
-
-
-
///
/// 加载指定路径的DLL文件
///
@@ -1375,11 +1397,31 @@ namespace Serein.NodeFlow.Env
connectionType,
NodeConnectChangeEventArgs.ConnectChangeType.Remote)));
}
- //else if (OperatingSystem.IsLinux())
- //{
-
- //}
+ return true;
+ }
+ ///
+ /// 移除连接关系
+ ///
+ /// 起始节点Model
+ /// 目标节点Model
+ /// 连接关系
+ ///
+ private async Task 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
}
}
-
-
///
/// 创建节点
///
///
-
private bool TryAddNode(NodeModelBase nodeModel)
{
nodeModel.Guid ??= Guid.NewGuid().ToString();
@@ -1503,10 +1542,6 @@ namespace Serein.NodeFlow.Env
return true;
}
-
-
-
-
///
/// 检查连接
///
@@ -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);
}
-
///
/// 连接节点
///
/// 起始节点
/// 目标节点
- /// 连接关系
- private bool ConnectInvokeOfNode(NodeModelBase fromNode, NodeModelBase toNode, ConnectionInvokeType connectionType)
+ /// 连接关系
+ 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
///
///
///
- 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;
}
diff --git a/NodeFlow/Env/FlowEnvironmentDecorator.cs b/NodeFlow/Env/FlowEnvironmentDecorator.cs
index b8577d9..9d4164c 100644
--- a/NodeFlow/Env/FlowEnvironmentDecorator.cs
+++ b/NodeFlow/Env/FlowEnvironmentDecorator.cs
@@ -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; // 使用原子自增代替锁
///
/// 传入false时,将停止数据通知。传入true时,
///
///
- public void SetFlag(bool value)
+ public void SetProjectLoadingFlag(bool value)
{
- Interlocked.Exchange(ref _flag, value ? 1 : 0);
+ Interlocked.Exchange(ref _loadingProjectFlag, value ? 1 : 0);
}
///
- ///
+ /// 判断是否正在加载项目
///
///
- 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 ConnectNodeAsync(string fromNodeGuid,
+ ///
+ /// 在两个节点之间创建连接关系
+ ///
+ /// 起始节点Guid
+ /// 目标节点Guid
+ /// 起始节点控制点
+ /// 目标节点控制点
+ /// 决定了方法执行后的后继行为
+ public async Task 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)
+
+ ///
+ /// 在两个节点之间创建连接关系
+ ///
+ /// 起始节点Guid
+ /// 目标节点Guid
+ /// 起始节点控制点
+ /// 目标节点控制点
+ /// 决定了方法参数来源
+ /// 设置第几个参数
+ public async Task ConnectArgSourceNodeAsync(string fromNodeGuid,
+ string toNodeGuid,
+ JunctionType fromNodeJunctionType,
+ JunctionType toNodeJunctionType,
+ ConnectionArgSourceType argSourceType,
+ int argIndex)
+ {
+ return await currentFlowEnvironment.ConnectArgSourceNodeAsync(fromNodeGuid, toNodeGuid, fromNodeJunctionType, toNodeJunctionType, argSourceType, argIndex);
+ }
+
+
+ ///
+ /// 连接远程环境并自动切换环境
+ ///
+ ///
+ ///
+ ///
+ ///
+ 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 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 RemoveConnectAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
+ public async Task RemoveConnectInvokeAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
{
- return await currentFlowEnvironment.RemoveConnectAsync(fromNodeGuid, toNodeGuid, connectionType);
+ return await currentFlowEnvironment.RemoveConnectInvokeAsync(fromNodeGuid, toNodeGuid, connectionType);
+ }
+
+ ///
+ /// 移除连接节点之间参数传递的关系
+ ///
+ /// 起始节点Guid
+ /// 目标节点Guid
+ /// 连接到第几个参数
+ /// 参数来源类型
+ public async Task RemoveConnectArgSourceAsync(string fromNodeGuid, string toNodeGuid, int argIndex)
+ {
+ return await currentFlowEnvironment.RemoveConnectArgSourceAsync(fromNodeGuid, toNodeGuid, argIndex);
}
public async Task RemoveNodeAsync(string nodeGuid)
@@ -296,9 +344,9 @@ namespace Serein.NodeFlow.Env
currentFlowEnvironment.SetMonitorObjState(key, isMonitor);
}
- public async Task SetNodeInterruptAsync(string nodeGuid, InterruptClass interruptClass)
+ public async Task 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);
}
diff --git a/NodeFlow/Env/MsgControllerOfClient.cs b/NodeFlow/Env/MsgControllerOfClient.cs
index 53548c8..9e16a41 100644
--- a/NodeFlow/Env/MsgControllerOfClient.cs
+++ b/NodeFlow/Env/MsgControllerOfClient.cs
@@ -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
{
-
-
-
///
/// 客户端的消息管理(用于处理服务端的响应)
///
@@ -28,6 +26,14 @@ namespace Serein.NodeFlow.Env
this.remoteFlowEnvironment = remoteFlowEnvironment;
SendCommandFunc = func;
}
+
+ ///
+ /// 处理需要返回的消息
+ ///
+ ///
+ ///
+ ///
+ ///
private async Task SendCommandAsync(string msgId, string theme, object? data)
{
await SendCommandFunc.Invoke(msgId, theme, data);
@@ -40,15 +46,12 @@ namespace Serein.NodeFlow.Env
///
///
/// 超时触发
- 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); // 客户端发送消息
}
///
@@ -58,33 +61,13 @@ namespace Serein.NodeFlow.Env
/// 超时触发
public async Task SendAndWaitDataAsync(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(msgId);
-
- //if (DebounceHelper.CanExecute(signal, overtimeInMs))
- //{
- // _ = SendCommandAsync.Invoke(signal, sendData);
- // return await remoteFlowEnvironment.WaitData(signal);
-
- // //(var type, var result) = await remoteFlowEnvironment.WaitDataWithTimeoutAsync(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);
}
diff --git a/NodeFlow/Env/MsgControllerOfServer.cs b/NodeFlow/Env/MsgControllerOfServer.cs
index a5ee4fc..064d6b0 100644
--- a/NodeFlow/Env/MsgControllerOfServer.cs
+++ b/NodeFlow/Env/MsgControllerOfServer.cs
@@ -227,7 +227,8 @@ namespace Serein.NodeFlow.Env
[AutoSocketHandle(ThemeValue = EnvMsgTheme.GetEnvInfo)]
private async Task GetEnvInfoAsync()
{
- return await environment.GetEnvInfoAsync();
+ var envInfo = await environment.GetEnvInfoAsync();
+ return envInfo;
}
///
@@ -248,7 +249,7 @@ namespace Serein.NodeFlow.Env
/// 远程环境端口
/// 密码
// [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
}
///
- /// 从远程环境移除节点
+ /// 远程从远程环境移除节点
///
///
///
@@ -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 };
}
///
- /// 连接节点
+ /// 远程连接节点的方法调用关系
///
/// 起始节点
/// 目标节点
- /// 连接关系
- [AutoSocketHandle(ThemeValue = EnvMsgTheme.ConnectNode)]
- public async Task ConnectNode(string fromNodeGuid, string toNodeGuid, string connectionType)
+ /// 起始节点控制点
+ /// 目标节点控制点
+ /// 连接关系
+ [AutoSocketHandle(ThemeValue = EnvMsgTheme.ConnectInvokeNode)]
+ public async Task ConnectInvokeNode(string fromNodeGuid,
+ string toNodeGuid,
+ string fromJunctionType,
+ string toJunctionType,
+ string invokeType)
{
- if (!EnumHelper.TryConvertEnum(connectionType, out var tmpConnectionType))
+ if (!EnumHelper.TryConvertEnum(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(fromJunctionType, out var tmpFromJunctionType))
{
- state = result
- };
+ return new{ state = false};
+ }
+ if (!EnumHelper.TryConvertEnum(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 };
}
///
- /// 移除连接关系
+ /// 远程移除节点的方法调用关系
///
/// 起始节点Guid
/// 目标节点Guid
- /// 连接关系
- ///
- [AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveConnect)]
- public async Task RemoveConnect(string fromNodeGuid, string toNodeGuid, string connectionType)
+ /// 连接关系
+ [AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveInvokeConnect)]
+ public async Task RemoveInvokeConnect(string fromNodeGuid, string toNodeGuid, string invokeType)
{
- if (!EnumHelper.TryConvertEnum(connectionType, out var tmpConnectionType))
+ if (!EnumHelper.TryConvertEnum(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);
+
+ ///
+ /// 远程连接节点的参数传递关系
+ ///
+ /// 起始节点
+ /// 目标节点
+ /// 起始节点控制点
+ /// 目标节点控制点
+ /// 入参参数来源类型
+ /// 第几个参数
+ [AutoSocketHandle(ThemeValue = EnvMsgTheme.ConnectArgSourceNode)]
+ public async Task 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(argSourceType, out var tmpArgSourceType))
+ {
+ return new { state = false };
+ }
+ if (!EnumHelper.TryConvertEnum(fromJunctionType, out var tmpFromJunctionType))
+ {
+ return new { state = false };
+ }
+ if (!EnumHelper.TryConvertEnum(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 };
+ }
+
+ ///
+ /// 远程移除节点的参数传递关系
+ ///
+ /// 起始节点Guid
+ /// 目标节点Guid
+ /// 目标节点的第几个参数
+ [AutoSocketHandle(ThemeValue = EnvMsgTheme.RemoveArgSourceConnect)]
+ public async Task 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
/// 中断指定节点,并指定中断等级。
///
/// 被中断的目标节点Guid
- /// 中断级别
+ /// 是否中断
/// 操作是否成功
[AutoSocketHandle(ThemeValue = EnvMsgTheme.SetNodeInterrupt)]
- public async Task SetNodeInterruptAsync(string nodeGuid, string interruptClass)
+ public async Task SetNodeInterruptAsync(string nodeGuid, bool isInterrupt)
{
- if (!EnumHelper.TryConvertEnum(interruptClass, out var @class))
- {
- return false;
- }
-
- return await this.environment.SetNodeInterruptAsync(nodeGuid, @class);
+
+ return await this.environment.SetNodeInterruptAsync(nodeGuid, isInterrupt);
}
diff --git a/NodeFlow/Env/RemoteFlowEnvironment.cs b/NodeFlow/Env/RemoteFlowEnvironment.cs
index a7e075d..601029f 100644
--- a/NodeFlow/Env/RemoteFlowEnvironment.cs
+++ b/NodeFlow/Env/RemoteFlowEnvironment.cs
@@ -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
///
/// 连接到远程环境后切换到的环境接口实现
///
- /// 连接到远程环境后,本地环境自动切换到对应的环境实体
+ /// 连接到远程环境后,本地环境自动切换到对应的环境实体
/// 远程环境下需要操作UI线程时,所提供的线程上下文封装工具
- 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 SendCommandAsync;
- private readonly RemoteEnvControl remoteEnvControl;
+ private readonly RemoteMsgUtil RemoteMsgUtil;
private readonly MsgControllerOfClient msgClient;
private readonly ConcurrentDictionary MethodDetailss = [];
@@ -70,6 +73,12 @@ namespace Serein.NodeFlow.Env
public IFlowEnvironment CurrentEnv => this;
public UIContextOperation UIContextOperation { get; }
+
+ ///
+ /// 标示是否正在加载项目
+ ///
+ 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 GetEnvInfoAsync()
{
-
var envInfo = await msgClient.SendAndWaitDataAsync(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 ConnectNodeAsync(string fromNodeGuid,
- string toNodeGuid,
- JunctionType fromNodeJunctionType,
- JunctionType toNodeJunctionType,
- ConnectionInvokeType connectionType,
- int argIndex = 0)
+ ///
+ /// 在两个节点之间创建方法调用关系
+ ///
+ /// 起始节点Guid
+ /// 目标节点Guid
+ /// 起始节点控制点
+ /// 目标节点控制点
+ /// 决定了方法执行后的后继行为
+ public async Task ConnectInvokeNodeAsync(string fromNodeGuid,
+ string toNodeGuid,
+ JunctionType fromNodeJunctionType,
+ JunctionType toNodeJunctionType,
+ ConnectionInvokeType invokeType)
{
- var result = await msgClient.SendAndWaitDataAsync(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(EnvMsgTheme.ConnectInvokeNode, sendObj);
if (result)
{
OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid,
toNodeGuid,
JunctionOfConnectionType.Invoke,
- connectionType,
+ invokeType,
NodeConnectChangeEventArgs.ConnectChangeType.Create)); // 通知UI
}
return result;
}
+ ///
+ /// 在两个节点之间创建参数传递关系
+ ///
+ /// 起始节点Guid
+ /// 目标节点Guid
+ /// 起始节点控制点
+ /// 目标节点控制点
+ /// 决定了方法参数来源
+ /// 设置第几个参数
+ public async Task 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(EnvMsgTheme.ConnectArgSourceNode, sendObj);
+ if (result)
+ {
+ OnNodeConnectChange?.Invoke(new NodeConnectChangeEventArgs(fromNodeGuid,
+ toNodeGuid,
+ JunctionOfConnectionType.Arg,
+ argIndex,
+ argSourceType,
+ NodeConnectChangeEventArgs.ConnectChangeType.Create)); // 通知UI
+ }
+ return result;
+ }
+
+
+ ///
+ /// 移除两个节点之间的方法调用关系
+ ///
+ /// 起始节点
+ /// 目标节点
+ /// 连接类型
+ public async Task RemoveConnectInvokeAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType invokeType)
+ {
+ var result = await msgClient.SendAndWaitDataAsync(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;
+ }
+ ///
+ /// 移除连接节点之间参数传递的关系
+ ///
+ /// 起始节点Guid
+ /// 目标节点Guid
+ /// 连接到第几个参数
+ public async Task RemoveConnectArgSourceAsync(string fromNodeGuid, string toNodeGuid, int argIndex)
+ {
+ var result = await msgClient.SendAndWaitDataAsync(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;
+ }
+
+ ///
+ /// 创建节点/区域/基础控件
+ ///
+ /// 节点/区域/基础控件类型
+ /// 节点在画布上的位置(
+ /// 节点绑定的方法说明
public async Task CreateNodeAsync(NodeControlType nodeControlType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null)
{
var nodeInfo = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.CreateNode, new
@@ -489,29 +691,6 @@ namespace Serein.NodeFlow.Env
});
return nodeInfo;
}
-
- public async Task RemoveConnectAsync(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType)
- {
- var result = await msgClient.SendAndWaitDataAsync(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 RemoveNodeAsync(string nodeGuid)
{
var result = await msgClient.SendAndWaitDataAsync(EnvMsgTheme.RemoveNode, new
@@ -548,13 +727,13 @@ namespace Serein.NodeFlow.Env
});
}
- public async Task SetNodeInterruptAsync(string nodeGuid, InterruptClass interruptClass)
+ public async Task SetNodeInterruptAsync(string nodeGuid, bool isInterrupt)
{
var state = await msgClient.SendAndWaitDataAsync(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(),
+ //});
}
}
diff --git a/NodeFlow/FlowStarter.cs b/NodeFlow/FlowStarter.cs
index 81418a7..e7f799d 100644
--- a/NodeFlow/FlowStarter.cs
+++ b/NodeFlow/FlowStarter.cs
@@ -46,13 +46,27 @@ namespace Serein.NodeFlow
///
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},开始执行后继分支");
diff --git a/NodeFlow/Model/CompositeActionNode.cs b/NodeFlow/Model/CompositeActionNode.cs
deleted file mode 100644
index 1801537..0000000
--- a/NodeFlow/Model/CompositeActionNode.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using Serein.Library;
-using Serein.Library.Api;
-
-namespace Serein.NodeFlow.Model
-{
-
- ///
- /// 组合动作节点(用于动作区域)
- ///
- public class CompositeActionNode : NodeModelBase
- {
- public List ActionNodes;
-
-
- ///
- /// 组合动作节点(用于动作区域)
- ///
- public CompositeActionNode(IFlowEnvironment environment, List actionNodes):base(environment)
- {
- ActionNodes = actionNodes;
- }
-
- //public override async Task Executing(IDynamicContext context)
- public override Task 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(),
- };
- }
- }
-
-}
diff --git a/NodeFlow/Model/CompositeConditionNode.cs b/NodeFlow/Model/CompositeConditionNode.cs
index 8d56f52..af32f8b 100644
--- a/NodeFlow/Model/CompositeConditionNode.cs
+++ b/NodeFlow/Model/CompositeConditionNode.cs
@@ -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
{
diff --git a/NodeFlow/Model/CompositeLoopNode.cs b/NodeFlow/Model/CompositeLoopNode.cs
deleted file mode 100644
index acf3822..0000000
--- a/NodeFlow/Model/CompositeLoopNode.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace Serein.NodeFlow.Model
-{
- //public class CompositeLoopNode : NodeBase
- //{
- //}
-}
diff --git a/NodeFlow/Model/SingleActionNode.cs b/NodeFlow/Model/SingleActionNode.cs
index 92a9487..5602462 100644
--- a/NodeFlow/Model/SingleActionNode.cs
+++ b/NodeFlow/Model/SingleActionNode.cs
@@ -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,
})
diff --git a/NodeFlow/Model/SingleConditionNode.cs b/NodeFlow/Model/SingleConditionNode.cs
index bc53ae5..4c21f21 100644
--- a/NodeFlow/Model/SingleConditionNode.cs
+++ b/NodeFlow/Model/SingleConditionNode.cs
@@ -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;
}
diff --git a/NodeFlow/Model/SingleExpOpNode.cs b/NodeFlow/Model/SingleExpOpNode.cs
index 5eaa994..da97270 100644
--- a/NodeFlow/Model/SingleExpOpNode.cs
+++ b/NodeFlow/Model/SingleExpOpNode.cs
@@ -31,7 +31,7 @@ namespace Serein.NodeFlow.Model
//public override async Task Executing(IDynamicContext context)
public override Task 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 }];
}
diff --git a/NodeFlow/Model/SingleFlipflopNode.cs b/NodeFlow/Model/SingleFlipflopNode.cs
index c32858b..899ab38 100644
--- a/NodeFlow/Model/SingleFlipflopNode.cs
+++ b/NodeFlow/Model/SingleFlipflopNode.cs
@@ -26,7 +26,7 @@ namespace Serein.NodeFlow.Model
public override async Task 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
/// 获取触发器参数
///
///
- 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
})
diff --git a/NodeFlow/Serein.NodeFlow.csproj b/NodeFlow/Serein.NodeFlow.csproj
index 51e7c4b..e57693b 100644
--- a/NodeFlow/Serein.NodeFlow.csproj
+++ b/NodeFlow/Serein.NodeFlow.csproj
@@ -1,7 +1,7 @@
- 1.0.17
+ 1.0.18
net8.0
enable
enable
@@ -60,11 +60,6 @@
-
-
-
-
-
diff --git a/NodeFlow/Tool/NodeMethodDetailsHelper.cs b/NodeFlow/Tool/NodeMethodDetailsHelper.cs
index 98f964a..882fe6f 100644
--- a/NodeFlow/Tool/NodeMethodDetailsHelper.cs
+++ b/NodeFlow/Tool/NodeMethodDetailsHelper.cs
@@ -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;
diff --git a/Serein.Library.MyGenerator/Attribute.cs b/Serein.Library.MyGenerator/Attribute.cs
index 6f9bd35..b61d09c 100644
--- a/Serein.Library.MyGenerator/Attribute.cs
+++ b/Serein.Library.MyGenerator/Attribute.cs
@@ -33,7 +33,6 @@ namespace Serein.Library
/// 节点的调试设置
///
DebugSetting,
-
}
@@ -68,6 +67,12 @@ namespace Serein.Library
/// 是否禁止参数进行修改(初始化后不能再通过 Setter 修改)
///
public bool IsProtection = false;
+
+ ///
+ /// 自定义代码
+ ///
+ public string CustomCode = null;
+
}
}
diff --git a/Serein.Library.MyGenerator/ParameterDetailsPropertyGenerator.cs b/Serein.Library.MyGenerator/ParameterDetailsPropertyGenerator.cs
index 7f06ab8..14f723b 100644
--- a/Serein.Library.MyGenerator/ParameterDetailsPropertyGenerator.cs
+++ b/Serein.Library.MyGenerator/ParameterDetailsPropertyGenerator.cs
@@ -163,7 +163,7 @@ namespace Serein.Library.NodeGenerator
var propertyName = field.ToPropertyName(); // 转为合适的属性名称
var attributeInfo = fieldKV.Value; // 缓存的特性信息
- var isProtection = attributeInfo.Search(nameof(PropertyInfo), nameof(PropertyInfo.IsProtection), "true"); // 是否为保护字段
+ var isProtection = attributeInfo.Search(nameof(PropertyInfo), nameof(PropertyInfo.IsProtection), value => bool.Parse(value)); // 是否为保护字段
// 生成 getter / setter
sb.AppendLine(leadingTrivia);
@@ -174,11 +174,12 @@ namespace Serein.Library.NodeGenerator
sb.AppendLine(" {");
sb.AppendLine($" if ({fieldName} {(isProtection ? "== default" : "!= value")})"); // 非保护的Setter
sb.AppendLine(" {");
- if (attributeInfo.Search(nameof(PropertyInfo), nameof(PropertyInfo.IsPrint), "true")) // 是否打印
+ sb.AppendLine($" SetProperty<{fieldType}>(ref {fieldName}, value); // 通知UI属性发生改变了");
+ if (attributeInfo.Search(nameof(PropertyInfo), nameof(PropertyInfo.IsPrint), value => bool.Parse(value))) // 是否打印
{
sb.AddCode(5, $"Console.WriteLine({fieldName});");
}
- if (attributeInfo.Search(nameof(PropertyInfo), nameof(PropertyInfo.IsNotification), "true")) // 是否通知
+ if (attributeInfo.Search(nameof(PropertyInfo), nameof(PropertyInfo.IsNotification), value => bool.Parse(value))) // 是否通知
{
if (classInfo.ExitsPath(nameof(NodeValuePath.Node))) // 节点 or 自定义节点
{
@@ -197,7 +198,12 @@ namespace Serein.Library.NodeGenerator
sb.AddCode(5, $"NodeModel?.Env?.NotificationNodeValueChangeAsync(NodeModel.Guid, \"DebugSetting.\"+nameof({propertyName}), value); // 通知远程环境属性发生改变了");
}
}
- sb.AppendLine($" SetProperty<{fieldType}>(ref {fieldName}, value); // 通知UI属性发生改变了");
+ if (attributeInfo.Search(nameof(PropertyInfo), nameof(PropertyInfo.CustomCode), value => !string.IsNullOrEmpty(value))) // 是否打印
+ {
+ var customCode = attributeInfo[nameof(PropertyInfo)][nameof(PropertyInfo.CustomCode)] as string;
+ customCode = customCode.Trim().Substring(1, customCode.Length - 2);
+ sb.AddCode(5, $"{customCode} // 添加的自定义代码");
+ }
//sb.AppendLine($" {fieldName} = value;");
//sb.AppendLine($" OnPropertyChanged(); // 通知UI属性发生改变了");
sb.AppendLine(" }");
@@ -510,7 +516,7 @@ namespace Serein.Library.NodeGenerator
public static bool Search(this Dictionary> dict,
string attributeName = null,
string attributePropertyName = null,
- string comparisonValue = null)
+ Func judgeFunc = null)
{
if (string.IsNullOrWhiteSpace(attributeName))
return false;
@@ -521,9 +527,11 @@ namespace Serein.Library.NodeGenerator
return true;
if (!abs.TryGetValue(attributePropertyName, out var absValue))
return false;
- if (string.IsNullOrWhiteSpace(comparisonValue))
+ if (judgeFunc == null)
return true;
- return absValue.Equals(comparisonValue);
+
+ return judgeFunc.Invoke(absValue); ;
+ //return absValue.Equals(comparisonValue);
}
diff --git a/Serein.Library.MyGenerator/Serein.Library.NodeGenerator.csproj b/Serein.Library.MyGenerator/Serein.Library.NodeGenerator.csproj
index 125db7c..a813521 100644
--- a/Serein.Library.MyGenerator/Serein.Library.NodeGenerator.csproj
+++ b/Serein.Library.MyGenerator/Serein.Library.NodeGenerator.csproj
@@ -2,6 +2,7 @@
netstandard2.0
+ 1.0.1
true
D:\Project\C#\DynamicControl\SereinFlow\.Output
@@ -14,6 +15,12 @@
True
true
+
+
+
+
+
+
diff --git a/WorkBench/App.xaml.cs b/WorkBench/App.xaml.cs
index bcc31fe..47b79f8 100644
--- a/WorkBench/App.xaml.cs
+++ b/WorkBench/App.xaml.cs
@@ -13,7 +13,7 @@ namespace Serein.Workbench
void LoadLocalProject()
{
#if DEBUG
- if (1 == 1)
+ if (1 == 11)
{
string filePath;
filePath = @"F:\临时\project\linux\project.dnf";
diff --git a/WorkBench/MainWindow.xaml b/WorkBench/MainWindow.xaml
index 5063664..a89165a 100644
--- a/WorkBench/MainWindow.xaml
+++ b/WorkBench/MainWindow.xaml
@@ -1,18 +1,26 @@
+
@@ -35,7 +43,7 @@
-