Forráskód Böngészése

sender, receiver with general data works

Dalibor Votruba 2 éve
szülő
commit
a317f08f58

+ 10 - 3
Workbench/QMonitor/qmonlib/Program.cs

@@ -6,8 +6,15 @@ using Quadarax.Foundation.Core.Logging;
 Console.WriteLine("Hello, World!");
 
 var logger = new ConsoleLogger();
-using (var cli = new QMonClient("TST", QMonConfiuration.CreateDefault(), logger))
+using (var cli = new QMonClient("TST", QMonClientConfiuration.CreateDefault(), logger))
 {
-    Console.WriteLine("Press any key to exit...");
-    Console.ReadKey();
+    using (var rcv = new QMonReceiver(QMonReceiverConfiguration.CreateDefault(), logger, OnGeneralReceived))
+    {
+        Console.WriteLine("Press any key to close...");
+        Console.ReadKey();
+    }
+}
+void OnGeneralReceived(MonGeneral general)
+{
+    Console.WriteLine($"General received: {general.InstanceIdentifier} items count {general.Items.Count}");
 }

+ 24 - 76
Workbench/QMonitor/qmonlib/QMonClient.cs

@@ -6,47 +6,31 @@ using System.Reflection;
 using System.Text;
 using qmonlib.Attributes;
 using Quadarax.Foundation.Core.Logging;
