-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathProcess.cs
More file actions
386 lines (345 loc) · 13.7 KB
/
Copy pathProcess.cs
File metadata and controls
386 lines (345 loc) · 13.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
using Logger;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using TDJS_Vision.Node;
namespace TDJS_Vision
{
public struct ProcessRunResult
{
public bool IsRunning;
public bool IsSuccess;
public string ProcessName;
public ProcessRunResult(bool isRunning, bool isSuccess, string name)
{
IsRunning = isRunning;
IsSuccess = isSuccess;
ProcessName = name;
}
}
/// <summary>
/// 检测流程类
/// 一个方案可以拥有多个流程
/// 每个流程也可以单独执行
/// </summary>
public class Process
{
/// <summary>
/// 流程包含的节点
/// </summary>
private List<NodeBase> _nodes = new List<NodeBase>();
/// <summary>
/// 流程名称
/// </summary>
public string ProcessName { get; set; }
/// <summary>
/// 流程运行时是否输出日志
/// </summary>
public bool ShowLog { get; set; } = true;
/// <summary>
/// 流程包含的节点
/// </summary>
public List<NodeBase> Nodes { get => _nodes;}
/// <summary>
/// 流程是否正在运行
/// </summary>
public bool IsRuning { get; set; } = false;
/// <summary>
/// 流程运行优先级
/// </summary>
public ProcessLvEnum RunLv { get; set; } = ProcessLvEnum.Lv5;
/// <summary>
/// 流程组别
/// </summary>
public ProcessGroup Group { get; set; } = ProcessGroup.Group1;
/// <summary>
/// 流程运行时间
/// </summary>
public long RunTime { get; private set; } = 0;
/// <summary>
/// 流程运行是否成功
/// </summary>
public bool Success { get; private set; }
/// <summary>
/// 是否跳过Else逻辑
/// </summary>
public bool SkipNextElseBlock { get; set; }
/// <summary>
/// 流程是否启用
/// </summary>
public bool Enable { get; set; } = true;
/// <summary>
/// 流程运行完更新流程界面和主界面的运行按钮Enable
/// </summary>
public static EventHandler<ProcessRunResult> UpdateRunStatus;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="solution"></param>
public Process(string processName)
{
ProcessName = processName;
}
public void AddNode(NodeBase node)
{
_nodes.Add(node);
}
#region 实现被触发执行的逻辑
/// <summary>
/// 是否是在流程编辑界面中手动点击运行
/// </summary>
public bool IsHandRun { get; set; }
/// <summary>
/// 是否为被动触发流程
/// </summary>
public bool IsPassiveTriggered { get; set; }
/// <summary>
/// 可选:添加触发方法
/// </summary>
/// <param name="passiveProcesses"></param>
/// <param name="ct"></param>
public void TriggerPassiveProcesses(IEnumerable<Process> passiveProcesses, CancellationToken ct)
{
foreach (var p in passiveProcesses)
{
if (p == null)
continue;
// 可在这里加条件判断是否可触发等
p.RunInternal(isCyclical: false, isTriggered: true, ct: ct);
}
}
private Action<Process> _triggerAction; // 由外部注入
public void SetTriggerAction(Action<Process> action)
{
_triggerAction = action;
}
// 在流程的某个节点需要触发其他流程时调用
public async Task TriggerProcess(string processName)
{
foreach(var pro in Solution.Instance.AllProcesses)
{
if (pro.ProcessName == processName)
{
// 触发某个流程
_triggerAction?.Invoke(pro);
break;
}
}
}
// 包装 Run 方法,支持标记“是否被触发”
public async Task RunInternal(bool isCyclical, bool isTriggered, CancellationToken ct)
{
using (ct.Register(() => { /* 可选:清理 */ }))
{
try
{
await Run(isCyclical); // 实际执行
}
catch (OperationCanceledException) when (ct.IsCancellationRequested)
{
LogHelper.AddLog(MsgLevel.Exception, $"被动流程执行取消!");
}
catch (Exception ex)
{
LogHelper.AddLog(MsgLevel.Exception, $"被动流程执行异常: {ex.Message}");
}
}
}
#endregion
/// <summary>
/// 流程开始运行
/// </summary>
public async Task Run(bool isCyclical)
{
if (Nodes.Count == 0 || !Enable)
return;
RunTime = 0;
UpdateRunStatus?.Invoke(this, new ProcessRunResult(true, false, ProcessName));
if (ShowLog)
LogHelper.AddLog(MsgLevel.Info, $"----------------------------------------------------- 【{ProcessName}】(开始) -----------------------------------------------------", true);
IsRuning = true;
Success = false;
for (int i = 0; i < _nodes.Count; i++)
{
NodeBase node = _nodes[i];
try
{
if (!node.Active)
continue;
NodeReturn result = await node.Run(Solution.Instance.CancellationToken, ShowLog);
RunTime += node.Result.RunTime;
// 检查还要不要继续运行
if (result.Flag == NodeRunFlag.StopRun)
{
// 当前节点要求停止后续节点执行
Success = true; // 可以设置为成功或其他状态
IsRuning = false;
if (ShowLog)
LogHelper.AddLog(MsgLevel.Info, $"--------------------------------- 【{ProcessName}】(结束) 【耗时】({RunTime}ms) 【状态】(提前完成) ---------------------------------", true);
UpdateRunStatus?.Invoke(this, new ProcessRunResult(false, true, ProcessName));
return; // 提前退出整个流程
}
#region 实现IF^Else逻辑
// ✅ 让节点返回“下一个要执行的索引”
// -1 表示顺序执行下一个(i+1)
// 其他表示跳转到指定索引
if (result.NextIndex == -1)
{
// 顺序执行下一个
continue;
}
else
{
// 跳转
i = result.NextIndex - 1; // for 循环会 +1,所以先 -1
}
#endregion
}
catch (OperationCanceledException ex)
{
Success = false;
IsRuning = false;
if (ShowLog)
LogHelper.AddLog(MsgLevel.Warn, $"--------------------------------- 【{ProcessName}】(结束) 【耗时】({RunTime}ms) 【状态】(运行中断) ---------------------------------", true);
UpdateRunStatus?.Invoke(this, new ProcessRunResult(false, false, ProcessName));
throw ex;
}
catch (Exception ex)
{
Success = false;
IsRuning = false;
if (ShowLog)
LogHelper.AddLog(MsgLevel.Exception, $"--------------------------------- 【{ProcessName}】(结束) 【耗时】({RunTime}ms) 【状态】(失败) ---------------------------------", true);
UpdateRunStatus?.Invoke(this, new ProcessRunResult(false, false, ProcessName));
throw ex;
}
}
// 所有节点都执行完毕
Success = true;
IsRuning = false;
if (ShowLog)
LogHelper.AddLog(MsgLevel.Info, $"--------------------------------- 【{ProcessName}】(结束) 【耗时】({RunTime}ms) 【状态】(成功) ---------------------------------", true);
UpdateRunStatus?.Invoke(this, new ProcessRunResult(false, true, ProcessName));
}
/// <summary>
/// 专用于需要订阅刷新前一个节点图像的节点
/// 要在参数节点处停止运行
/// </summary>
public async Task RunForUpdateImages(NodeBase node2Stop)
{
// 重置运行取消令牌
Solution.Instance.ResetTokenSource();
// 节点数为0或流程不启用则不运行
if (Nodes.Count == 0 || !Enable)
return;
RunTime = 0;
// 更新运行状态
UpdateRunStatus?.Invoke(this, new ProcessRunResult(true, false, ProcessName));
if(ShowLog)
LogHelper.AddLog(MsgLevel.Info, $"----------------------------------------------------- 【{ProcessName}】(开始) -----------------------------------------------------", true);
IsRuning = true;
Success = false;
for (int i = 0; i < _nodes.Count; i++)
{
NodeBase node = _nodes[i];
try
{
if (node2Stop == node)
{
break;
}
NodeReturn result = await node.Run(Solution.Instance.CancellationToken, ShowLog);
RunTime += node.Result.RunTime;
// 检查还要不要继续运行
if (result.Flag == NodeRunFlag.StopRun)
{
// 当前节点要求停止后续节点执行
Success = true; // 可以设置为成功或其他状态
IsRuning = false;
if (ShowLog)
LogHelper.AddLog(MsgLevel.Info, $"--------------------------------- 【{ProcessName}】(结束) 【耗时】({RunTime}ms) 【状态】(提前完成) ---------------------------------", true);
UpdateRunStatus?.Invoke(this, new ProcessRunResult(false, true, ProcessName));
return; // 提前退出整个流程
}
#region 实现IF^Else逻辑
// ✅ 让节点返回“下一个要执行的索引”
// -1 表示顺序执行下一个(i+1)
// 其他表示跳转到指定索引
if (result.NextIndex == -1)
{
// 顺序执行下一个
continue;
}
else
{
// 跳转
i = result.NextIndex - 1; // for 循环会 +1,所以先 -1
}
#endregion
}
catch (OperationCanceledException ex)
{
Success = false;
IsRuning = false;
RunTime += node.Result.RunTime;
if (ShowLog)
LogHelper.AddLog(MsgLevel.Warn, $"--------------------------------- 【{ProcessName}】(结束) 【耗时】({RunTime}ms) 【状态】(运行中断) ---------------------------------", true);
UpdateRunStatus?.Invoke(this, new ProcessRunResult(false, false, ProcessName));
throw ex;
}
catch (Exception ex)
{
Success = false;
IsRuning = false;
RunTime += node.Result.RunTime;
if (ShowLog)
LogHelper.AddLog(MsgLevel.Exception, $"--------------------------------- 【{ProcessName}】(结束) 【耗时】({RunTime}ms) 【状态】(失败) ---------------------------------", true);
UpdateRunStatus?.Invoke(this, new ProcessRunResult(false, false, ProcessName));
throw ex;
}
}
Success = true;
IsRuning = false;
if (ShowLog)
LogHelper.AddLog(MsgLevel.Info, $"--------------------------------- 【{ProcessName}】(结束) 【耗时】({RunTime}ms) 【状态】(成功) ---------------------------------", true);
UpdateRunStatus?.Invoke(this, new ProcessRunResult(false, true, ProcessName));
}
}
/// <summary>
/// 流程运行优先级别,同级并行运行
/// </summary>
public enum ProcessLvEnum
{
/// <summary>
/// 1级最先运行
/// </summary>
Lv1,
Lv2,
Lv3,
Lv4,
/// <summary>
/// 5级最后运行
/// </summary>
Lv5,
}
public enum ProcessGroup
{
Group1,
Group2,
Group3,
Group4,
Group5
//Group6,
//Group7,
//Group8,
//Group9,
//Group10,
//Group11,
//Group12,
//Group13,
//Group14,
//Group15,
//Group16
}
}