Explorar o código

finalize Receiver

Dalibor Votruba %!s(int64=2) %!d(string=hai) anos
pai
achega
dbdde61deb

+ 20 - 0
Workbench/QMonitor/qmonlib/Dependencies/Object/Dynamic/Dyo.cs

@@ -0,0 +1,20 @@
+namespace qmonlib.Dependencies.Object.Dynamic
+{
+    public class Dyo : DyoMember
+    {
+        #region *** Fields ***
+
+        #endregion
+
+        #region *** Constructors ***
+
+        public Dyo(string name) : base(null, ElementType.Root, null, name)
+        {
+        }
+        #endregion
+
+        #region *** Operations ***
+
+        #endregion
+    }
+}

+ 139 - 0
Workbench/QMonitor/qmonlib/Dependencies/Object/Dynamic/DyoMember.cs

@@ -0,0 +1,139 @@
+using System.Collections;
+using System.Text;
+
+namespace qmonlib.Dependencies.Object.Dynamic
+{
+    public class DyoMember
+    {
+         #region *** Constants ***
+
+            public const string PathSeparator = "/";
+            public const string PathRoot = ".";
+            #endregion
+
+            #region *** Properties ***
+            private long Id { get; }
+            public ElementType Type { get; }
+            private Dyo? Root { get; }
+            private DyoMember? Parent { get; }
+            public string Name { get; }
+            public object? Value { get; private set; }
+            public DyoMember[] Members => _members.ToArray();
+            #endregion
+            #region *** Fields ***
+            private static long _idCnt;
+            private IList<DyoMember> _members = new List<DyoMember>();
+            #endregion
+
+            #region *** Indexer ***
+            public DyoMember this[string name] => Get(name);
+            public DyoMember this[int ordinal] => _members.Skip(ordinal).First();
+            #endregion
+
+            #region *** Constructors ***
+            public DyoMember(Dyo? root, ElementType type, DyoMember? parent, string name, object? value = null)
+            {
+                Id = root?.GetNextId() ?? -1;
+                Type = type;
+                Parent = parent;
+                Root = root;
+                Name = name;
+                Value = value;
+            }
+            #endregion
+
+            #region *** Operations ***
+            public DyoMember Add(string name, ElementType elementType, object? value = null)
+            {
+                ThrowIfExists(name);
+                var item = new DyoMember(Root ?? (Dyo)this, elementType, this, name, value);
+                _members.Add(item);
+                return item;
+            }
+
+            public void Remove(string name)
+            {
+                var item = Get(name);
+                item.Clear();
+                _members.Remove(item);
+            }
+            public void Clear()
+            {
+                foreach (var member in _members)
+                    member.Clear();
+                _members.Clear();
+            }
+
+            public DyoMember Get(string name)
+            {
+                ThrowIfNotExists(name);
+                var item = _members.First(x => x.Name == name);
+                return item;
+            }
+
+            public void Set(string name, object? value)
+            {
+                var item = Get(name);
+                item.Value = value;
+            }
+            public void Reset()
+            {
+                foreach (var member in _members)
+                    member.Reset();
+                Value = null;
+            }
+            public bool Exists(string name, Dyo.ElementType? elementType = null)
+            {
+                if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name));
+                var exists = elementType!=null ? _members.Any(x => x.Name == name && x.Type == elementType) : _members.Any(x => x.Name == name);
+                return exists;
+            }
+            public string GetPath()
+            {
+                if (Parent == null) return Dyo.PathRoot;
+                var path = Parent.GetPath() + Dyo.PathSeparator + Name;
+                return path;
+            }
+
+            public string Dump()
+            {
+                var sb = new StringBuilder();
+                sb.Append(Name).Append(" [#").Append(Id).Append(";").Append(Type).Append("] ").Append(_members.Count).Append(" members").AppendLine();
+                sb.Append("\t").Append("Path:").Append(GetPath()).AppendLine();
+                if (Type == ElementType.Value)
+                    sb.Append("\t").Append("Value:").Append(Value == null ? "NULL" : Value.ToString()).AppendLine();
+                foreach (var member in _members)
+                    sb.Append("\t* ").Append(member.Dump());
+                return sb.ToString();
+            }
+            #endregion
+
+            #region *** Private Operations ***
+
+            private void ThrowIfNotExists(string name)
+            {
+                if (!Exists(name)) throw new Exception($"Dyo member with name '{name}' does not exist.");
+            }
+            private void ThrowIfExists(string name)
+            {
+                if (Exists(name)) throw new Exception($"Dyo member with name '{name}' already exists.");
+            }
+            private long GetNextId()
+            {
+                _idCnt++;
+                return _idCnt;
+            }
+            #endregion
+            #region *** Nested Types ***
+            public enum ElementType
+            {
+                Value,
+                Object,
+                Collection,
+                Root
+            }
+
+            #endregion
+        }
+    
+}

