using System.IO.Abstractions; using System.Net.Sockets; using Quadarax.Foundation.Core.Logging; using Quadarax.Foundation.Core.Object; using Quadarax.Foundation.Core.Thread; namespace Quadarax.Foundation.Core.QMonitor { public abstract class QMonHostBase : DisposableObject where TConfiguration : QMonHostConfiguration { #region *** Fields *** private bool _isEnabled; private readonly ILog? _log; private readonly ILogger? _logger; #endregion #region *** Properties *** protected TConfiguration Configuration { get; } protected abstract Uri UriGeneral { get; } protected abstract Uri UriData { get; } protected abstract TimeSpan IntervalGeneral { get; } protected abstract TimeSpan? IntervalData { get; } protected LoopWorker? WorkerGeneral { get; private set; } protected LoopWorker? WorkerData { get; private set; } protected ILogger? Logger => _logger; public bool IsEnabled { get => _isEnabled; set => SetEnabled(value); } protected Json.Binder Binder { get; } = new Json.Binder(new FileSystem(), false, true, 100); #endregion #region *** Constructors *** protected QMonHostBase(TConfiguration configuration, ILogger? externalLogger) { _logger = externalLogger; Configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); _log = externalLogger?.GetLogger(GetType()); SetEnabled(configuration.Enabled); } #endregion #region *** Private Operations *** protected void Open() { if (!_isEnabled) return; if (WorkerGeneral != null) throw new InvalidOperationException("UDP client channel General already open. Close first."); if (WorkerData != null) throw new InvalidOperationException("UDP client channel Data already open. Close first."); var contextGeneral = new QMonWorkerContext(CreateUdpClient(UriGeneral)); WorkerGeneral = new LoopWorker("GeneralWorker", contextGeneral,async (_)=>await OnTimerGeneral(contextGeneral), _logger); WorkerGeneral.IterationsDelayBetween = IntervalGeneral; WorkerGeneral.Start(); Log(LogSeverityEnum.Debug, $"General worker started with interval '{IntervalGeneral}'"); if (IntervalData.HasValue) { var contextData = new QMonWorkerContext(CreateUdpClient(UriData)); WorkerData = new LoopWorker("GeneralWorker", contextData,async (_)=>await OnTimerData(contextData), _logger); WorkerData.IterationsDelayBetween = IntervalData.Value; WorkerData.Start(); Log(LogSeverityEnum.Debug, $"Data worker started with interval '{IntervalData}'"); } OnOpen(); } protected void Close() { if (!_isEnabled) return; WorkerGeneral?.Stop(); WorkerGeneral?.Dispose(); WorkerGeneral = null; WorkerData?.Stop(); WorkerData?.Dispose(); WorkerData = null; OnClose(); } protected abstract void OnOpen(); protected abstract void OnClose(); #pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously protected virtual async Task OnTimerData(QMonWorkerContext context) #pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously { throw new NotImplementedException(); } #pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously protected virtual async Task OnTimerGeneral(QMonWorkerContext context) #pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously { throw new NotImplementedException(); } #endregion protected void SetEnabled(bool value) { if (value == _isEnabled) return; _isEnabled = value; if (_isEnabled) Open(); else Close(); } protected override void OnDisposing() { Close(); } protected void Log(LogSeverityEnum type, string message, Exception? e = null) { _log?.Log(type, message, e); } protected abstract UdpClient CreateUdpClient(Uri targetUri); } }