using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Options;
|
using WIDESEAWCS_S7Simulator.Core.Enums;
|
using WIDESEAWCS_S7Simulator.Core.Interfaces;
|
using WIDESEAWCS_S7Simulator.Core.Protocol;
|
|
namespace WIDESEAWCS_S7Simulator.Application.Protocol;
|
|
/// <summary>
|
/// Application 层的协议轮询服务。
|
/// 按配置编排模板与规则,并触发对应处理器执行。
|
/// </summary>
|
public class ProtocolMonitoringHostedService : BackgroundService
|
{
|
private readonly ISimulatorInstanceManager _instanceManager;
|
private readonly IProtocolTemplateService _templateService;
|
private readonly Dictionary<string, IDeviceProtocolHandler> _protocolHandlers;
|
private readonly ILogger<ProtocolMonitoringHostedService> _logger;
|
private readonly ProtocolMonitoringOptions _options;
|
private readonly Dictionary<string, ProtocolRuntimeState> _runtimeStates = new(StringComparer.OrdinalIgnoreCase);
|
|
public ProtocolMonitoringHostedService(
|
ISimulatorInstanceManager instanceManager,
|
IProtocolTemplateService templateService,
|
IOptions<ProtocolMonitoringOptions> options,
|
IEnumerable<IDeviceProtocolHandler> protocolHandlers,
|
ILogger<ProtocolMonitoringHostedService> logger)
|
{
|
_instanceManager = instanceManager;
|
_templateService = templateService;
|
_protocolHandlers = protocolHandlers.ToDictionary(x => x.ProtocolName, StringComparer.OrdinalIgnoreCase);
|
_logger = logger;
|
_options = options.Value;
|
}
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
{
|
var intervalMs = Math.Max(50, _options.PollingIntervalMs);
|
|
while (!stoppingToken.IsCancellationRequested)
|
{
|
try
|
{
|
var bindings = _options.TemplateBindings;
|
|
foreach (var instance in _instanceManager.GetAllInstances())
|
{
|
if (instance.GetState().Status != InstanceStatus.Running)
|
{
|
continue;
|
}
|
|
var templateId = instance.Config.ProtocolTemplateId;
|
if (string.IsNullOrWhiteSpace(templateId))
|
{
|
continue;
|
}
|
|
var binding = bindings.FirstOrDefault(x => string.Equals(x.TemplateId, templateId, StringComparison.OrdinalIgnoreCase));
|
if (binding == null)
|
{
|
continue;
|
}
|
|
if (!_protocolHandlers.TryGetValue(binding.ProtocolName, out var protocolHandler))
|
{
|
continue;
|
}
|
|
var template = await _templateService.GetByIdAsync(templateId);
|
if (template == null)
|
{
|
continue;
|
}
|
|
if (!_runtimeStates.TryGetValue(instance.Config.Id, out var runtimeState))
|
{
|
runtimeState = new ProtocolRuntimeState();
|
_runtimeStates[instance.Config.Id] = runtimeState;
|
}
|
|
// 每轮先把实例当前内存同步到 MemoryStore,再执行规则处理。
|
var memoryData = instance.ExportMemory();
|
instance.MemoryStore.Import(memoryData);
|
|
var changed = protocolHandler.Process(instance.MemoryStore, template, runtimeState);
|
|
// 处理器有变更时,回写到 PLC 运行内存。
|
if (changed)
|
{
|
var updated = instance.MemoryStore.Export();
|
instance.ImportMemory(updated);
|
}
|
}
|
}
|
catch (Exception ex)
|
{
|
_logger.LogWarning(ex, "Protocol monitoring loop failed.");
|
}
|
|
await Task.Delay(intervalMs, stoppingToken);
|
}
|
}
|
}
|