+ 2 - 0
Workbench/QMonitor/qmonlib/MonItemGeneral.cs

@@ -6,6 +6,8 @@ namespace qmonlib
     [Serializable]
     public class MonItemGeneral
     {
+        [JsonPropertyName("nam")]
+        public string Name { get; set; }
         [JsonPropertyName("cpt")]
         public string Caption { get; set; }
         [JsonPropertyName("dsc")]

+ 21 - 0
Workbench/QMonitor/qmonlib/MonReceiverGeneralCahedItem.cs

@@ -0,0 +1,21 @@
+using System.Net;
+
+namespace qmonlib
+{
+    public class MonReceiverGeneralCahedItem
+    {
+        public DateTime Received { get; set; }
+        public IPEndPoint Source { get; set; }
+        public MonGeneral Data { get; set; }
+
+
+
+        public MonReceiverGeneralCahedItem(DateTime received, IPEndPoint source, MonGeneral data)
+        {
+            Received = received;
+            Source = source;
+            Data = data;
+        }
+
+    }
+}

+ 25 - 8
Workbench/QMonitor/qmonlib/Program.cs

@@ -1,20 +1,37 @@
 // See https://aka.ms/new-console-template for more information
 
+
 using qmonlib;
 using Quadarax.Foundation.Core.Logging;
 
-Console.WriteLine("Hello, World!");
-
 var logger = new ConsoleLogger();
+
+var cancel = new CancellationTokenSource();
+
+new Thread(() =>
+{
+    OnStartReceiver(cancel.Token);
+
+}).Start();
 using (var cli = new QMonClient("TST", QMonClientConfiuration.CreateDefault(), logger))
 {
-    using (var rcv = new QMonReceiver(QMonReceiverConfiguration.CreateDefault(), logger, OnGeneralReceived))
-    {
-        Console.WriteLine("Press any key to close...");
-        Console.ReadKey();
-    }
+
+    Console.WriteLine("Press any key to close...");
+    Console.ReadKey();
+    cancel.Cancel();
 }
+
 void OnGeneralReceived(MonGeneral general)
 {
     Console.WriteLine($"General received: {general.InstanceIdentifier} items count {general.Items.Count}");
-}
+}
+
+void OnStartReceiver(CancellationToken cancelToken)
+{
+    using (var rcv = new QMonReceiver(QMonReceiverConfiguration.CreateDefault(), logger, OnGeneralReceived))
+    {
+        while (!cancelToken.IsCancellationRequested)
+            Thread.Sleep(100);
+    }
+    Console.WriteLine("Receiver stopped");
+}

+ 48 - 7
Workbench/QMonitor/qmonlib/QMonReceiver.cs

@@ -1,10 +1,9 @@
 using System.Collections.Concurrent;
-using System.Data;
 using System.Net;
 using System.Net.Sockets;
 using System.Text;
+using System.Text.Json;
 using Quadarax.Foundation.Core.Logging;
