MonitorCommand.cs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. using System.Globalization;
  2. using System.Runtime.InteropServices.JavaScript;
  3. using System.Text;
  4. using System.Text.Json;
  5. using Quadarax.Foundation.Core.Data;
  6. using Quadarax.Foundation.Core.QConsole;
  7. using Quadarax.Foundation.Core.QConsole.Argument;
  8. using Quadarax.Foundation.Core.QConsole.Attributes;
  9. using Quadarax.Foundation.Core.QConsole.Value;
  10. using Quadarax.Foundation.Core.QMonitor.Interfaces;
  11. using Quadarax.Foundation.Core.Value.Extensions;
  12. using Result = Quadarax.Foundation.Core.Value.Result;
  13. namespace Quadarax.Foundation.Core.QMonitor.Console.Commands
  14. {
  15. [CommandDefinition]
  16. internal class MonitorCommand : BaseCommand
  17. {
  18. #region *** Constants ***
  19. private const string CS_CMD_MONITOR_NAME = "monitor";
  20. private const string CS_CMD_MONITOR_DESC = "Monitor specific single channel";
  21. protected const string CS_ARG_NAME_IID = "iid";
  22. private const string CS_ARG_HINT_IID = "<instance_identifier>";
  23. private const string CS_ARG_DESC_IID = "Specify instance identifier to listen from.";
  24. protected const string CS_ARG_NAME_CHANNEL = "channel";
  25. private const string CS_ARG_HINT_CHANNEL = "<chennel>";
  26. private const string CS_ARG_DESC_CHANNEL = "Specify full channel name to monitor.";
  27. protected const string CS_ARG_NAME_REFRESH = "refresh";
  28. private const string CS_ARG_HINT_REFRESH = "<refresh_interval>";
  29. private const string CS_ARG_DESC_REFRESH = "Specify receiver refresh interval to detect changes. Default is 00:00:05.";
  30. protected const string CS_ARG_NAME_GENFILE = "genfile";
  31. private const string CS_ARG_HINT_GENFILE = "<general_file>";
  32. private const string CS_ARG_DESC_GENFILE = "Use general metadata from json file during initialization (no needs to wait to receive).";
  33. protected const string CS_ARG_NAME_REWIND = "rewind";
  34. private const string CS_ARG_HINT_REWIND = "<is_rewind>";
  35. private const string CS_ARG_DESC_REWIND = "Flag defines if rewind to first available cached data (may live when no cached data), otherwise wait for new data.";
  36. #endregion
  37. #region *** Properties ***
  38. public override string Name => CS_CMD_MONITOR_NAME;
  39. public override string Description => CS_CMD_MONITOR_DESC;
  40. private string InstanceIdentifier { get; set; }
  41. private string ChannelName { get; set; }
  42. private TimeSpan RefreshInterval { get; set; }
  43. private string GeneralFile { get; set; }
  44. private bool IsRewind { get; set; }
  45. #endregion
  46. #region *** Private fields ***
  47. private long _dumpCnt;
  48. private MonData? _lastData;
  49. private IDictionary<string, MonData> _lastDataCollection = new Dictionary<string, MonData>();
  50. #endregion
  51. #region *** Constructor ***
  52. public MonitorCommand(Engine engine) : base(engine)
  53. {
  54. }
  55. #endregion
  56. #region *** Execute ***
  57. protected override Result OnExecute()
  58. {
  59. WriteInfo($"Refresh interval is set to {RefreshInterval}");
  60. WriteInfo($"Waiting for channel definition '{InstanceIdentifier}' and channel '{ChannelName}'...");
  61. using (var hnd = Receiver.CreateHandler(InstanceIdentifier, ChannelName, RefreshInterval,GeneralFile, true))
  62. {
  63. hnd.ReceiverHandlerStateChanged += OnReceiverHandlerStateChanged;
  64. hnd.ReceiverHandlerDataChanged += OnReceiverHandlerDataChanged;
  65. if (IsRewind)
  66. {
  67. WriteInfo("Rewind to first available cached data.");
  68. hnd.Rewind(isBackward:true);
  69. hnd.Play(false);
  70. }
  71. else
  72. {
  73. hnd.Play(true);
  74. }
  75. WriteCaption("To close receiver press any key ...");
  76. System.Console.ReadKey();
  77. }
  78. return new Result();
  79. }
  80. #endregion
  81. #region *** Private Operations ***
  82. protected override void OnInitialize()
  83. {
  84. base.OnInitialize();
  85. InstanceIdentifier = GetArgumentValueOrDefault<string>(CS_ARG_NAME_IID);
  86. ChannelName = GetArgumentValueOrDefault<string>(CS_ARG_NAME_CHANNEL);
  87. RefreshInterval = GetArgumentValueOrDefault<TimeSpan>(CS_ARG_NAME_REFRESH);
  88. GeneralFile = GetArgumentValueOrDefault<string>(CS_ARG_NAME_GENFILE);
  89. IsRewind = GetArgumentValueOrDefault<bool>(CS_ARG_NAME_REWIND);
  90. }
  91. protected override IEnumerable<AbstractArgument> OnSetupArguments()
  92. {
  93. var list = base.OnSetupArguments().ToList();
  94. list.Add(new NamedArgument(CS_ARG_NAME_IID, CS_ARG_HINT_IID, CS_ARG_DESC_IID, TypeValuesEnum.String,string.Empty,true));
  95. list.Add(new NamedArgument(CS_ARG_NAME_CHANNEL, CS_ARG_HINT_CHANNEL, CS_ARG_DESC_CHANNEL, TypeValuesEnum.String,string.Empty,true));
  96. list.Add(new NamedArgument(CS_ARG_NAME_REFRESH, CS_ARG_HINT_REFRESH, CS_ARG_DESC_REFRESH, TypeValuesEnum.TimeSpan,TimeSpan.FromSeconds(5).ToString(),false));
  97. list.Add(new NamedArgument(CS_ARG_NAME_GENFILE, CS_ARG_HINT_GENFILE, CS_ARG_DESC_GENFILE, TypeValuesEnum.String, string.Empty, false));
  98. list.Add(new FlagArgument(CS_ARG_NAME_REWIND, CS_ARG_HINT_REWIND, CS_ARG_DESC_REWIND, false));
  99. return list;
  100. }
  101. private void OnReceiverHandlerDataChanged(IReceiverHandler sender, MonData newData)
  102. {
  103. RenderData(sender.Descriptor, newData);
  104. }
  105. private void OnReceiverHandlerStateChanged(IReceiverHandler sender, ReceiverHandlerStateEnum state)
  106. {
  107. WriteInfo($"! Receiver state change to {sender.State.ToString().ToUpper()}");
  108. }
  109. private void RenderData(MonItemGeneral descriptor, MonData data)
  110. {
  111. var firstLine = $"*** Dump [{_dumpCnt}] {descriptor.ViewType} * {descriptor.Caption} ***";
  112. WriteInfo(firstLine);
  113. WriteCaption($"Timestamp: {DateTime.FromFileTimeUtc(data.TimestampFtUtc)} ({data.TimestampFtUtc})");
  114. WriteCaption($"Name: {data.Name}");
  115. WriteInfo(new('-', firstLine.Length));
  116. var diff = _lastData?.Diff(data);
  117. if (descriptor.ViewType == MonItemGeneral.MonViewType.Item)
  118. {
  119. //item view
  120. foreach (var item in descriptor.Items.OrderBy(x=>x.Order))
  121. {
  122. var sb = new StringBuilder();
  123. if (diff != null)
  124. {
  125. if (diff.ContainsKey(item.Name)) sb.Append("[*] ");
  126. }
  127. sb.Append(string.IsNullOrEmpty(item.Label) ? item.Name : item.Label).Append(" : ");
  128. var properties = ParseProperties(JsonDocument.Parse(data.Data).RootElement);
  129. var arg = properties.FirstOrDefault(x => string.Equals(x.Name, item.Name, StringComparison.InvariantCultureIgnoreCase));
  130. sb.Append(arg != null ? arg.Value : "N/A");
  131. WriteInfo(sb.ToString());
  132. }
  133. }
  134. WriteInfo(new('-', firstLine.Length));
  135. _lastData = data;
  136. _dumpCnt++;
  137. }
  138. private TypedArgument[] ParseProperties(JsonElement element)
  139. {
  140. var result = new List<TypedArgument>();
  141. foreach (var property in element.EnumerateObject())
  142. {
  143. if (property.Value.ValueKind.In(JsonValueKind.False, JsonValueKind.True, JsonValueKind.Number,
  144. JsonValueKind.String))
  145. {
  146. TypedArgument? arg = null;
  147. if (property.Value.ValueKind.In(JsonValueKind.False, JsonValueKind.True))
  148. {
  149. arg = new TypedArgument(property.Name, property.Value.GetBoolean());
  150. }
  151. else if (property.Value.ValueKind == JsonValueKind.Null)
  152. {
  153. result.Add(new TypedArgument(property.Name,null, typeof(string)));
  154. }
  155. else if (property.Value.ValueKind == JsonValueKind.Number)
  156. {
  157. result.Add(new TypedArgument(property.Name, property.Value.GetDecimal()));
  158. }
  159. else if (property.Value.ValueKind == JsonValueKind.String)
  160. {
  161. result.Add(new TypedArgument(property.Name, property.Value.GetString()));
  162. }
  163. if (arg != null)
  164. result.Add(arg);
  165. }
  166. }
  167. return result.ToArray();
  168. }
  169. #endregion
  170. }
  171. }