QMonClient.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. using System.ComponentModel.DataAnnotations;
  2. using System.IO.Abstractions;
  3. using System.Net;
  4. using System.Net.Sockets;
  5. using System.Reflection;
  6. using System.Text;
  7. using qmonlib.Attributes;
  8. using Quadarax.Foundation.Core.Logging;
  9. using Quadarax.Foundation.Core.Object;
  10. using Quadarax.Foundation.Core.Reflection.Extensions;
  11. namespace qmonlib
  12. {
  13. public class QMonClient : DisposableObject
  14. {
  15. #region *** Properties ***
  16. public bool IsEnabled
  17. {
  18. get => _isEnabled;
  19. set
  20. {
  21. SetEnabled(value);
  22. }
  23. }
  24. public string InstanceIdentifier { get; }
  25. #endregion
  26. #region *** Fields ***
  27. private bool _isEnabled;
  28. private QMonConfiuration _configuration;
  29. private UdpClient? _udpClientGeneral;
  30. private UdpClient? _udpClientData;
  31. private Timer? _timerGeneral;
  32. private Timer? _timerData;
  33. private IDictionary<string, MonItemGeneral> _generalCache = new Dictionary<string, MonItemGeneral>();
  34. private ILog? _log;
  35. private Quadarax.Foundation.Core.Json.Binder _binder = new Quadarax.Foundation.Core.Json.Binder(new FileSystem(),false,true,100);
  36. #endregion
  37. #region *** Constructors ***
  38. public QMonClient(string instanceIdentifier, QMonConfiuration configuration, ILogger? externalLogger)
  39. {
  40. _log = externalLogger?.GetLogger(GetType());
  41. InstanceIdentifier = instanceIdentifier ?? throw new ArgumentNullException(nameof(instanceIdentifier));
  42. _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
  43. SetEnabled(_configuration.Enabled);
  44. ScanAssemblies();
  45. }
  46. private void ScanAssemblies()
  47. {
  48. var assemblies = AppDomain.CurrentDomain.GetAssemblies();
  49. foreach (var assembly in assemblies)
  50. {
  51. var types = assembly.GetTypesWithAttribute<MonitoredClassAttribute>(true);
  52. foreach (var type in types)
  53. {
  54. var monItemGeneral = new MonItemGeneral
  55. {
  56. Caption = type.GetCustomAttribute<MonitoredClassAttribute>()?.Caption ?? type.Name,
  57. Description = type.GetCustomAttribute<MonitoredClassAttribute>()?.Description ?? string.Empty,
  58. ViewType = MonItemGeneral.MonViewType.Item
  59. };
  60. var properties = type.GetPropertiesWithAttribute<MonitoredPropertyAttribute>(true);
  61. var keys = new List<Tuple<string,int>>();
  62. foreach (var property in properties)
  63. {
  64. var itemDescriptor = new MonItemGeneral.ItemDescriptor
  65. {
  66. Name = property.Name,
  67. TypeName = property.PropertyType.Name,
  68. Label = property.GetCustomAttribute<MonitoredPropertyAttribute>()?.Label ?? property.Name,
  69. Description = property.GetCustomAttribute<MonitoredPropertyAttribute>()?.Description ?? string.Empty,
  70. Order = property.GetCustomAttribute<MonitoredPropertyAttribute>()?.Order ?? 0,
  71. _propertyInfo = property
  72. };
  73. monItemGeneral.Items.Add(itemDescriptor);
  74. if (property.GetCustomAttribute<MonitoredPropertyKeyAttribute>() != null)
  75. {
  76. keys.Add(new Tuple<string, int>(property.Name, property.GetCustomAttribute<MonitoredPropertyKeyAttribute>()!.KeyOrder));
  77. }
  78. }
  79. foreach (var key in keys.OrderBy(x => x.Item2))
  80. {
  81. var ord = monItemGeneral.Items.FindIndex(x => x.Name == key.Item1);
  82. if (ord>=0)
  83. monItemGeneral.KeyOrdinals.Add(ord);
  84. }
  85. _generalCache.Add(type.FullName!, monItemGeneral);
  86. }
  87. }
  88. }
  89. #endregion
  90. #region *** Public Operations ***
  91. #endregion
  92. #region *** Protected Operations ***
  93. protected override void OnDisposing()
  94. {
  95. Close();
  96. _generalCache.Clear();
  97. }
  98. private void Open()
  99. {
  100. if (_udpClientGeneral != null) throw new InvalidOperationException("UDP client channel General already open. Close first.");
  101. if (_udpClientData != null) throw new InvalidOperationException("UDP client channel Data already open. Close first.");
  102. _udpClientGeneral = CreateUdpClient(_configuration.TargetUriGeneral);
  103. _udpClientData = CreateUdpClient(_configuration.TargetUriData);
  104. _timerGeneral = new Timer(OnTimerGeneral, this, _configuration.EmitGeneralInterval, _configuration.EmitGeneralInterval);
  105. _timerData = new Timer(OnTimerData, this, _configuration.EmitDataInterval, _configuration.EmitDataInterval);
  106. }
  107. private void OnTimerData(object? state)
  108. {
  109. }
  110. private void OnTimerGeneral(object? state)
  111. {
  112. if (state == null) throw new ArgumentNullException(nameof(state));
  113. var owner = (QMonClient)state;
  114. if (owner._udpClientGeneral == null) throw new InvalidOperationException("UDP client channel General not open.");
  115. try
  116. {
  117. var data = new MonGeneral()
  118. {
  119. InstanceIdentifier = owner.InstanceIdentifier,
  120. Items = new List<MonItemGeneral>()
  121. };
  122. data.Items.AddRange(owner._generalCache.Values);
  123. var dataOut = Serialize(data);
  124. _udpClientGeneral?.Send(dataOut);
  125. _log?.Log(LogSeverityEnum.Trace, $"[{InstanceIdentifier}] Sent General packet size = {dataOut.Length} bytes");
  126. }
  127. catch(Exception ex)
  128. {
  129. _log?.Log(LogSeverityEnum.Error, $"[{InstanceIdentifier}] Error sending general data", ex);
  130. }
  131. }
  132. private byte[] Serialize(MonGeneral data)
  133. {
  134. if (data == null) throw new ArgumentNullException(nameof(data));
  135. var json = _binder.SaveToString(data);
  136. return Encoding.UTF8.GetBytes(json);
  137. }
  138. private void Close()
  139. {
  140. if (_udpClientGeneral != null)
  141. {
  142. _timerGeneral?.Dispose();
  143. _udpClientGeneral.Close();
  144. _udpClientGeneral.Dispose();
  145. _udpClientGeneral = null;
  146. _timerGeneral = null;
  147. }
  148. if (_udpClientData != null)
  149. {
  150. _timerData?.Dispose();
  151. _udpClientData.Close();
  152. _udpClientData.Dispose();
  153. _udpClientData = null;
  154. _timerData = null;
  155. }
  156. }
  157. private UdpClient CreateUdpClient(Uri targetUri)
  158. {
  159. var ep = new IPEndPoint(IPAddress.Parse(targetUri.DnsSafeHost), targetUri.Port);
  160. var udpClient = new UdpClient();
  161. udpClient.Connect(ep);
  162. return udpClient;
  163. }
  164. private void SetEnabled(bool value)
  165. {
  166. if (value == _isEnabled)
  167. return;
  168. _isEnabled = value;
  169. if (_isEnabled)
  170. Open();
  171. else
  172. Close();
  173. }
  174. #endregion
  175. #region *** Nested Types ***
  176. #endregion
  177. }
  178. }