-using Quadarax.Foundation.Core.Object;
 
 namespace qmonlib
 {
@@ -16,13 +15,13 @@ namespace qmonlib
         protected override Uri UriData => Configuration.SourceUriData;
         protected override TimeSpan IntervalGeneral => Configuration.GeneralReceiverInterval;
         protected override TimeSpan? IntervalData => null;
-        public MonGeneral[] AvailableGeneral => _generalCache.Values.ToArray();
+        public MonGeneral[] AvailableGeneral => _generalCache.Values.Select(x=>x.Data).ToArray();
         #endregion
         #region *** Fields ***
         private GeneralDataReceivedDelegate _generalReceivedCallback;
-
-            private bool _isReceivingGeneral;
-        private IDictionary<string, MonGeneral> _generalCache = new ConcurrentDictionary<string, MonGeneral>();
+        private bool _isReceivingGeneral;
+        private CancellationTokenSource _dataReceiverCancel;
+        private IDictionary<string, MonReceiverGeneralCahedItem> _generalCache = new ConcurrentDictionary<string, MonReceiverGeneralCahedItem>();
         #endregion
         #region *** Constructors ***
         public QMonReceiver(QMonReceiverConfiguration configuration, ILogger logger, GeneralDataReceivedDelegate generalDataReceivedCallback = null) : base(configuration, logger)
@@ -36,10 +35,25 @@ namespace qmonlib
 
         protected override void OnOpen()
         {
+            var _dataReceiverCancel = new CancellationTokenSource();
+            new Thread(() =>
+            {
+                try
+                {
+                    OnThreadData(_dataReceiverCancel.Token);
+                }
+                catch (OperationCanceledException)
+                {
+                    Log(LogSeverityEnum.Info, $"Data receiver thread on {UriData} unexpected stopped");
+                }
+            }).Start();
+            Log(LogSeverityEnum.Info, $"Data receiver thread on {UriData} started");
         }
 
         protected override void OnClose()
         {
+            _dataReceiverCancel?.Cancel();
+            Log(LogSeverityEnum.Info, $"Data receiver thread on {UriData} stopped");
         }
 
         protected override void OnTimerData(object? state)
@@ -61,7 +75,7 @@ namespace qmonlib
                 Log(LogSeverityEnum.Debug,
                     $"[ReceiverGeneral] receive general data from '{remoteEndPoint}' [{general.InstanceIdentifier}] size={data.Length} bytes.");
 
-                _generalCache.TryAdd(general.InstanceIdentifier, general);
+                _generalCache.TryAdd(general.InstanceIdentifier, new MonReceiverGeneralCahedItem(DateTime.Now, remoteEndPoint, general));
                 _generalReceivedCallback?.Invoke(general);
             }
             catch (Exception e)
@@ -73,6 +87,29 @@ namespace qmonlib
                 owner._isReceivingGeneral = false;
             }
         }
+
+        private void OnThreadData(CancellationToken cancellation)
+        {
+            if (cancellation == null) throw new ArgumentNullException(nameof(cancellation));
+
+            if (cancellation.IsCancellationRequested)
+            {
+                Log(LogSeverityEnum.Debug, $"[ReceiverData] Cancellation token detected on listener '{UriData}'.");
+            }
+            try
+            {
+                if (UdpClientData.Available==0) return;
+                var remoteEndPoint = new IPEndPoint(IPAddress.Parse(this.UriData.DnsSafeHost), this.UriData.Port);
+                var data = UdpClientData.Receive(ref remoteEndPoint);
+                var jsonData = JsonDocument.Parse(Encoding.UTF8.GetString(data));
+                Log(LogSeverityEnum.Debug, $"[ReceiverData] receive monitor data from '{remoteEndPoint}' size={data.Length} bytes.");
+            }
+            catch (Exception e)
+            {
+                Log(LogSeverityEnum.Error, $"[ReceiverData] Error receiving monitor data", e);
+            }
+        }
+
         protected override UdpClient CreateUdpClient(Uri targetUri)
         {
             var udpClient = new UdpClient(targetUri.Port);
@@ -81,6 +118,10 @@ namespace qmonlib
 
         protected override void OnDisposing()
         {
+            _dataReceiverCancel?.Cancel();
+            _dataReceiverCancel?.Dispose();
+            _dataReceiverCancel = null;
+            base.OnDisposing();
         }
         #endregion
     }

