using System.Runtime.InteropServices; using AVEVA.Historian.Client.Models; using AVEVA.Historian.Client.Wcf; namespace AVEVA.Historian.Client.Protocol; internal sealed class Historian2020ProtocolDialect { private readonly HistorianClientOptions _options; public Historian2020ProtocolDialect(HistorianClientOptions options) { _options = options ?? throw new ArgumentNullException(nameof(options)); } public IAsyncEnumerable ReadRawAsync(string tag, DateTime startUtc, DateTime endUtc, int maxValues, CancellationToken cancellationToken) { if (_options.Transport != HistorianTransport.LocalPipe) { return Missing($"StartDataRetrievalQuery/Full over {_options.Transport}", cancellationToken); } if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { return Missing("StartDataRetrievalQuery/Full requires Windows for the LocalPipe + SSPI path", cancellationToken); } return ReadRawWindowsAsync(tag, startUtc, endUtc, maxValues, cancellationToken); } private IAsyncEnumerable ReadRawWindowsAsync(string tag, DateTime startUtc, DateTime endUtc, int maxValues, CancellationToken cancellationToken) { #pragma warning disable CA1416 // Validated by RuntimeInformation.IsOSPlatform check above. HistorianWcfReadOrchestrator orchestrator = new(_options); return orchestrator.ReadRawAsync(tag, startUtc, endUtc, maxValues, cancellationToken); #pragma warning restore CA1416 } public IAsyncEnumerable ReadAggregateAsync(string tag, DateTime startUtc, DateTime endUtc, RetrievalMode mode, TimeSpan interval, CancellationToken cancellationToken) { if (_options.Transport != HistorianTransport.LocalPipe) { return Missing($"StartDataRetrievalQuery/{mode} over {_options.Transport}", cancellationToken); } if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { return Missing($"StartDataRetrievalQuery/{mode} requires Windows for the LocalPipe + SSPI path", cancellationToken); } return ReadAggregateWindowsAsync(tag, startUtc, endUtc, mode, interval, cancellationToken); } private IAsyncEnumerable ReadAggregateWindowsAsync(string tag, DateTime startUtc, DateTime endUtc, RetrievalMode mode, TimeSpan interval, CancellationToken cancellationToken) { #pragma warning disable CA1416 HistorianWcfReadOrchestrator orchestrator = new(_options); return orchestrator.ReadAggregateAsync(tag, startUtc, endUtc, mode, interval, cancellationToken); #pragma warning restore CA1416 } public Task> ReadAtTimeAsync(string tag, IReadOnlyList timestampsUtc, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (_options.Transport != HistorianTransport.LocalPipe) { throw new ProtocolEvidenceMissingException($"StartDataRetrievalQuery/Interpolated at-time over {_options.Transport}"); } if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { throw new ProtocolEvidenceMissingException("StartDataRetrievalQuery/Interpolated at-time requires Windows for the LocalPipe + SSPI path"); } #pragma warning disable CA1416 HistorianWcfReadOrchestrator orchestrator = new(_options); return orchestrator.ReadAtTimeAsync(tag, timestampsUtc, cancellationToken); #pragma warning restore CA1416 } public IAsyncEnumerable ReadBlocksAsync(string tag, DateTime startUtc, DateTime endUtc, CancellationToken cancellationToken) { return Missing("StartBlockRetrievalQuery", cancellationToken); } public IAsyncEnumerable ReadEventsAsync(DateTime startUtc, DateTime endUtc, CancellationToken cancellationToken) { if (_options.Transport != HistorianTransport.LocalPipe) { return Missing($"StartEventDataRetrievalQuery over {_options.Transport}", cancellationToken); } if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { return Missing("StartEventDataRetrievalQuery requires Windows for the LocalPipe + SSPI path", cancellationToken); } return ReadEventsWindowsAsync(startUtc, endUtc, cancellationToken); } private IAsyncEnumerable ReadEventsWindowsAsync(DateTime startUtc, DateTime endUtc, CancellationToken cancellationToken) { #pragma warning disable CA1416 HistorianWcfEventOrchestrator orchestrator = new(_options); return orchestrator.ReadEventsAsync(startUtc, endUtc, cancellationToken); #pragma warning restore CA1416 } public IAsyncEnumerable BrowseTagNamesAsync(string filter, CancellationToken cancellationToken) { return Missing("StartLikeTagNameSearch/GetLikeTagnames", cancellationToken); } public Task GetTagMetadataAsync(string tag, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); throw new ProtocolEvidenceMissingException("GetTagInfoByName/GetTagInfos"); } public Task GetConnectionStatusAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (!OperatingSystem.IsWindows()) { throw new ProtocolEvidenceMissingException("GetConnectionStatus on non-Windows"); } return Wcf.HistorianWcfStatusClient.GetConnectionStatusAsync(_options, cancellationToken); } public Task GetStoreForwardStatusAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (!OperatingSystem.IsWindows()) { throw new ProtocolEvidenceMissingException("GetStoreForwardStatus on non-Windows"); } return Wcf.HistorianWcfStatusClient.GetStoreForwardStatusAsync(_options, cancellationToken); } public Task GetSystemParameterAsync(string name, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ArgumentException.ThrowIfNullOrWhiteSpace(name); if (!OperatingSystem.IsWindows()) { throw new ProtocolEvidenceMissingException("GetSystemParameter on non-Windows"); } return Wcf.HistorianWcfStatusClient.GetSystemParameterAsync(_options, name, cancellationToken); } private static async IAsyncEnumerable Missing( string operation, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken) { await Task.Yield(); cancellationToken.ThrowIfCancellationRequested(); throw new ProtocolEvidenceMissingException(operation); #pragma warning disable CS0162 yield break; #pragma warning restore CS0162 } }