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; /// /// Application 层的协议轮询服务。 /// 按配置编排模板与规则,并触发对应处理器执行。 /// public class ProtocolMonitoringHostedService : BackgroundService { private readonly ISimulatorInstanceManager _instanceManager; private readonly IProtocolTemplateService _templateService; private readonly Dictionary _protocolHandlers; private readonly ILogger _logger; private readonly ProtocolMonitoringOptions _options; private readonly Dictionary _runtimeStates = new(StringComparer.OrdinalIgnoreCase); public ProtocolMonitoringHostedService( ISimulatorInstanceManager instanceManager, IProtocolTemplateService templateService, IOptions options, IEnumerable protocolHandlers, ILogger 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); } } }