| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- using PropertyGridLib.Controls;
- using System;
- using System.Collections.Generic;
- using System.Threading;
- using TeamAAS.FlowEditor.Execution;
- using TeamAAS.FlowEditor.Models;
- namespace TeamAAS.FlowEditor.Plugins
- {
- /// <summary>
- /// 插件抽象基类 - 参照 VisionKit 的 BaseAbstractPlugin<TModel>
- /// 泛型 TModel 自动实例化,子类只需实现 InitPlugin 和 PluginRun
- /// </summary>
- [Serializable]
- public abstract class BasePlugin<TModel> : IFlowNodePlugin where TModel : BasePluginModel, new()
- {
- public TModel Model { get; protected set; }
- public BasePluginModel GetModel { get => Model; set => Model = (TModel)value; }
- /// <summary>
- /// 所属流程绑定的结果注册表(运行态=Main,编辑/调试态=Debug)。
- /// 由 FlowNode 在初始化/换图时注入;未注入时回退到 Debug 注册表。
- /// </summary>
- [field: NonSerialized]
- public ResultRegistry Registry { get; set; }
- /// <summary>实际使用的注册表(保证非 null)</summary>
- protected ResultRegistry RegistryOrDebug => Registry ?? ResultRegistry.Debug;
- [NonSerialized]
- private TeamAAS.Global.IPluginContext _context;
- /// <summary>
- /// 插件运行上下文:获取平台服务(相机/机器人/通讯/供料/运动)的正规渠道。
- /// 未注入时回落到全局 ServiceRegistry.Default,永不为 null;
- /// 插件经 Context.GetService 取服务,无需直接摸 XxxManager.Instance。
- /// 宿主将来可提供自定义实现(如远程代理)注入覆盖。
- /// </summary>
- public TeamAAS.Global.IPluginContext Context
- {
- get => _context ?? TeamAAS.Global.ServiceRegistry.Default;
- set => _context = value;
- }
- /// <summary>按类型获取平台服务(工厂方法):相机/机器人/通讯/供料/运动管理器等;未注册返回 null。</summary>
- protected T Service<T>() => Context.GetService<T>();
- public int CostTime { get; protected set; }
- public NodeRunStatus IsSuccess { get; set; } = NodeRunStatus.NotStarted;
- public bool IsEnable { get; set; } = true;
- public Dictionary<string, object> LastResults { get; private set; }
- /// <summary>分支节点:返回下一个要执行的节点名列表(null=非分支节点)</summary>
- public List<string> BranchTargets { get; protected set; }
- protected BasePlugin()
- {
- Model = new TModel();
- }
- /// <summary>
- /// 释放插件持有的资源。
- /// 子类有相机句柄/连接流/大对象等需释放的资源时,重写并调用 base.Dispose()。
- /// </summary>
- public virtual void Dispose()
- {
- try
- {
- LastResults?.Clear();
- LastResults = null;
- BranchTargets?.Clear();
- BranchTargets = null;
- Model = null;
- }
- catch { }
- }
- public virtual bool InitPlugin()
- {
- return true;
- }
- /// <summary>
- /// 声明插件输出字段。静态插件重写此方法声明固定输出;动态插件可从 Model 动态生成。
- /// </summary>
- public virtual List<OutputField> DeclareOutputs() => new List<OutputField>();
- public abstract NodeRunStatus PluginRun(CancellationToken token, out Dictionary<string, object> results);
- public bool InitRun()
- {
- Dictionary<string, object> results = new Dictionary<string, object>();
- try
- {
- bool ret = InitPlugin();
- foreach (var field in DeclareOutputs())
- {
- results[field.Key] = field.ValueType != null && field.ValueType.IsValueType
- ? Activator.CreateInstance(field.ValueType)
- : null;
- }
- results["状态"] = NodeRunStatus.NotStarted;
- results["结果"] = false;
- results["耗时"] = 0;
- results["模型"] = this;
- if (!ret)
- results["Error"] = GetModel.FlowName + "插件初始化失败";
- RegistryOrDebug.SetResult(GetModel.FlowId, GetModel.NodeId, GetModel.NodeName, results);
- LastResults = results;
- return ret;
- }
- catch (System.Exception ex)
- {
- results["Error"] = GetModel.FlowName + ex.Message;
- RegistryOrDebug.SetResult(GetModel.FlowId, GetModel.NodeId, GetModel.NodeName, results);
- LastResults = results;
- System.Diagnostics.Debug.WriteLine($"[InitRun] {GetModel.NodeName}: {ex}");
- return false;
- }
- }
- public NodeRunStatus Run(CancellationToken token)
- {
- IsSuccess = NodeRunStatus.Running;
- NodeRunStatus status;
- try
- {
- Dictionary<string, object> results;
- status = PluginRun(token, out results);
- LastResults = results;
- IsSuccess = status;
- }
- catch (System.Exception)
- {
- IsSuccess = NodeRunStatus.Failed;
- status = NodeRunStatus.Failed;
- }
- return status;
- }
- /// <summary>
- /// 通过公式获取节点执行结果值
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="formula"></param>
- /// <returns></returns>
- public T GetValue<T>(FormulaBound<T> formula)
- {
- if (formula == null)
- return default(T);
- object _result = new object();
- _result = RegistryOrDebug.ResolveFormula(GetModel.FlowId, formula.Formula);
- if (_result == null || _result?.ToString() == "")
- return formula.Value;
- else if (typeof(T).IsInterface)
- {
- if (_result is T tResult)
- return tResult;
- else
- return default(T);
- }
- else
- return (T)System.Convert.ChangeType(_result, typeof(T));
- }
- public object GetResolve(FormulaBound<object> formula)
- {
- if (formula == null)
- return default(object);
- object _result = new object();
- _result = RegistryOrDebug.ResolveFormula(GetModel.FlowId, formula.Formula);
- if (_result == null || _result?.ToString() == "")
- return formula.Value;
- else
- return _result;
- }
- /// <summary>
- /// 保存一条插件日志(像 GetValue 一样直接调用)。
- /// level 是详细度等级(1低/2中/3高/4终):超过本插件设置的"日志等级"就跳过对应通道(存储/显示各一道,详见下行);
- /// 两道独立闸门:level ≤ 节点「存储详细度」才写文件(1/2 公共日志,3/4 流程/任务 独立路径);level ≤ 节点「显示详细度」才进实时日志控件(可存而不显、显而不存)。category 是类别(Info/Warning/Error),只作标记不影响存/显。
- /// 例:Log(1, "开始执行"); Log(3, "通讯超时", TeamAAS.LogLevel.Warning);
- /// </summary>
- public void Log(int level, string message, TeamAAS.LogLevel category = TeamAAS.LogLevel.Info)
- => TeamAAS.Logging.PluginLogger.Log(
- Model.FlowName, Model.NodeName, Model.StoreVerbosity, Model.DisplayVerbosity, level, message, category);
- }
- }
|