| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Linq;
- using System.Text;
- using System.Text.RegularExpressions;
- using TeamAAS.Communication;
- namespace TeamAAS.FlowEditor.Execution
- {
- /// <summary>
- /// 执行结果注册中心 - 存储各节点最新执行结果,支持 &{节点名.属性名} 公式解析
- /// 内部结构: Dictionary<GraphId, Dictionary<NodeName, Dictionary<PropName, object>>>
- /// 保留键 "Gloab" 用于存储全局变量
- ///
- /// 实例化设计:主页面运行流程与产品管理编辑/调试流程使用各自独立的注册表实例,
- /// 避免 Debug 流程的清理/写入干扰运行中流程的结果缓存(导致内存释放异常)。
- /// - <see cref="Main"/>:主页面的运行流程(FlowRunner)专用
- /// - <see cref="Debug"/>:产品管理编辑/调试流程专用
- /// 产品管理进入监控模式时挂接的是主页面运行态流程,其 Graph.Registry 指向 Main,
- /// 因此公式解析/结果读取会自动落到主面对象上。
- /// </summary>
- public class ResultRegistry
- {
- /// <summary>主页面运行流程专用注册表</summary>
- public static ResultRegistry Main { get; } = new ResultRegistry();
- /// <summary>产品管理编辑/调试流程专用注册表</summary>
- public static ResultRegistry Debug { get; } = new ResultRegistry();
- public const string GlobalVariablesKey = "Gloab";
- public readonly Dictionary<string, Dictionary<string, Dictionary<string, object>>> _store
- = new Dictionary<string, Dictionary<string, Dictionary<string, object>>>();
- private readonly object _lock = new object();
- private bool _initialized;
- /// <summary>
- /// 初始化所有注册表实例:订阅全局变量变化事件,自动刷新 ResultRegistry
- /// </summary>
- public static void Initialize()
- {
- Main.InitializeInstance();
- Debug.InitializeInstance();
- }
- /// <summary>
- /// 刷新所有注册表实例的全局变量区(全局变量为进程级共享数据)
- /// </summary>
- public static void RefreshGlobals()
- {
- Main.RefreshGlobalVariables();
- Debug.RefreshGlobalVariables();
- }
- /// <summary>
- /// 初始化:订阅全局变量变化事件,自动刷新本注册表
- /// </summary>
- public void InitializeInstance()
- {
- if (_initialized) return;
- _initialized = true;
- GlobalVariableManager.Instance.VariablesChanged += RefreshGlobalVariables;
- RefreshGlobalVariables();
- }
- /// <summary>
- /// 设置节点最新执行结果
- /// </summary>
- public void SetResult(string graphId, string nodeid, string nodeName, Dictionary<string, object> results)
- {
- if (string.IsNullOrEmpty(graphId) || string.IsNullOrEmpty(nodeName)) return;
- lock (_lock)
- {
- if (!_store.TryGetValue(graphId, out var flowDict))
- {
- flowDict = new Dictionary<string, Dictionary<string, object>>();
- _store[graphId] = flowDict;
- }
- flowDict[nodeName] = results ?? new Dictionary<string, object>();
- }
- }
- /// <summary>
- /// 向指定流程的「输入」虚拟节点写入单个变量(供 &{输入.变量名} 2段式解析)
- /// </summary>
- public void SetInputVariable(string graphId, string varName, object value)
- {
- if (string.IsNullOrEmpty(graphId) || string.IsNullOrEmpty(varName)) return;
- lock (_lock)
- {
- if (!_store.TryGetValue(graphId, out var flowDict))
- {
- flowDict = new Dictionary<string, Dictionary<string, object>>();
- _store[graphId] = flowDict;
- }
- if (!flowDict.TryGetValue("输入", out var inputDict))
- {
- inputDict = new Dictionary<string, object>();
- flowDict["输入"] = inputDict;
- }
- inputDict[varName] = value;
- }
- }
- /// <summary>
- /// 获取指定流程下所有节点的结果
- /// </summary>
- public void GetFlowResults(string graphId, out Dictionary<string, Dictionary<string, object>> flowResults)
- {
- flowResults = new Dictionary<string, Dictionary<string, object>>();
- if (string.IsNullOrEmpty(graphId)) return;
- lock (_lock)
- {
- if (_store.TryGetValue(graphId, out var dict))
- {
- foreach (var kvp in dict)
- flowResults[kvp.Key] = kvp.Value;
- }
- }
- }
- /// <summary>
- /// 获取节点最新结果字典
- /// </summary>
- public Dictionary<string, object> GetResult(string graphId, string nodeName)
- {
- lock (_lock)
- {
- if (_store.TryGetValue(graphId, out var flowDict) && flowDict.TryGetValue(nodeName, out var dict))
- return dict;
- }
- return null;
- }
- /// <summary>
- /// 获取节点某个属性值
- /// </summary>
- public object GetValue(string graphId, string nodeName, string propertyName)
- {
- lock (_lock)
- {
- if (_store.TryGetValue(graphId, out var flowDict)
- && flowDict.TryGetValue(nodeName, out var dict)
- && dict.TryGetValue(propertyName, out var val))
- return val;
- }
- return null;
- }
- /// <summary>
- /// 刷新全局变量到 _store["Gloab"]
- /// </summary>
- public void RefreshGlobalVariables()
- {
- var vars = GlobalVariableManager.Instance.Variables;
- lock (_lock)
- {
- if (!_store.TryGetValue(GlobalVariablesKey, out var gloabDict))
- {
- gloabDict = new Dictionary<string, Dictionary<string, object>>();
- _store[GlobalVariablesKey] = gloabDict;
- }
- gloabDict.Clear();
- foreach (var v in vars)
- {
- if (string.IsNullOrWhiteSpace(v.Name)) continue;
- gloabDict[v.Name] = new Dictionary<string, object>
- {
- ["Value"] = v.Value,
- ["DataType"] = v.DataType,
- ["Note"] = v.Note ?? ""
- };
- }
- }
- }
- /// <summary>
- /// 解析公式 &{节点名.属性名}(2段式)或 &{流程名.节点名.属性名}(3段式)
- /// 特殊支持 &{Gloab.变量名} 直接获取全局变量值(2段式),或 &{Gloab.变量名.Value}(3段式)
- /// </summary>
- public object ResolveFormula(string FlowId, string formula)
- {
- if (string.IsNullOrEmpty(formula)) return formula;
- var match2 = Regex.Match(formula, @"^&\{(?<node>[^.}]+)\.(?<prop>[^.}]+)\}$");
- var match3 = Regex.Match(formula, @"^&\{(?<flow>[^.}]+)\.(?<node>[^.}]+)\.(?<prop>[^.}]+)\}$");
- if (match2.Success)
- {
- string first = match2.Groups["node"].Value;
- string second = match2.Groups["prop"].Value;
- if (first == GlobalVariablesKey)
- {
- return GetValue(GlobalVariablesKey, second, "Value");
- }
- var result = GetValue(FlowId, first, second);
- return result;
- }
- else if (match3.Success)
- {
- string flow = match3.Groups["flow"].Value;
- string node = match3.Groups["node"].Value;
- string prop = match3.Groups["prop"].Value;
- if (flow == GlobalVariablesKey)
- {
- return GetValue(GlobalVariablesKey, node, prop);
- }
- return GetValue(flow, node, prop);
- }
- else
- return formula;
- }
- /// <summary>
- /// 删除指定流程中某个节点的执行结果
- /// </summary>
- public void RemoveNodeResult(string graphId, string nodeName)
- {
- if (string.IsNullOrEmpty(graphId) || string.IsNullOrEmpty(nodeName)) return;
- lock (_lock)
- {
- if (_store.TryGetValue(graphId, out var flowDict))
- flowDict.Remove(nodeName);
- }
- }
- /// <summary>
- /// 清空指定流程的所有结果
- /// </summary>
- public void ClearFlow(string graphId)
- {
- if (string.IsNullOrEmpty(graphId)) return;
- lock (_lock)
- {
- _store.Remove(graphId);
- }
- }
- /// <summary>
- /// 完全释放所有流程数据(各流程 GraphId 及其子流程 SubGraphId 条目全部移除),仅保留全局变量区。
- /// ClearFlow 只按单个 GraphId 清理,会漏掉组合/循环子流程写入的 SubGraphId 条目;
- /// 切换/重载产品、进出监控时用本方法彻底清干净,避免上次产品的数据残留堆积。
- /// </summary>
- public void ClearAllFlows()
- {
- lock (_lock)
- {
- var flowKeys = _store.Keys.Where(k => k != GlobalVariablesKey).ToList();
- foreach (var key in flowKeys)
- _store.Remove(key);
- }
- }
- /// <summary>
- /// 清空所有结果
- /// </summary>
- public void Clear()
- {
- lock (_lock)
- {
- _store.Clear();
- }
- }
- #region 调试监控(供主页“注册表监控”窗口的 PropertyGrid 直接绑定 Main / Debug 显示)
- /// <summary>【监控】当前缓存的流程数(不含全局变量区)。若 Debug 持续增长而不回落,通常意味着清理没做好。</summary>
- [Category("注册表监控")]
- [DisplayName("流程数")]
- [ReadOnly(true)]
- public int FlowCount
- {
- get { lock (_lock) return _store.Keys.Count(k => k != GlobalVariablesKey); }
- }
- /// <summary>【监控】缓存的流程 GraphId 列表(逗号分隔)。</summary>
- [Category("注册表监控")]
- [DisplayName("流程ID列表")]
- [ReadOnly(true)]
- public string FlowIds
- {
- get { lock (_lock) return string.Join(", ", _store.Keys.Where(k => k != GlobalVariablesKey)); }
- }
- /// <summary>【监控】全局变量条目数。</summary>
- [Category("注册表监控")]
- [DisplayName("全局变量数")]
- [ReadOnly(true)]
- public int GlobalVariableCount
- {
- get { lock (_lock) return _store.TryGetValue(GlobalVariablesKey, out var g) ? g.Count : 0; }
- }
- /// <summary>【监控】是否已初始化(已订阅全局变量变化事件)。</summary>
- [Category("注册表监控")]
- [DisplayName("已初始化")]
- [ReadOnly(true)]
- public bool IsInitialized
- {
- get { lock (_lock) return _initialized; }
- }
- /// <summary>
- /// 【监控】完整内容快照(多行文本):流程 → 节点 → 结果键值,用于排查 Main / Debug 是否被正确管理。
- /// 大对象(图像 / CogRecord 等)只显示类型名,避免 ToString 噪音。
- /// </summary>
- [Category("注册表监控")]
- [DisplayName("内容快照")]
- [ReadOnly(true)]
- public string Snapshot
- {
- get
- {
- lock (_lock)
- {
- var sb = new StringBuilder();
- foreach (var flow in _store)
- {
- if (flow.Key == GlobalVariablesKey)
- {
- sb.AppendLine($"[全局变量 Gloab] {flow.Value.Count} 项");
- foreach (var v in flow.Value)
- {
- object gv = v.Value != null && v.Value.TryGetValue("Value", out var raw) ? raw : null;
- sb.AppendLine($" {v.Key} = {DescribeValue(gv)}");
- }
- continue;
- }
- sb.AppendLine($"[流程 {flow.Key}] 节点 {flow.Value.Count} 个");
- foreach (var node in flow.Value)
- {
- sb.AppendLine($" · {node.Key}({node.Value.Count} 项)");
- foreach (var kv in node.Value)
- sb.AppendLine($" {kv.Key} = {DescribeValue(kv.Value)}");
- }
- }
- return sb.Length == 0 ? "(空)" : sb.ToString();
- }
- }
- }
- /// <summary>监控快照的值格式化:基础类型直接 ToString,集合显示项数,其余大对象只显示类型名。</summary>
- private static string DescribeValue(object v)
- {
- if (v == null) return "null";
- var t = v.GetType();
- bool basic = t.IsPrimitive || v is string || v is decimal || v is DateTime || t.IsEnum;
- if (basic) return v.ToString();
- if (v is System.Collections.IEnumerable en)
- {
- int c = 0;
- foreach (var _ in en) c++;
- return $"{t.Name}({c} 项)";
- }
- return t.Name;
- }
- #endregion
- }
- }
|