Merge branch 'release/TestFluitek_01'
This commit is contained in:
@@ -80,7 +80,7 @@ namespace IOB_UT_NEXT.Config.Base
|
||||
/// <summary>
|
||||
/// Soglia massima errori prima della disconnessione automatica in check
|
||||
/// </summary>
|
||||
public int MaxErroriCheck { get; set; } = 100;
|
||||
public int MaxErroriCheck { get; set; } = 50;
|
||||
|
||||
/// <summary>
|
||||
/// Max tentativi ping permessi (default: 5)
|
||||
@@ -107,6 +107,11 @@ namespace IOB_UT_NEXT.Config.Base
|
||||
/// </summary>
|
||||
public bool EnabRedisQue { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Forza esecuzione WorkLoopMachine (verso macchina PLC/CNC) in SingleThread (vs ThreadPool)
|
||||
/// </summary>
|
||||
public bool MachWLoopSingleThread { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Versione software IOB
|
||||
/// </summary>
|
||||
|
||||
@@ -125,6 +125,7 @@ namespace IOB_UT_NEXT.Config
|
||||
Customer = fIni.ReadString("TAGS", "Customer", "EgalWare"),
|
||||
EnabelPodlManFull = bool.Parse(fIni.ReadString("OPTPAR", "EnabelPodlManFull", "false")),
|
||||
EnabRedisQue = bool.Parse(fIni.ReadString("IOB", "EnableRedisQueue", "true")),
|
||||
MachWLoopSingleThread = bool.Parse(fIni.ReadString("OPTPAR", "MachSingleThread", "false")),
|
||||
MaxErroriCheck = fIni.ReadInteger("OPTPAR", "MAX_ERR_CHECK", maxErrCheck),
|
||||
MaxPingRetry = fIni.ReadInteger("OPTPAR", "MAX_PING_RETRY", 5),
|
||||
MinDeltaSec = fIni.ReadInteger("IOB", "MinDeltaSec", 6),
|
||||
@@ -140,11 +141,11 @@ namespace IOB_UT_NEXT.Config
|
||||
exclOptPar.Add("DELAY_READ_PZ_COUNT");
|
||||
exclOptPar.Add("DISABLE_SEND_WDST");
|
||||
exclOptPar.Add("EnabelPodlManFull");
|
||||
exclOptPar.Add("MachSingleThread");
|
||||
exclOptPar.Add("MAX_ERR_CHECK");
|
||||
exclOptPar.Add("MAX_PING_RETRY");
|
||||
exclOptPar.Add("SEND_ALARM_RESET");
|
||||
exclOptPar.Add("SEND_MACHINE_CONF");
|
||||
exclOptPar.Add("timerIntMs");
|
||||
exclOptPar.Add("WAIT_REC_MSEC");
|
||||
exclOptPar.Add("WATCHDOG_PERIOD");
|
||||
|
||||
@@ -155,6 +156,7 @@ namespace IOB_UT_NEXT.Config
|
||||
{
|
||||
int.TryParse(rawTimer, out uiTimer);
|
||||
}
|
||||
exclOptPar.Add("timerIntMs");
|
||||
// ultimo controllo: timer deve essere compreso tra 10 a 500 x evitare task troppo veloci o lenti...
|
||||
uiTimer = uiTimer < 10 ? 10 : uiTimer;
|
||||
uiTimer = uiTimer > 500 ? 500 : uiTimer;
|
||||
@@ -272,7 +274,7 @@ namespace IOB_UT_NEXT.Config
|
||||
PzTotMode = fIni.ReadString("OPTPAR", "PZGTOT_MODE", ""),
|
||||
ReadErrorMax = fIni.ReadInteger("OPTPAR", "READ_ERROR_MAX", 20),
|
||||
ReadErrorSleepTime = fIni.ReadInteger("OPTPAR", "READ_ERROR_SLEEP_TIME", 20000),
|
||||
StartupVetoQueueIN = fIni.ReadInteger("OPTPAR", "VETO_QUEUE_IN", 10),
|
||||
StartupVetoQueueIN = fIni.ReadInteger("OPTPAR", "VETO_QUEUE_IN", 6),
|
||||
Vendor = fIni.ReadString("MACHINE", "VENDOR", "STEAMWARE"),
|
||||
Connect = new ConnectionDto()
|
||||
{
|
||||
|
||||
@@ -200,8 +200,11 @@
|
||||
<Compile Include="iobRefreshedEventArgs.cs" />
|
||||
<Compile Include="IobWinStatus.cs" />
|
||||
<Compile Include="Iob\BaseObj.cs" />
|
||||
<Compile Include="JobTask2Exe.cs" />
|
||||
<Compile Include="MeasureUtils.cs" />
|
||||
<Compile Include="plcMemMapExt.cs" />
|
||||
<Compile Include="TimerMan.cs" />
|
||||
<Compile Include="SingleThreadTaskScheduler.cs" />
|
||||
<Compile Include="TCMan.cs" />
|
||||
<Compile Include="TimeUtils.cs" />
|
||||
<Compile Include="ToMapo.cs" />
|
||||
|
||||
@@ -238,6 +238,16 @@ namespace IOB_UT_NEXT.Iob
|
||||
/// </summary>
|
||||
public DataQueue QueueRawTransf;// = new DataQueue("000", "QueueRawTransf", false);
|
||||
|
||||
/// <summary>
|
||||
/// Coda delle richieste dal server (Task2Exe)
|
||||
/// </summary>
|
||||
public DataQueue QueueSrvReq;
|
||||
|
||||
/// <summary>
|
||||
/// Coda delle risposte al server (Task2Exe)
|
||||
/// </summary>
|
||||
public DataQueue QueueSrvResp;
|
||||
|
||||
/// <summary>
|
||||
/// Coda valori LOG UTENTE (da non sottocampionare come samples)...
|
||||
/// </summary>
|
||||
@@ -621,16 +631,18 @@ namespace IOB_UT_NEXT.Iob
|
||||
{
|
||||
string codIob = IOBConfFull.General.FilenameIOB;
|
||||
bool useRedis = IOBConfFull.General.EnabRedisQue;
|
||||
QueueAlarm = new DataQueue(codIob, "QueueAlarm", false, redisMan);
|
||||
// valutare se portare di nuovo in redis...
|
||||
QueueIN = new DataQueue(codIob, "QueueIN", useRedis, redisMan);
|
||||
QueueSrvResp = new DataQueue(codIob, "QueueServResp", useRedis, redisMan);
|
||||
// fix a NON redis
|
||||
QueueAlarm = new DataQueue(codIob, "QueueAlarm", false, redisMan);
|
||||
QueueFLog = new DataQueue(codIob, "QueueFLog", false, redisMan);
|
||||
//QueueFLog = new DataQueue(codIob, "QueueFLog", useRedis, redisMan);
|
||||
QueueMessages = new DataQueue(codIob, "QueueMessages", false, redisMan);
|
||||
QueueRawTransf = new DataQueue(codIob, "QueueRawTransf", false, redisMan);
|
||||
QueueULog = new DataQueue(codIob, "QueueULog", false, redisMan);
|
||||
QueuePing = new DataQueue(codIob, "QueuePing", false, redisMan);
|
||||
QueueRawTransf = new DataQueue(codIob, "QueueRawTransf", false, redisMan);
|
||||
QueueSrvReq = new DataQueue(codIob, "QueueServReq", false, redisMan);
|
||||
QueueULog = new DataQueue(codIob, "QueueULog", false, redisMan);
|
||||
}
|
||||
|
||||
#endregion Protected Methods
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IOB_UT_NEXT
|
||||
{
|
||||
/// <summary>
|
||||
/// Classe per gestione Job Task2Exe x una macchina
|
||||
/// </summary>
|
||||
public class JobTaskData
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public JobTaskData(string codTav, string rawData)
|
||||
{
|
||||
CodTav = codTav;
|
||||
RawData = rawData;
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#if false
|
||||
public JobTaskData(string codTav, Dictionary<string, string> newDict)
|
||||
{
|
||||
CodTav = codTav;
|
||||
RawData = JsonConvert.SerializeObject(newDict);
|
||||
}
|
||||
#endif
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Codice tavola (empty = main)
|
||||
/// </summary>
|
||||
public string CodTav { get; private set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Dizionario in formato raw (da deserializzare
|
||||
/// </summary>
|
||||
public string RawData { get; private set; } = "";
|
||||
|
||||
#endregion Public Properties
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Dizionario dei Task associati
|
||||
/// </summary>
|
||||
public static Dictionary<string, string> TaskDict(string rawData)
|
||||
{
|
||||
var answ = new Dictionary<string, string>();
|
||||
if (!string.IsNullOrEmpty(rawData))
|
||||
{
|
||||
answ = JsonConvert.DeserializeObject<Dictionary<string, string>>(rawData) ?? new Dictionary<string, string>();
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class SingleThreadTaskScheduler : TaskScheduler, IDisposable
|
||||
{
|
||||
private readonly BlockingCollection<Task> _tasks = new BlockingCollection<Task>();
|
||||
private readonly Thread _thread;
|
||||
public SynchronizationContext SyncContext { get; private set; }
|
||||
|
||||
public SingleThreadTaskScheduler(string threadName)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<bool>();
|
||||
_thread = new Thread(() =>
|
||||
{
|
||||
// Creiamo il contesto di sincronizzazione personalizzato
|
||||
SyncContext = new SingleThreadSynchronizationContext(this);
|
||||
SynchronizationContext.SetSynchronizationContext(SyncContext);
|
||||
tcs.SetResult(true);
|
||||
|
||||
foreach (var task in _tasks.GetConsumingEnumerable())
|
||||
{
|
||||
base.TryExecuteTask(task);
|
||||
}
|
||||
})
|
||||
{ IsBackground = true, Name = threadName };
|
||||
_thread.Start();
|
||||
tcs.Task.Wait(); // Aspetta che il thread sia pronto col suo contesto
|
||||
}
|
||||
|
||||
private class SingleThreadSynchronizationContext : SynchronizationContext
|
||||
{
|
||||
private readonly SingleThreadTaskScheduler _sch;
|
||||
public SingleThreadSynchronizationContext(SingleThreadTaskScheduler sch) => _sch = sch;
|
||||
public override void Post(SendOrPostCallback d, object state)
|
||||
=> Task.Factory.StartNew(() => d(state), CancellationToken.None, TaskCreationOptions.None, _sch);
|
||||
}
|
||||
|
||||
protected override void QueueTask(Task task) => _tasks.Add(task);
|
||||
protected override bool TryExecuteTaskInline(Task task, bool prev)
|
||||
=> Thread.CurrentThread == _thread && base.TryExecuteTask(task);
|
||||
protected override IEnumerable<Task> GetScheduledTasks() => _tasks;
|
||||
public override int MaximumConcurrencyLevel => 1;
|
||||
public void Dispose() => _tasks.CompleteAdding();
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IOB_UT_NEXT
|
||||
{
|
||||
/// <summary>
|
||||
/// Classe di gestione info Timer per esecuzione ordinata processi secondo priorità
|
||||
/// </summary>
|
||||
public class TimerMan
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Init classe timer
|
||||
/// </summary>
|
||||
/// <param name="contesto"></param>
|
||||
public TimerMan(ContextType contesto)
|
||||
{
|
||||
Contesto = contesto;
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Enums
|
||||
|
||||
/// <summary>
|
||||
/// Tipologia contesto timer
|
||||
/// </summary>
|
||||
public enum ContextType
|
||||
{
|
||||
Machine = 0,
|
||||
Server
|
||||
}
|
||||
|
||||
#endregion Public Enums
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Contesto del timer
|
||||
/// </summary>
|
||||
public ContextType Contesto { get; private set; } = ContextType.Machine;
|
||||
|
||||
/// <summary>
|
||||
/// Contatore chiamate timers x debug timing
|
||||
/// </summary>
|
||||
public Dictionary<gatherCycle, int> CycleCount { get; set; } = new Dictionary<gatherCycle, int>();
|
||||
|
||||
/// <summary>
|
||||
/// Contatore durata exec x debug timing
|
||||
/// </summary>
|
||||
public Dictionary<gatherCycle, double> CycleElaps { get; set; } = new Dictionary<gatherCycle, double>();
|
||||
|
||||
/// <summary>
|
||||
/// Dizionario scadenza timers interni x esecuzione dei vari task a differente frequenza di chiamata
|
||||
/// </summary>
|
||||
public Dictionary<gatherCycle, DateTime> Veto { get; set; } = new Dictionary<gatherCycle, DateTime>();
|
||||
|
||||
#endregion Public Properties
|
||||
}
|
||||
}
|
||||
@@ -351,36 +351,6 @@ namespace IOB_UT_NEXT
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if false
|
||||
/// <summary>
|
||||
/// Versione async della chiamata ad URL
|
||||
/// </summary>
|
||||
/// <param name="URL"></param>
|
||||
/// <returns></returns>
|
||||
public static string callUrlAsync(string URL)
|
||||
{
|
||||
// Chiamo in modalità task...
|
||||
var resp = Task.Run(() => callUrl(URL));
|
||||
resp.Wait();
|
||||
return resp.Result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Versione async della chiamata ad URL
|
||||
/// </summary>
|
||||
/// <param name="URL"></param>
|
||||
/// <param name="payload"></param>
|
||||
/// <returns></returns>
|
||||
public static string callUrlAsync(string URL, string payload)
|
||||
{
|
||||
// Chiamo in modalità task...
|
||||
var resp = Task.Run(() => callUrl(URL, payload));
|
||||
resp.Wait();
|
||||
return resp.Result;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Effettua chiamata URL IMMEDIATAMENTE e restituisce risultato
|
||||
/// </summary>
|
||||
@@ -435,7 +405,7 @@ namespace IOB_UT_NEXT
|
||||
clientPayload = new WebClientWT();
|
||||
}
|
||||
clientPayload.Headers.Add("user-agent", $"{CRS("appName")}-PAYLOAD");
|
||||
clientPayload.Headers.Add("Content-Type", "application/json");
|
||||
clientPayload.Headers.Add("Content-ContextType", "application/json");
|
||||
try
|
||||
{
|
||||
// problema certificati locali...
|
||||
@@ -553,20 +523,6 @@ namespace IOB_UT_NEXT
|
||||
public static string CRS(string key)
|
||||
{
|
||||
return ConfigurationManager.AppSettings[key] ?? string.Empty;
|
||||
#if false
|
||||
string answ = "";
|
||||
if (ConfigurationManager.AppSettings.Count > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
answ = ConfigurationManager.AppSettings[key].ToString();
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
}
|
||||
return answ;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<add key="urlCallTOut" value="9999" />
|
||||
<add key="urlRandWait" value="200" />
|
||||
<!-- ciclo corto x invio a server: ms -->
|
||||
<add key="timerIntMs" value="10" />
|
||||
<add key="timerIntMs" value="50" />
|
||||
<add key="fastCount" value="20" />
|
||||
<add key="normCount" value="200" />
|
||||
<add key="slowCount" value="300" />
|
||||
@@ -73,7 +73,7 @@
|
||||
<add key="windowCanMax" value="true" />
|
||||
<add key="trayClose" value="true" />
|
||||
<add key="autoSaveSec" value="60" />
|
||||
<add key="waitRecMSec" value="60000" />
|
||||
<add key="waitRecMSec" value="20000" />
|
||||
<add key="testCharSep" value="|" />
|
||||
<add key="delayShowLogMs" value="1000" />
|
||||
<add key="vetoSeconds" value="5" />
|
||||
|
||||
@@ -86,6 +86,12 @@ DISABLE_SEND_WDST=TRUE
|
||||
; bit da scrivere come trace ad ogni check
|
||||
;MEM_2_TRACE=|BIT3|BIT4|BIT5|
|
||||
PARAM_CONF=3028.json
|
||||
; test timing & errori
|
||||
timerIntMs=30
|
||||
MachSingleThread=true
|
||||
MAX_ERR_CHECK=10
|
||||
;WAIT_REC_MSEC=15000
|
||||
|
||||
|
||||
[BRANCH]
|
||||
NAME=master
|
||||
|
||||
@@ -88,6 +88,10 @@ ENABLE_SEND_PZC_BLOCK=TRUE
|
||||
MIN_SEND_PZC_BLOCK=0
|
||||
MAX_SEND_PZC_BLOCK=100
|
||||
DISABLE_SEND_WDST=TRUE
|
||||
; test timing & errori
|
||||
;timerIntMs=40
|
||||
;MachSingleThread=true
|
||||
MAX_ERR_CHECK=10
|
||||
; bit da scrivere come trace ad ogni check
|
||||
;MEM_2_TRACE=|BIT3|BIT4|BIT5|
|
||||
PARAM_CONF=3029.json
|
||||
|
||||
@@ -71,6 +71,7 @@ MIN_SEND_PZC_BLOCK=0
|
||||
MAX_SEND_PZC_BLOCK=100
|
||||
; Disabilito conteggio Pezzi come richiesto
|
||||
DISABLE_PZCOUNT=TRUE
|
||||
DISABLE_SEND_WDST=TRUE
|
||||
|
||||
[BRANCH]
|
||||
NAME=master
|
||||
|
||||
@@ -26,10 +26,12 @@ CLI_INST=SteamWareSim
|
||||
;STARTLIST=3004
|
||||
;STARTLIST=3002
|
||||
;STARTLIST=GT575
|
||||
;STARTLIST=3029
|
||||
;STARTLIST=3004,3005
|
||||
;STARTLIST=SIMUL_01
|
||||
;STARTLIST=FOV106
|
||||
STARTLIST=FOV107
|
||||
;STARTLIST=3028
|
||||
;STARTLIST=3029
|
||||
|
||||
|
||||
MAXCNC=10
|
||||
@@ -162,6 +162,7 @@
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="DATA\CONF\3001.ini" />
|
||||
<None Include="DATA\CONF\3001.json" />
|
||||
<None Include="DATA\CONF\3002.ini">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
@@ -177,6 +178,7 @@
|
||||
<None Include="DATA\CONF\3021.ini">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="DATA\CONF\3021.json" />
|
||||
<None Include="DATA\CONF\3025.ini">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
@@ -231,7 +233,9 @@
|
||||
<None Include="DATA\CONF\FOV100.ini" />
|
||||
<None Include="DATA\CONF\FOV101.ini" />
|
||||
<None Include="DATA\CONF\FOV102.ini" />
|
||||
<None Include="DATA\CONF\FOV106.ini" />
|
||||
<None Include="DATA\CONF\FOV106.ini">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="DATA\CONF\FOV107.ini">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
|
||||
+591
-421
File diff suppressed because it is too large
Load Diff
@@ -48,6 +48,7 @@ REM ROBOCOPY %2 \\192.168.1.133\Steamware\IOB-WIN-FANUC-DEB /MIR
|
||||
REM ROBOCOPY %2 \\10.51.90.10\Steamware\IOB-WIN-FANUC-DEB /MIR
|
||||
REM ROBOCOPY %2 \\10.51.90.14\Steamware\IOB-WIN-FANUC-DEB /MIR
|
||||
REM ROBOCOPY %2 \\10.51.90.13\Steamware\IOB-WIN-FANUC-DEB /MIR
|
||||
|
||||
ROBOCOPY %2 \\10.51.90.15\Steamware\IOB-WIN-FANUC-DEB /MIR
|
||||
REM ROBOCOPY %2 \\10.51.90.9\Steamware\IOB-WIN-FANUC-DEB /MIR
|
||||
|
||||
|
||||
+680
-107
File diff suppressed because it is too large
Load Diff
@@ -32,6 +32,11 @@ namespace IOB_WIN_FORM.Iob
|
||||
{
|
||||
#region Protected Fields
|
||||
|
||||
/// <summary>
|
||||
/// Variabile numero errori vari (in lettura) --> se supera soglia maxErroriCheck --> disconnette
|
||||
/// </summary>
|
||||
protected static int numErroriCheck = 0;
|
||||
|
||||
protected bool _connOk = false;
|
||||
|
||||
/// <summary>
|
||||
@@ -59,13 +64,6 @@ namespace IOB_WIN_FORM.Iob
|
||||
/// </summary>
|
||||
protected int B_output;
|
||||
|
||||
#if false
|
||||
/// <summary>
|
||||
/// Ultimo valore B_output inviato
|
||||
/// </summary>
|
||||
protected int B_output_sent = -1;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Vettore 32 BIT valori precedenti
|
||||
/// </summary>
|
||||
@@ -308,11 +306,6 @@ namespace IOB_WIN_FORM.Iob
|
||||
/// </summary>
|
||||
protected bool numArtCharTrim = false;
|
||||
|
||||
/// <summary>
|
||||
/// Variabile numero errori vari (in lettura) --> se supera soglia maxErroriCheck --> disconnette
|
||||
/// </summary>
|
||||
protected int numErroriCheck = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Timeout x ping al server
|
||||
/// </summary>
|
||||
@@ -678,16 +671,6 @@ namespace IOB_WIN_FORM.Iob
|
||||
}
|
||||
}
|
||||
|
||||
protected bool queueInEnabCurr
|
||||
{
|
||||
get => qInEnabCurr;
|
||||
set
|
||||
{
|
||||
qInEnabCurr = value;
|
||||
lgInfo($"SET queueInEnabCurr: {value} | {DateTime.Now:HHmmss}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Definizioni x replace in file ricette
|
||||
/// </summary>
|
||||
@@ -1026,13 +1009,6 @@ namespace IOB_WIN_FORM.Iob
|
||||
{
|
||||
get => $@"{urlCommandIob("remTask2Exe")}?taskName=";
|
||||
}
|
||||
/// <summary>
|
||||
/// URL per richiamo task da eseguire...
|
||||
/// </summary>
|
||||
protected string urlRemTask2ExeTav(string codTav)
|
||||
{
|
||||
return $@"{urlCommandIob("remTask2Exe")}|{codTav}?taskName=";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// URL per salvataggio dati PARAMETRI IOB...
|
||||
@@ -1139,31 +1115,6 @@ namespace IOB_WIN_FORM.Iob
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Verifico i dynData x validità:
|
||||
/// - siano almeno 1
|
||||
/// - NON siano tutti identici
|
||||
/// </summary>
|
||||
/// <param name="currDynData"></param>
|
||||
/// <returns></returns>
|
||||
protected bool checkValidDynData(Dictionary<string, string> currDynData)
|
||||
{
|
||||
bool answ = false;
|
||||
// conto num valori
|
||||
int numVal = currDynData.Count;
|
||||
bool dataPresent = numVal > 0;
|
||||
if (dataPresent)
|
||||
{
|
||||
// prendo il primo valore..
|
||||
string firstVal = currDynData.FirstOrDefault().Value;
|
||||
// conto val uguali al primo
|
||||
int numEq = currDynData.Where(x => x.Value == firstVal).Count();
|
||||
// se solo 1 o almeno 1 è diverso è ok
|
||||
answ = numVal == 1 || (numVal > numEq);
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodifica file MAP (caso <paramref name="ByteNum" />.bit)
|
||||
/// </summary>
|
||||
@@ -1226,6 +1177,26 @@ namespace IOB_WIN_FORM.Iob
|
||||
}
|
||||
}
|
||||
|
||||
protected static long GetObjectSize(object genObj, bool isSerializable)
|
||||
{
|
||||
long result = 0;
|
||||
if (isSerializable)
|
||||
{
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
var formatter = new BinaryFormatter();
|
||||
formatter.Serialize(stream, genObj);
|
||||
result = stream.Length;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string rawVal = System.Text.Json.JsonSerializer.Serialize(genObj, options);
|
||||
result = rawVal.Length;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodifica valore della coda IN nel formato hasVeto[0]=dtEve hasVeto[1]=valore hasVeto[2]=counter
|
||||
/// </summary>
|
||||
@@ -1246,6 +1217,36 @@ namespace IOB_WIN_FORM.Iob
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Accodamento richieste server
|
||||
/// </summary>
|
||||
/// <param name="codTav"></param>
|
||||
/// <param name="newReq"></param>
|
||||
protected void accodaServReq(string codTav, string newReq)
|
||||
{
|
||||
JobTaskData jobTask = new JobTaskData(codTav, newReq);
|
||||
// accodo richiesta serializzata
|
||||
string serVal = JsonConvert.SerializeObject(jobTask);
|
||||
QueueSrvReq.Enqueue(serVal);
|
||||
// loggo!
|
||||
lgDebug($"[QUEUE] | QueueSrvReq len: {QueueSrvReq.Count}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Accodamento risposte per il server
|
||||
/// </summary>
|
||||
/// <param name="codTav"></param>
|
||||
/// <param name="rawData"></param>
|
||||
protected void accodaServResp(string codTav, string rawData)
|
||||
{
|
||||
JobTaskData jobTask = new JobTaskData(codTav, rawData);
|
||||
// accodo richiesta serializzata
|
||||
string serVal = JsonConvert.SerializeObject(jobTask);
|
||||
QueueSrvResp.Enqueue(serVal);
|
||||
// loggo!
|
||||
lgDebug($"[QUEUE] | QueueSrvResp len: {QueueSrvResp.Count}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Classe di base implementazione traduzione di una LUT da memoria come valore BIT a valore
|
||||
/// esplicito x FLog
|
||||
@@ -1268,11 +1269,28 @@ namespace IOB_WIN_FORM.Iob
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifica veto coda QueueIN ed aggiorna abilitazione su variabile
|
||||
/// Verifico i dynData x validità:
|
||||
/// - siano almeno 1
|
||||
/// - NON siano tutti identici
|
||||
/// </summary>
|
||||
protected void checkVetoQueueIn()
|
||||
/// <param name="currDynData"></param>
|
||||
/// <returns></returns>
|
||||
protected bool checkValidDynData(Dictionary<string, string> currDynData)
|
||||
{
|
||||
queueInEnabCurr = dtVetoQueueIN < DateTime.Now;
|
||||
bool answ = false;
|
||||
// conto num valori
|
||||
int numVal = currDynData.Count;
|
||||
bool dataPresent = numVal > 0;
|
||||
if (dataPresent)
|
||||
{
|
||||
// prendo il primo valore..
|
||||
string firstVal = currDynData.FirstOrDefault().Value;
|
||||
// conto val uguali al primo
|
||||
int numEq = currDynData.Where(x => x.Value == firstVal).Count();
|
||||
// se solo 1 o almeno 1 è diverso è ok
|
||||
answ = numVal == 1 || (numVal > numEq);
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1352,6 +1370,42 @@ namespace IOB_WIN_FORM.Iob
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifica se salvare (nel log) info dei FluxLog filtrati
|
||||
/// - per scadenza valore VetoFlushFiltFL
|
||||
/// - per un numero complessivo di eventi superiori a soglia
|
||||
/// </summary>
|
||||
/// <param name="minCount">numero minimo di eventi necessari al salvataggio (come somma complessiva)</param>
|
||||
protected void FiltFluxLogCheckSave(long minCount)
|
||||
{
|
||||
DateTime adesso = DateTime.Now;
|
||||
bool doWrite = VetoFlushFiltFL < adesso;
|
||||
// conteggio valori
|
||||
if (!doWrite)
|
||||
{
|
||||
long numFL = DictFiltFLog.Sum(x => x.Value);
|
||||
doWrite = numFL > minCount;
|
||||
}
|
||||
if (doWrite)
|
||||
{
|
||||
// scrivo log x ogni valore
|
||||
string sep = "------------------------------------------------------------";
|
||||
_logger.Info(sep);
|
||||
_logger.Info("- Paret0 Eventi FluxLog filtrati");
|
||||
_logger.Info(sep);
|
||||
foreach (var item in DictFiltFLog.OrderByDescending(x => x.Value))
|
||||
{
|
||||
// loggo!
|
||||
_logger.Info($"{item.Key}: {item.Value}");
|
||||
}
|
||||
_logger.Info(sep);
|
||||
// reset dizionario
|
||||
DictFiltFLog.Clear();
|
||||
// nuovo veto a 1h
|
||||
VetoFlushFiltFL = adesso.AddHours(1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imposta eventuali altri valori default
|
||||
/// </summary>
|
||||
@@ -1740,7 +1794,7 @@ namespace IOB_WIN_FORM.Iob
|
||||
}
|
||||
answ = await utils.callUrlAsync(url2call);
|
||||
#if false
|
||||
answ = utils.callUrlNow(url2call);
|
||||
answ = utils.callUrlNow(url2call);
|
||||
#endif
|
||||
}
|
||||
return answ;
|
||||
@@ -3190,28 +3244,28 @@ namespace IOB_WIN_FORM.Iob
|
||||
url2call = $"{urlRemTask2ExeTav(codTav)}{taskName}";
|
||||
}
|
||||
|
||||
#if false
|
||||
|
||||
try
|
||||
{
|
||||
Task.Run(async () => answ = await utils.callUrlAsync(url2call))
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
lgInfo($"Task2Exe.remTask2exe | {esitoTask} | chiamata URL {url2call} | answ: {answ}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lgError("ProcessAutoOdl | Crash nel ponte Sync/Async: " + ex.Message);
|
||||
}
|
||||
#endif
|
||||
await utils.callUrlAsync(url2call);
|
||||
#if false
|
||||
answ = utils.callUrlNow(url2call);
|
||||
#endif
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Salva nel dizionario il num di valori letti e filtrati/non inviati
|
||||
/// </summary>
|
||||
/// <param name="codFlux"></param>
|
||||
protected void SaveFiltFluxLog(string codFlux)
|
||||
{
|
||||
if (DictFiltFLog.ContainsKey(codFlux))
|
||||
{
|
||||
DictFiltFLog[codFlux]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
DictFiltFLog.Add(codFlux, 1);
|
||||
_logger.Info($"FluxLog | veto | {codFlux}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invio reset allarmi all'avvio per sicurezza...
|
||||
/// </summary>
|
||||
@@ -3335,7 +3389,7 @@ namespace IOB_WIN_FORM.Iob
|
||||
lgInfo("chiamata URL " + urlSetM2IOB);
|
||||
await utils.callUrlAsync(urlSetM2IOB);
|
||||
#if false
|
||||
utils.callUrlNow(urlSetM2IOB);
|
||||
utils.callUrlNow(urlSetM2IOB);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -3424,7 +3478,7 @@ namespace IOB_WIN_FORM.Iob
|
||||
lgInfo("chiamata URL " + url2call);
|
||||
await utils.callUrlAsync(url2call);
|
||||
#if false
|
||||
utils.callUrlNow(url2call);
|
||||
utils.callUrlNow(url2call);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -3912,33 +3966,6 @@ namespace IOB_WIN_FORM.Iob
|
||||
}
|
||||
}
|
||||
|
||||
protected static long GetObjectSize(object genObj, bool isSerializable)
|
||||
{
|
||||
long result = 0;
|
||||
if (isSerializable)
|
||||
{
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
|
||||
var formatter = new BinaryFormatter();
|
||||
formatter.Serialize(stream, genObj);
|
||||
result = stream.Length;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string rawVal = System.Text.Json.JsonSerializer.Serialize(genObj, options);
|
||||
result = rawVal.Length;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static readonly JsonSerializerOptions options = new JsonSerializerOptions
|
||||
{
|
||||
ReferenceHandler = ReferenceHandler.IgnoreCycles,
|
||||
WriteIndented = false // Optional: set to true for pretty-printing
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Traccia in redis l'attività di lettura dati
|
||||
/// </summary>
|
||||
@@ -4123,6 +4150,7 @@ namespace IOB_WIN_FORM.Iob
|
||||
}
|
||||
return fatto;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua chiamata MP-IO per tentare chiusura ODL specifico
|
||||
/// </summary>
|
||||
@@ -4448,6 +4476,7 @@ namespace IOB_WIN_FORM.Iob
|
||||
}
|
||||
raiseRefresh(currDispData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Versione sync chiamata setup PODL
|
||||
/// </summary>
|
||||
@@ -4542,6 +4571,14 @@ namespace IOB_WIN_FORM.Iob
|
||||
return $@"{urlMesServer}{IOBConfFull.MapoMes.ApiUrl(cmqReq)}{IOBConfFull.General.FilenameIOB}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// URL per richiamo task da eseguire...
|
||||
/// </summary>
|
||||
protected string urlRemTask2ExeTav(string codTav)
|
||||
{
|
||||
return $@"{urlCommandIob("remTask2Exe")}|{codTav}?taskName=";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifica se il parametro passi il limite della DeadBand (globale o specifica se
|
||||
/// configurata) Il riferimento è al prec valore currProdData
|
||||
@@ -4595,6 +4632,12 @@ namespace IOB_WIN_FORM.Iob
|
||||
|
||||
#region Private Fields
|
||||
|
||||
private static readonly JsonSerializerOptions options = new JsonSerializerOptions
|
||||
{
|
||||
ReferenceHandler = ReferenceHandler.IgnoreCycles,
|
||||
WriteIndented = false // Optional: set to true for pretty-printing
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Oggetto logger della classe
|
||||
/// </summary>
|
||||
@@ -4610,64 +4653,6 @@ namespace IOB_WIN_FORM.Iob
|
||||
/// </summary>
|
||||
private Dictionary<string, long> DictFiltFLog = new Dictionary<string, long>();
|
||||
|
||||
/// <summary>
|
||||
/// Valore veto al salvataggio di valori filtrati in FluxLog se NON superato limite chiamate
|
||||
/// </summary>
|
||||
private DateTime VetoFlushFiltFL = DateTime.Now.AddHours(1);
|
||||
|
||||
/// <summary>
|
||||
/// Salva nel dizionario il num di valori letti e filtrati/non inviati
|
||||
/// </summary>
|
||||
/// <param name="codFlux"></param>
|
||||
protected void SaveFiltFluxLog(string codFlux)
|
||||
{
|
||||
if (DictFiltFLog.ContainsKey(codFlux))
|
||||
{
|
||||
DictFiltFLog[codFlux]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
DictFiltFLog.Add(codFlux, 1);
|
||||
_logger.Info($"FluxLog | veto | {codFlux}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifica se salvare (nel log) info dei FluxLog filtrati
|
||||
/// - per scadenza valore VetoFlushFiltFL
|
||||
/// - per un numero complessivo di eventi superiori a soglia
|
||||
/// </summary>
|
||||
/// <param name="minCount">numero minimo di eventi necessari al salvataggio (come somma complessiva)</param>
|
||||
protected void FiltFluxLogCheckSave(long minCount)
|
||||
{
|
||||
DateTime adesso = DateTime.Now;
|
||||
bool doWrite = VetoFlushFiltFL < adesso;
|
||||
// conteggio valori
|
||||
if (!doWrite)
|
||||
{
|
||||
long numFL = DictFiltFLog.Sum(x => x.Value);
|
||||
doWrite = numFL > minCount;
|
||||
}
|
||||
if (doWrite)
|
||||
{
|
||||
// scrivo log x ogni valore
|
||||
string sep = "------------------------------------------------------------";
|
||||
_logger.Info(sep);
|
||||
_logger.Info("- Paret0 Eventi FluxLog filtrati");
|
||||
_logger.Info(sep);
|
||||
foreach (var item in DictFiltFLog.OrderByDescending(x => x.Value))
|
||||
{
|
||||
// loggo!
|
||||
_logger.Info($"{item.Key}: {item.Value}");
|
||||
}
|
||||
_logger.Info(sep);
|
||||
// reset dizionario
|
||||
DictFiltFLog.Clear();
|
||||
// nuovo veto a 1h
|
||||
VetoFlushFiltFL = adesso.AddHours(1);
|
||||
}
|
||||
}
|
||||
|
||||
private string LastDayCurr = "";
|
||||
|
||||
/// <summary>
|
||||
@@ -4685,6 +4670,17 @@ namespace IOB_WIN_FORM.Iob
|
||||
private Dictionary<string, int> TrackDetStatsCount = new Dictionary<string, int>();
|
||||
|
||||
private Dictionary<string, Dictionary<string, string>> TrackDetValsCount = new Dictionary<string, Dictionary<string, string>>();
|
||||
#if false
|
||||
/// <summary>
|
||||
/// Ultimo valore B_output inviato
|
||||
/// </summary>
|
||||
protected int B_output_sent = -1;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Valore veto al salvataggio di valori filtrati in FluxLog se NON superato limite chiamate
|
||||
/// </summary>
|
||||
private DateTime VetoFlushFiltFL = DateTime.Now.AddHours(1);
|
||||
|
||||
/// <summary>
|
||||
/// Dizionario dei valori bloccati x evitare log eccessivo
|
||||
@@ -4720,88 +4716,6 @@ namespace IOB_WIN_FORM.Iob
|
||||
|
||||
#region Private Properties
|
||||
|
||||
/// <summary>
|
||||
/// Verifica se la IOB sia ENABLED (da server o Demo)
|
||||
/// </summary>
|
||||
public async Task<bool> CheckIobEnabled()
|
||||
{
|
||||
// 1. Controllo Veto (Sincrono)
|
||||
if (dtVetoCheckIOB >= DateTime.Now)
|
||||
return IobOnline;
|
||||
|
||||
bool currentAnsw = false;
|
||||
|
||||
if (DemoOut)
|
||||
{
|
||||
currentAnsw = (QueueIN.Count + QueueFLog.Count >= nMaxSend);
|
||||
}
|
||||
else
|
||||
{
|
||||
currentAnsw = await ExecuteIobCheckWithRetry(maxRetries: 5);
|
||||
#if false
|
||||
// 2. Chiamata asincrona con Retry (Ponte Sync/Async)
|
||||
currentAnsw = Task.Run(async () => await ExecuteIobCheckWithRetry(maxRetries: 5))
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
#endif
|
||||
}
|
||||
|
||||
// 3. Gestione Stato e Logica UI
|
||||
UpdateIobState(currentAnsw);
|
||||
|
||||
return currentAnsw;
|
||||
}
|
||||
|
||||
private async Task<bool> ExecuteIobCheckWithRetry(int maxRetries)
|
||||
{
|
||||
var rand = new Random();
|
||||
for (int i = 0; i <= maxRetries; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
// Al terzo tentativo fallito resetto i client
|
||||
if (i == 3) resetWebClients();
|
||||
|
||||
int delay = i == 3 ? rand.Next(250, 1000) : rand.Next(250, 500);
|
||||
await Task.Delay(delay);
|
||||
}
|
||||
|
||||
string callResp = await callUrl(urlIobEnabled, i < 3); // true per i primi tentativi
|
||||
if (callResp == "OK") return true;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lgError($"Eccez<ione in ExecuteIobCheckWithRetry{Environment.NewLine}{exc}");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void UpdateIobState(bool newStatus)
|
||||
{
|
||||
// Log se lo stato è cambiato
|
||||
if (IobOnline != newStatus)
|
||||
{
|
||||
lgInfo(newStatus ? "IOB ONLINE for server MP/IO" : "IOB OFFLINE for server MP/IO");
|
||||
IobOnline = newStatus;
|
||||
if (newStatus)
|
||||
{
|
||||
lastIobOnline = DateTime.Now;
|
||||
parentForm.commSrvActive = 2; // Stato Online
|
||||
}
|
||||
else
|
||||
{
|
||||
parentForm.commSrvActive = 1; // Stato Degradato/Offline
|
||||
}
|
||||
}
|
||||
|
||||
// Imposto il veto per il prossimo controllo
|
||||
dtVetoCheckIOB = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 5);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Boolean abilitazione coda eventi IN
|
||||
/// </summary>
|
||||
@@ -4815,98 +4729,6 @@ namespace IOB_WIN_FORM.Iob
|
||||
get => redisMan.redHash($"IOB:Status:{IOBConfFull.General.FilenameIOB}:CurrProdData");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test ping all'indirizzo impostato nei parametri
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private IPStatus GetPingStatus()
|
||||
{
|
||||
var pStatus = Task.Run(async () => await GetPingStatusAsync(maxPingRetry + 1))
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
|
||||
return pStatus;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test ping all'indirizzo impostato nei parametri
|
||||
/// </summary>
|
||||
/// <param name="maxRetry">Numero max tentativi (maxPingRetry + 1)</param>
|
||||
/// <returns></returns>
|
||||
private async Task<IPStatus> GetPingStatusAsync(int maxAttempts)
|
||||
{
|
||||
// 1. Check disabilitazione
|
||||
if (IOBConfFull.MapoMes.DisabPing) return IPStatus.Success;
|
||||
|
||||
// 2. Estrazione Host/IP pulita
|
||||
string host = IOBConfFull.MapoMes.IpAddr;
|
||||
try
|
||||
{
|
||||
// Rimuove protocollo (http://, ftp://, etc)
|
||||
if (host.Contains("://"))
|
||||
host = new Uri(host).Host;
|
||||
else if (host.Contains(":"))
|
||||
host = host.Split(':')[0];
|
||||
}
|
||||
catch { /* fallback al valore originale se Uri fallisce */ }
|
||||
|
||||
// 3. Risoluzione Indirizzo
|
||||
if (!IPAddress.TryParse(host, out IPAddress address))
|
||||
{
|
||||
try
|
||||
{
|
||||
var addresses = Dns.GetHostAddresses(host);
|
||||
if (addresses.Length > 0) address = addresses[0];
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lgError($"Impossibile risolvere DNS per {host}: {ex.Message}");
|
||||
return IPStatus.DestinationHostUnreachable;
|
||||
}
|
||||
}
|
||||
|
||||
if (address == null) return IPStatus.Unknown;
|
||||
|
||||
// 4. Ciclo di Ping con Retry
|
||||
var rand = new Random();
|
||||
using (Ping pingSender = new Ping())
|
||||
{
|
||||
for (int attempt = 1; attempt <= maxAttempts; attempt++)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Timeout dinamico come nel tuo originale
|
||||
int timeout = (attempt == 1)
|
||||
? rand.Next(200, 400)
|
||||
: (pingServerMsTimeout * attempt / 2);
|
||||
|
||||
PingReply reply = pingSender.Send(address, timeout);
|
||||
|
||||
if (reply.Status == IPStatus.Success)
|
||||
{
|
||||
if (attempt > 1) lgInfo("Server PING OK dopo retry!");
|
||||
return IPStatus.Success;
|
||||
}
|
||||
|
||||
lgInfo($"Ping tent. {attempt} fallito: {reply.Status} (Timeout: {timeout}ms)");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lgError($"Eccezione durante ping tent. {attempt}: {ex.Message}");
|
||||
}
|
||||
|
||||
// Attesa prima del prossimo tentativo (se non è l'ultimo)
|
||||
if (attempt < maxAttempts)
|
||||
{
|
||||
await Task.Delay(rand.Next(50, 200));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return IPStatus.TimedOut;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// URL di base del server MES da contattare
|
||||
/// </summary>
|
||||
@@ -5149,6 +4971,33 @@ namespace IOB_WIN_FORM.Iob
|
||||
return fatto;
|
||||
}
|
||||
|
||||
private async Task<bool> ExecuteIobCheckWithRetry(int maxRetries)
|
||||
{
|
||||
var rand = new Random();
|
||||
for (int i = 0; i <= maxRetries; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
// Al terzo tentativo fallito resetto i client
|
||||
if (i == 3) resetWebClients();
|
||||
|
||||
int delay = i == 3 ? rand.Next(250, 1000) : rand.Next(250, 500);
|
||||
await Task.Delay(delay);
|
||||
}
|
||||
|
||||
string callResp = await callUrl(urlIobEnabled, i < 3); // true per i primi tentativi
|
||||
if (callResp == "OK") return true;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lgError($"Eccez<ione in ExecuteIobCheckWithRetry{Environment.NewLine}{exc}");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue filtraggio dati x bit blinking!!!
|
||||
/// </summary>
|
||||
@@ -5226,6 +5075,97 @@ namespace IOB_WIN_FORM.Iob
|
||||
demFactDynData = IOBConfFull.FluxLog.DemFactDynData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test ping all'indirizzo impostato nei parametri
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private IPStatus GetPingStatus()
|
||||
{
|
||||
var pStatus = Task.Run(async () => await GetPingStatusAsync(maxPingRetry + 1))
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
|
||||
return pStatus;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test ping all'indirizzo impostato nei parametri
|
||||
/// </summary>
|
||||
/// <param name="maxRetry">Numero max tentativi (maxPingRetry + 1)</param>
|
||||
/// <returns></returns>
|
||||
private async Task<IPStatus> GetPingStatusAsync(int maxAttempts)
|
||||
{
|
||||
// 1. Check disabilitazione
|
||||
if (IOBConfFull.MapoMes.DisabPing) return IPStatus.Success;
|
||||
|
||||
// 2. Estrazione Host/IP pulita
|
||||
string host = IOBConfFull.MapoMes.IpAddr;
|
||||
try
|
||||
{
|
||||
// Rimuove protocollo (http://, ftp://, etc)
|
||||
if (host.Contains("://"))
|
||||
host = new Uri(host).Host;
|
||||
else if (host.Contains(":"))
|
||||
host = host.Split(':')[0];
|
||||
}
|
||||
catch { /* fallback al valore originale se Uri fallisce */ }
|
||||
|
||||
// 3. Risoluzione Indirizzo
|
||||
if (!IPAddress.TryParse(host, out IPAddress address))
|
||||
{
|
||||
try
|
||||
{
|
||||
var addresses = Dns.GetHostAddresses(host);
|
||||
if (addresses.Length > 0) address = addresses[0];
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lgError($"Impossibile risolvere DNS per {host}: {ex.Message}");
|
||||
return IPStatus.DestinationHostUnreachable;
|
||||
}
|
||||
}
|
||||
|
||||
if (address == null) return IPStatus.Unknown;
|
||||
|
||||
// 4. Ciclo di Ping con Retry
|
||||
var rand = new Random();
|
||||
using (Ping pingSender = new Ping())
|
||||
{
|
||||
for (int attempt = 1; attempt <= maxAttempts; attempt++)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Timeout dinamico come nel tuo originale
|
||||
int timeout = (attempt == 1)
|
||||
? rand.Next(200, 400)
|
||||
: (pingServerMsTimeout * attempt / 2);
|
||||
|
||||
PingReply reply = pingSender.Send(address, timeout);
|
||||
|
||||
if (reply.Status == IPStatus.Success)
|
||||
{
|
||||
if (attempt > 1) lgInfo("Server PING OK dopo retry!");
|
||||
return IPStatus.Success;
|
||||
}
|
||||
|
||||
lgInfo($"Ping tent. {attempt} fallito: {reply.Status} (Timeout: {timeout}ms)");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lgError($"Eccezione durante ping tent. {attempt}: {ex.Message}");
|
||||
}
|
||||
|
||||
// Attesa prima del prossimo tentativo (se non è l'ultimo)
|
||||
if (attempt < maxAttempts)
|
||||
{
|
||||
await Task.Delay(rand.Next(50, 200));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return IPStatus.TimedOut;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifica se il log di un dato errore sia permesso
|
||||
/// </summary>
|
||||
@@ -5632,7 +5572,6 @@ namespace IOB_WIN_FORM.Iob
|
||||
{
|
||||
lgError($"Errore in RecipeDoProcessPODL.callUrl: {ex.Message}");
|
||||
}
|
||||
|
||||
}
|
||||
answ = true;
|
||||
}
|
||||
@@ -5662,6 +5601,132 @@ namespace IOB_WIN_FORM.Iob
|
||||
parentForm.dataProcLabel = string.Format("RAW: {0} --> IN: {1} --> OUT: {2}", nReadIN, nReadFilt, nSendOut);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chiamate ritorno task eseguiti al server
|
||||
/// </summary>
|
||||
/// <param name="listaValori"></param>
|
||||
/// <returns></returns>
|
||||
private async Task SendTaskResult(List<string> listaValori)
|
||||
{
|
||||
foreach (var rawJob in listaValori)
|
||||
{
|
||||
// deserializzo...
|
||||
JobTaskData jobTask = JsonConvert.DeserializeObject<JobTaskData>(rawJob);
|
||||
#if false
|
||||
// loggo tutti i task done...
|
||||
foreach (var item in jobTask.TaskList)
|
||||
{
|
||||
sendToTaskWatch(item.Key, item.Value, jobTask.CodTav);
|
||||
}
|
||||
#endif
|
||||
// ora chiamo la cancellazione dei task eseguiti...
|
||||
var taskDict = JobTaskData.TaskDict(jobTask.RawData);
|
||||
foreach (var item in taskDict)
|
||||
{
|
||||
await remTask2exe(item.Key, item.Value, jobTask.CodTav);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua ciclo recupero richieste server
|
||||
/// </summary>
|
||||
private async Task ServerGetRequestsAsync()
|
||||
{
|
||||
// recupero elenco delle cose da fare
|
||||
string resp = await getTask2exe("");
|
||||
// se ho qualcosa --> creo obj e lo accodo...
|
||||
//if (!string.IsNullOrEmpty(resp))
|
||||
if (!string.IsNullOrEmpty(resp) && resp.Length > 2)
|
||||
{
|
||||
//await ProcessResp(resp, "");
|
||||
accodaServReq("", resp);
|
||||
if (isMulti)
|
||||
{
|
||||
foreach (var item in IOBConfFull.Device.MultiIobList)
|
||||
{
|
||||
resp = await getTask2exe(item);
|
||||
accodaServReq(item, resp);
|
||||
//await ProcessResp(resp, rawJob);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vers originale
|
||||
#if false
|
||||
// recupero elenco delle cose da fare
|
||||
string resp = await getTask2exe("");
|
||||
await ProcessResp(resp, "");
|
||||
// se fosse multi --> eseguo task per le varie sub (Tavole/Pallet)
|
||||
if (isMulti)
|
||||
{
|
||||
foreach (var item in IOBConfFull.Device.MultiIobList)
|
||||
{
|
||||
resp = await getTask2exe(item);
|
||||
await ProcessResp(resp, item);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua ciclo invio rispsote (=esito esecuzione richieste) al server
|
||||
/// </summary>
|
||||
private async Task ServerPutRespAsync()
|
||||
{
|
||||
// verifico SE la coda abbia dei valori...
|
||||
if (QueueSrvResp.Count > 0)
|
||||
{
|
||||
// invio pacchetto di dati (max da conf)
|
||||
for (int i = 0; i < nMaxSend; i++)
|
||||
{
|
||||
// SE ho qualcosa in coda...
|
||||
if (QueueSrvResp.Count > 0)
|
||||
{
|
||||
string currVal = "";
|
||||
if (MPOnline)
|
||||
{
|
||||
if (IobOnline)
|
||||
{
|
||||
List<string> listaValori = new List<string>();
|
||||
// se ho + di maxJsonData elementi --> invio un set di dati alla volta
|
||||
if (QueueSrvResp.Count > maxJsonData)
|
||||
{
|
||||
// prendoi primi maxJsonDataValori
|
||||
for (int j = 0; j < maxJsonData; j++)
|
||||
{
|
||||
QueueSrvResp.TryDequeue(out currVal);
|
||||
listaValori.Add(currVal);
|
||||
}
|
||||
await SendTaskResult(listaValori);
|
||||
}
|
||||
else
|
||||
{
|
||||
// invio in blocco
|
||||
listaValori = QueueSrvResp.ToList();
|
||||
await SendTaskResult(listaValori);
|
||||
// svuoto!
|
||||
QueueSrvResp = new DataQueue(IOBConfFull.General.FilenameIOB, "QueueServResp", IOBConfFull.General.EnabRedisQue, redisMan);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imposto alcuni valori di default
|
||||
/// </summary>
|
||||
@@ -5687,15 +5752,18 @@ namespace IOB_WIN_FORM.Iob
|
||||
{
|
||||
string codIob = IOBConfFull.General.FilenameIOB;
|
||||
bool useRedis = IOBConfFull.General.EnabRedisQue;
|
||||
QueueAlarm = new DataQueue(codIob, "QueueAlarm", false, redisMan);
|
||||
QueueIN.Dispose();
|
||||
QueueIN = new DataQueue(codIob, "QueueIN", useRedis, redisMan);
|
||||
QueueSrvResp.Dispose();
|
||||
QueueSrvResp = new DataQueue(codIob, "QueueServResp", useRedis, redisMan);
|
||||
// no coda redis
|
||||
QueueAlarm = new DataQueue(codIob, "QueueAlarm", false, redisMan);
|
||||
QueueFLog = new DataQueue(codIob, "QueueFLog", false, redisMan);
|
||||
QueueMessages = new DataQueue(codIob, "QueueMessages", false, redisMan);
|
||||
QueueRawTransf = new DataQueue(codIob, "QueueRawTransf", false, redisMan);
|
||||
QueueULog = new DataQueue(codIob, "QueueULog", false, redisMan);
|
||||
QueuePing = new DataQueue(codIob, "QueuePing", false, redisMan);
|
||||
QueueRawTransf = new DataQueue(codIob, "QueueRawTransf", false, redisMan);
|
||||
QueueSrvReq = new DataQueue(codIob, "QueueServReq", false, redisMan);
|
||||
QueueULog = new DataQueue(codIob, "QueueULog", false, redisMan);
|
||||
}
|
||||
// imposto contatori blink a zero...
|
||||
i_counters = new int[32];
|
||||
@@ -5982,6 +6050,28 @@ namespace IOB_WIN_FORM.Iob
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateIobState(bool newStatus)
|
||||
{
|
||||
// Log se lo stato è cambiato
|
||||
if (IobOnline != newStatus)
|
||||
{
|
||||
lgInfo(newStatus ? "IOB ONLINE for server MP/IO" : "IOB OFFLINE for server MP/IO");
|
||||
IobOnline = newStatus;
|
||||
if (newStatus)
|
||||
{
|
||||
lastIobOnline = DateTime.Now;
|
||||
parentForm.commSrvActive = 2; // Stato Online
|
||||
}
|
||||
else
|
||||
{
|
||||
parentForm.commSrvActive = 1; // Stato Degradato/Offline
|
||||
}
|
||||
}
|
||||
|
||||
// Imposto il veto per il prossimo controllo
|
||||
dtVetoCheckIOB = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 5);
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
}
|
||||
+710
-178
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,8 @@
|
||||
}
|
||||
],
|
||||
"fluxLogVeto": [
|
||||
"E_nblock1",
|
||||
"E_nline1",
|
||||
"S_nactS1P1",
|
||||
"S_nloadS1P1",
|
||||
"S_nactUP1",
|
||||
|
||||
Reference in New Issue
Block a user