-using Quadarax.Foundation.Core.Object;
 using Quadarax.Foundation.Core.Reflection.Extensions;
 
 namespace qmonlib
 {
-    public class QMonClient : DisposableObject
+    public class QMonClient : QMonHostBase<QMonClientConfiuration>
     {
         #region *** Properties ***
-        public bool IsEnabled
-        {
-            get => _isEnabled;
-            set
-            {
-                SetEnabled(value);
-            }
-        }
+
+        protected override Uri UriGeneral => Configuration.TargetUriGeneral;
+        protected override Uri UriData => Configuration.TargetUriData;
+        protected override TimeSpan IntervalGeneral => Configuration.EmitGeneralInterval;
+        protected override TimeSpan? IntervalData => Configuration.EmitDataInterval;
+
         public string InstanceIdentifier { get; }
         #endregion
 
         #region *** Fields ***
-        private bool _isEnabled;
-        private QMonConfiuration _configuration;
-        private UdpClient? _udpClientGeneral;
-        private UdpClient? _udpClientData;
-
-        private Timer? _timerGeneral;
-        private Timer? _timerData;
-
         private IDictionary<string, MonItemGeneral> _generalCache = new Dictionary<string, MonItemGeneral>();
-        private ILog? _log;
-        private Quadarax.Foundation.Core.Json.Binder _binder = new Quadarax.Foundation.Core.Json.Binder(new FileSystem(),false,true,100);
         
         #endregion
 
         #region *** Constructors ***
-        public QMonClient(string instanceIdentifier, QMonConfiuration configuration, ILogger? externalLogger)
+        public QMonClient(string instanceIdentifier, QMonClientConfiuration configuration, ILogger? externalLogger) : base(configuration, externalLogger)
         {
-            _log = externalLogger?.GetLogger(GetType());
             InstanceIdentifier = instanceIdentifier ?? throw new ArgumentNullException(nameof(instanceIdentifier));
-            _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
-            SetEnabled(_configuration.Enabled);
             ScanAssemblies();
         }
 
@@ -105,32 +89,19 @@ namespace qmonlib
         #region *** Protected Operations ***
         protected override void OnDisposing()
         {
-            Close();
+            base.OnDisposing();
             _generalCache.Clear();
         }
 
-        private void Open()
-        {
-            if (_udpClientGeneral != null) throw new InvalidOperationException("UDP client channel General already open. Close first.");
-            if (_udpClientData != null) throw new InvalidOperationException("UDP client channel Data already open. Close first.");
-
-            _udpClientGeneral = CreateUdpClient(_configuration.TargetUriGeneral);
-            _udpClientData = CreateUdpClient(_configuration.TargetUriData);
-
-            _timerGeneral = new Timer(OnTimerGeneral, this, _configuration.EmitGeneralInterval, _configuration.EmitGeneralInterval);
-            _timerData = new Timer(OnTimerData, this, _configuration.EmitDataInterval, _configuration.EmitDataInterval);
-        }
-
-        private void OnTimerData(object? state)
+        protected override void OnTimerData(object? state)
         {
             
         }
 
-        private void OnTimerGeneral(object? state)
+        protected override void OnTimerGeneral(object? state)
         {
             if (state == null) throw new ArgumentNullException(nameof(state));
             var owner = (QMonClient)state;
-            if (owner._udpClientGeneral == null) throw new InvalidOperationException("UDP client channel General not open.");
             try
             {
               
@@ -141,59 +112,36 @@ namespace qmonlib
                 };
                 data.Items.AddRange(owner._generalCache.Values);
                 var dataOut = Serialize(data);
-                _udpClientGeneral?.Send(dataOut);
-                _log?.Log(LogSeverityEnum.Trace, $"[{InstanceIdentifier}] Sent General packet size = {dataOut.Length} bytes");
+                UdpClientGeneral.Send(dataOut);
+                Log(LogSeverityEnum.Trace, $"[{InstanceIdentifier}] Sent General packet size = {dataOut.Length} bytes");
             }
             catch(Exception ex)
             {
-                _log?.Log(LogSeverityEnum.Error, $"[{InstanceIdentifier}] Error sending general data", ex);
+                Log(LogSeverityEnum.Error, $"[{InstanceIdentifier}] Error sending general data", ex);
             }
         }
 
         private byte[] Serialize(MonGeneral data)
         {
             if (data == null) throw new ArgumentNullException(nameof(data));
-            var json = _binder.SaveToString(data);
+            var json = Binder.SaveToString(data);
             return Encoding.UTF8.GetBytes(json);
         }
-
-        private void Close()
-        {
-            if (_udpClientGeneral != null)
-            {
-                _timerGeneral?.Dispose();
-                _udpClientGeneral.Close();
-                _udpClientGeneral.Dispose();
-                _udpClientGeneral = null;
-                _timerGeneral = null;
-            }
-
-            if (_udpClientData != null)
-            {
-                _timerData?.Dispose();
-                _udpClientData.Close();
-                _udpClientData.Dispose();
-                _udpClientData = null;
-                _timerData = null;
-            }
-        }
-
-        private UdpClient CreateUdpClient(Uri targetUri)
+        protected override UdpClient CreateUdpClient(Uri targetUri)
         {
             var ep = new IPEndPoint(IPAddress.Parse(targetUri.DnsSafeHost), targetUri.Port);
             var udpClient = new UdpClient();
             udpClient.Connect(ep);
             return udpClient;
         }
-        private void SetEnabled(bool value)
-        {  
-            if (value == _isEnabled)
-                return;
-            _isEnabled = value;
-            if (_isEnabled)
-                Open();
-            else
-                Close();
+
+        protected override void OnOpen()
+        {
+        }
+
+        protected override void OnClose()
+        {
+            
         }
         #endregion
 

+ 3 - 4
Workbench/QMonitor/qmonlib/QMonConfiuration.cs → Workbench/QMonitor/qmonlib/QMonClientConfiuration.cs

@@ -1,17 +1,16 @@
 namespace qmonlib
 {
-    public class QMonConfiuration
+    public class QMonClientConfiuration : QMonHostConfiguration
     {
-        public bool Enabled { get; set; }
         public Uri TargetUriGeneral { get; set; }
         public Uri TargetUriData { get; set; }
 
         public TimeSpan EmitGeneralInterval { get; set; }
         public TimeSpan EmitDataInterval { get; set; }
 
-        public static QMonConfiuration CreateDefault()
+        public static QMonClientConfiuration CreateDefault()
         {
-            return new QMonConfiuration
+            return new QMonClientConfiuration
             {
                 Enabled = true,
                 TargetUriGeneral = new Uri("udp://127.0.0.1:5100"),

+ 121 - 0
Workbench/QMonitor/qmonlib/QMonHostBase.cs

@@ -0,0 +1,121 @@
+using System.IO.Abstractions;
+using System.Net;
+using System.Net.Sockets;
+using Quadarax.Foundation.Core.Logging;
+using Quadarax.Foundation.Core.Object;
+
+namespace qmonlib
+{
+    public abstract class QMonHostBase<TConfiguration> : DisposableObject 
+        where TConfiguration : QMonHostConfiguration
+    {
+
+        #region *** Fields ***
+        private bool _isEnabled;
+        private ILog? _log;
+
+        private UdpClient? _udpClientGeneral;
+        private UdpClient? _udpClientData;
+
+        private Timer? _timerGeneral;
+        private Timer? _timerData;
+
+        #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 UdpClient UdpClientGeneral => _udpClientGeneral ?? throw new InvalidOperationException("UDP client channel General not open.");
+        protected UdpClient UdpClientData => _udpClientData ?? throw new InvalidOperationException("UDP client channel Data not open.");
+        public bool IsEnabled
+        {
+            get => _isEnabled;
+            set => SetEnabled(value);
+        }
+        protected Quadarax.Foundation.Core.Json.Binder Binder { get; } = new Quadarax.Foundation.Core.Json.Binder(new FileSystem(),false,true,100);
+
+        #endregion
+
+        #region *** Constructors ***
+
+        protected QMonHostBase(TConfiguration configuration, ILogger? 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 (_udpClientGeneral != null) throw new InvalidOperationException("UDP client channel General already open. Close first.");
+            if (_udpClientData != null) throw new InvalidOperationException("UDP client channel Data already open. Close first.");
+
+            _udpClientGeneral = CreateUdpClient(UriGeneral);
+            _udpClientData = CreateUdpClient(UriData);
+
+            _timerGeneral = new Timer(OnTimerGeneral, this, IntervalGeneral, IntervalGeneral);
+            if (IntervalData.HasValue)
+                _timerData = new Timer(OnTimerData, this, IntervalData.Value, IntervalData.Value);
+            
+            OnOpen();
+        }
+        protected void Close()
+        {
+            if (!_isEnabled) return;
+         
+            if (_udpClientGeneral != null)
+            {
+                _timerGeneral?.Dispose();
+                _udpClientGeneral.Close();
+                _udpClientGeneral.Dispose();
+                _udpClientGeneral = null;
+                _timerGeneral = null;
+            }
+
+            if (_udpClientData != null)
+            {
+                _timerData?.Dispose();
+                _udpClientData.Close();
+                _udpClientData.Dispose();
+                _udpClientData = null;
+                _timerData = null;
+            }
+            OnClose();
+        }
+
+        protected abstract void OnOpen();
+        protected abstract void OnClose();
+        protected abstract void OnTimerData(object? state);
+        protected abstract void OnTimerGeneral(object? state);
+        #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);
+    }
+}

+ 7 - 0
Workbench/QMonitor/qmonlib/QMonHostConfiguration.cs

@@ -0,0 +1,7 @@
+namespace qmonlib
+{
+    public abstract class QMonHostConfiguration
+    {
+        public bool Enabled { get; set; }
+    }
+}

+ 87 - 0
Workbench/QMonitor/qmonlib/QMonReceiver.cs

@@ -0,0 +1,87 @@
+using System.Collections.Concurrent;
+using System.Data;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using Quadarax.Foundation.Core.Logging;
+using Quadarax.Foundation.Core.Object;
+
+namespace qmonlib
+{
+    public delegate void GeneralDataReceivedDelegate(MonGeneral general);
+    public class QMonReceiver : QMonHostBase<QMonReceiverConfiguration> 
+    {
+        #region *** Properties ***
+        protected override Uri UriGeneral => Configuration.SourceUriGeneral;
+        protected override Uri UriData => Configuration.SourceUriData;
+        protected override TimeSpan IntervalGeneral => Configuration.GeneralReceiverInterval;
+        protected override TimeSpan? IntervalData => null;
+        public MonGeneral[] AvailableGeneral => _generalCache.Values.ToArray();
+        #endregion
+        #region *** Fields ***
+        private GeneralDataReceivedDelegate _generalReceivedCallback;
+
+            private bool _isReceivingGeneral;
+        private IDictionary<string, MonGeneral> _generalCache = new ConcurrentDictionary<string, MonGeneral>();
+        #endregion
+        #region *** Constructors ***
+        public QMonReceiver(QMonReceiverConfiguration configuration, ILogger logger, GeneralDataReceivedDelegate generalDataReceivedCallback = null) : base(configuration, logger)
+        {
+            _generalReceivedCallback = generalDataReceivedCallback;
+        }
+        #endregion
+        
+
+        #region *** Private overrides ***
+
+        protected override void OnOpen()
+        {
+        }
+
+        protected override void OnClose()
+        {
+        }
+
+        protected override void OnTimerData(object? state)
+        {
+            throw new NotSupportedException("Timer is not allowed in receiver.");
+        }
+
+        protected override void OnTimerGeneral(object? state)
+        {
+            if (state == null) throw new ArgumentNullException(nameof(state));
+            var owner = (QMonReceiver)state;
+            if (owner._isReceivingGeneral) return;
+            owner._isReceivingGeneral = true;
+            try
+            {
+                var remoteEndPoint = new IPEndPoint(IPAddress.Parse(owner.UriGeneral.DnsSafeHost), owner.UriGeneral.Port);
+                var data = UdpClientGeneral.Receive(ref remoteEndPoint);
+                var general = (MonGeneral) Binder.LoadFromString(Encoding.UTF8.GetString(data), typeof(MonGeneral));
+                Log(LogSeverityEnum.Debug,
+                    $"[ReceiverGeneral] receive general data from '{remoteEndPoint}' [{general.InstanceIdentifier}] size={data.Length} bytes.");
+
+                _generalCache.TryAdd(general.InstanceIdentifier, general);
+                _generalReceivedCallback?.Invoke(general);
+            }
+            catch (Exception e)
+            {
+                Log(LogSeverityEnum.Error, $"[ReceiverGeneral] Error receiving general data", e);
+            }
+            finally
+            {
+                owner._isReceivingGeneral = false;
+            }
+        }
+        protected override UdpClient CreateUdpClient(Uri targetUri)
+        {
+            var udpClient = new UdpClient(targetUri.Port);
+            return udpClient;
+        }
+
+        protected override void OnDisposing()
+        {
+        }
+        #endregion
+    }
+}

+ 37 - 0
Workbench/QMonitor/qmonlib/QMonReceiverConfiuration.cs

@@ -0,0 +1,37 @@
+namespace qmonlib
+{
+    public class QMonReceiverConfiguration : QMonHostConfiguration
+    {
+        public Uri SourceUriGeneral { get; set; }
+        public Uri SourceUriData { get; set; }
+        public TimeSpan GeneralReceiverInterval { get; set; }
+
+
+        public DataCacheConfiguration DataCache { get; set; } = new();
+
+        public static QMonReceiverConfiguration CreateDefault()
+        {
+            return new QMonReceiverConfiguration()
+            {
+                Enabled = true,
+                SourceUriGeneral = new Uri("udp://0.0.0.0:5100"),
+                SourceUriData = new Uri("udp://0.0.0.0:5101"),
+                GeneralReceiverInterval = TimeSpan.FromSeconds(5),
+                DataCache = new DataCacheConfiguration()
+                {
+					Path = "%AppData%\\.qmon",
+					RecordRetentionTimeSpan = TimeSpan.FromHours(5),
+                    FlushCacheInterval = TimeSpan.FromSeconds(5)
+				}
+            };
+        }
+
+        public class DataCacheConfiguration
+        {
+            public string Path { get; set; }
+            public TimeSpan RecordRetentionTimeSpan { get; set; }
+
+            public TimeSpan FlushCacheInterval { get; set; }
+        }
+    }
+}