IPluginContext.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. using System;
  2. using System.Collections.Generic;
  3. namespace TeamAAS.Global
  4. {
  5. /// <summary>
  6. /// 插件运行上下文:插件获取平台服务的唯一正规渠道。
  7. /// 目标:插件代码不再直接摸 CameraManager.Instance 等静态单例,
  8. /// 而是向宿主要服务 —— 宿主可以把服务放在本进程、独立进程甚至远端(分布式扩展点)。
  9. /// 阶段1:接口先行,宿主适配器后续接入;现有插件行为不受影响。
  10. /// </summary>
  11. public interface IPluginContext
  12. {
  13. /// <summary>按类型获取平台服务(相机/机器人/通讯/供料/运动卡管理器等)。未注册返回 null。</summary>
  14. T GetService<T>();
  15. /// <summary>按类型对象获取平台服务(非泛型版,供反射场景)。未注册返回 null。</summary>
  16. object GetService(Type serviceType);
  17. /// <summary>按类型与名称获取设备(如相机名、通讯设备名)。找不到返回 null。</summary>
  18. T GetDevice<T>(string deviceName);
  19. /// <summary>获取某类设备的全部实例。</summary>
  20. IEnumerable<T> GetDevices<T>();
  21. /// <summary>写一条插件日志(level 1~4 详细度,语义与 BasePlugin.Log 一致)。</summary>
  22. void Log(string flowName, string nodeName, int level, string message, string category = "Info");
  23. }
  24. /// <summary>
  25. /// 简单服务注册表:宿主启动时注册实例,插件经由 IPluginContext 消费。
  26. /// 线程安全;第一阶段由主程序把现有 Manager 单例注册进来(Adapter 模式,零行为变化)。
  27. /// </summary>
  28. public sealed class ServiceRegistry : IPluginContext
  29. {
  30. private static readonly Lazy<ServiceRegistry> _default =
  31. new Lazy<ServiceRegistry>(() => new ServiceRegistry(), isThreadSafe: true);
  32. /// <summary>全局默认注册表(宿主未注入自定义实现时使用)。</summary>
  33. public static ServiceRegistry Default => _default.Value;
  34. private readonly object _sync = new object();
  35. private readonly Dictionary<Type, object> _services = new Dictionary<Type, object>();
  36. /// <summary>注册/替换一个服务实例(按具体类型索引)。</summary>
  37. public void Register<T>(T service)
  38. {
  39. if (service == null) return;
  40. lock (_sync) { _services[typeof(T)] = service; }
  41. }
  42. /// <summary>移除注册。</summary>
  43. public void Unregister<T>()
  44. {
  45. lock (_sync) { _services.Remove(typeof(T)); }
  46. }
  47. /// <inheritdoc />
  48. public T GetService<T>()
  49. {
  50. return (T)GetService(typeof(T));
  51. }
  52. /// <inheritdoc />
  53. public object GetService(Type serviceType)
  54. {
  55. if (serviceType == null) return null;
  56. lock (_sync)
  57. {
  58. object svc;
  59. return _services.TryGetValue(serviceType, out svc) ? svc : null;
  60. }
  61. }
  62. /// <inheritdoc />
  63. public T GetDevice<T>(string deviceName)
  64. {
  65. foreach (var device in GetDevices<T>())
  66. {
  67. var named = device as TeamAAS.Global.Devices.INamedDevice;
  68. if (named == null) continue; // 设备类型未实现 INamedDevice 时无法按名查找
  69. if (string.Equals(named.Name, deviceName, StringComparison.OrdinalIgnoreCase))
  70. return device;
  71. }
  72. return default(T);
  73. }
  74. /// <inheritdoc />
  75. public IEnumerable<T> GetDevices<T>()
  76. {
  77. // IDeviceProvider<TDevice> 带 INamedDevice 约束,此处经反射构造闭合泛型接口后取服务,
  78. // 保持 GetDevices<T> 对调用方无约束(注册方负责满足约束)。
  79. var providerType = typeof(TeamAAS.Global.Devices.IDeviceProvider<>).MakeGenericType(typeof(T));
  80. var provider = GetService(providerType);
  81. if (provider != null)
  82. {
  83. var devices = providerType.GetProperty("Devices")?.GetValue(provider) as IEnumerable<T>;
  84. if (devices != null)
  85. {
  86. foreach (var d in devices) yield return d;
  87. }
  88. yield break;
  89. }
  90. // 兜底:设备集合本身被当作服务注册(IReadOnlyList<T> 等)
  91. var list = GetService<System.Collections.Generic.IReadOnlyList<T>>();
  92. if (list != null)
  93. {
  94. foreach (var d in list) yield return d;
  95. }
  96. }
  97. /// <inheritdoc />
  98. public void Log(string flowName, string nodeName, int level, string message, string category = "Info")
  99. {
  100. // 阶段1:转发到控制台,宿主接入 PluginLogger 后替换(避免 SDK 反向依赖 TeamAAS.Global)
  101. System.Diagnostics.Debug.WriteLine($"[{category}][L{level}][{flowName}/{nodeName}] {message}");
  102. }
  103. }
  104. }