+ 99 - 0
Workbench/QMonitor/qmonlib/processServer.json

@@ -0,0 +1,99 @@
+{
+	"api-base-url": "http://localhost:5000/api/",
+	"api-user": "Process",
+	"api-pwd": "SmRAd1avKA",
+	"api-magic": "SHARE",
+	"api-timeout": "00:10:00",
+	"System": {
+		"mode": "Proxy",
+		"identification": "DevNode#1",
+		"preferred-interface": "auto",
+		"pool-pull-documents": 4,
+		"pool-pull-interval": "00:01:00",
+		"pool-path-base": "D:\\BO.PS",
+		"pool-path-pending": ".pending",
+		"pool-path-working": ".working",
+		"pool-path-done": ".done",
+		"pool-path-fail": ".fail",
+		"pool-retention": {
+			"enabled": true,
+			"retention-": "24:00:00",
+			"size": 1000000000,
+			"items": 100
+		},
+		"status-monitoring": {
+			"enabled": true,
+			"file": "{CD}\\status.csv",
+			"monitoring-interval": "00:00:10"
+		},
+
+		"scenario-path-base": "{CD}\\Scenarios",
+    "scenario-parallels": 2,
+		"Scenarios": [
+			{
+				"name": "test",
+				"accept-filters": [
+					{
+						"code": "profile",
+						"value": "test"
+					}
+				],
+				"cmd": "scenario-dummy.cmd",
+				"args": "{filenames} {billingplan}",
+				"timeout-interval": "01:00:00",
+				"exitcode-succ": 0,
+				"exitcode-fail": 1
+			}
+		],
+		"Proxy" : {
+			"Process": {
+				"Succ": [
+					true,
+					false
+				],
+        "Output": [
+          "result.txt"
+        ]
+			},
+			"App": {
+				"default-documents-count": 4,
+        "max-documents-count": 20,
+				"default-artifacts-count": 2,
+				"Extension": [
+					".cad",
+					".txt",
+					".catia"
+				],
+				"NamePrefix": [
+					"object",
+					"wing",
+					"holo"
+				],
+				"PresetCreditCost": [
+					1,
+					2,
+					3
+				],
+				"PresetWatermark": [
+					true,
+					false
+				],
+				"PresetQuality": [
+					0,
+					1,
+					2,
+					3
+				],
+				"PresetProcessProfile": [
+					"TEST",
+					"HIRES",
+					"LOWRES"
+				],
+				"PresetTest": [
+					true,
+					false
+				]
+			} 
+    } 
+	}
+}

+ 9 - 0
Workbench/QMonitor/qmonlib/qmonlib.csproj

@@ -11,4 +11,13 @@
     <PackageReference Include="System.IO.Abstractions" Version="19.2.69" />
   </ItemGroup>
 
+  <ItemGroup>
+    <None Update="processServer.json">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="testjson.json">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+  </ItemGroup>
+
 </Project>

+ 22 - 0
Workbench/QMonitor/qmonlib/testjson.json

@@ -0,0 +1,22 @@
+{
+  "atr1": "val1",
+  "atrbool": true,
+  "colstr": [
+    "colstrval1",
+    "colstrval2"
+  ],
+  "colbool": [
+    true,
+    false
+  ],
+  "colobj": [
+    {
+      "obja1": "obj",
+      "abja2": true
+    },
+    {
+      "obja1": "obj2",
+      "abja2": false
+    }
+  ]
+}