Files
Mapo-IOB-WIN/IOB-WIN-NEXT/IobNet/Ftp.cs
T
2024-10-07 14:47:44 +02:00

366 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using EgwProxy.Ftp;
using IOB_UT_NEXT;
using MapoSDK;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
namespace IOB_WIN_NEXT.IobNet
{
/// <summary>
/// Classe gestione sync via FTP
/// </summary>
public class Ftp : Iob.Generic
{
#region Public Constructors
/// <summary>
/// Estende l'init della classe base, impiegando il pacchetto EgwCoreLib.Ftp
/// - gestione dei task da svolgere da configurazione json specifica
/// - specializzazione da conf e non da codice
/// </summary>
/// <param name="caller"></param>
/// <param name="IOBConf"></param>
public Ftp(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf)
{
lgInfo("Init IobFtp Client");
// init datetime counters
DateTime adesso = DateTime.Now;
lastPzCountSend = adesso;
lastWarnODL = adesso;
vetoCheckStatus = adesso;
// 2023.09.05 imposto anche primo ping e check disconnected...
lastPING = adesso;
lastDisconnCheck = adesso;
var POWEROFF_TIMEOUT_SEC = getOptPar("POWEROFF_TIMEOUT_SEC");
if (!string.IsNullOrEmpty(POWEROFF_TIMEOUT_SEC))
{
int.TryParse(POWEROFF_TIMEOUT_SEC, out PoweroffTimeoutSec);
}
// fix coda ping
PingQueue = new DataQueue("000", "PingQueue", false);
// carico conf specifica steps FTP
string ftpConfFile = getOptPar("FTP_PARAM");
if (!string.IsNullOrEmpty(ftpConfFile))
{
loadFtpConfFile(ftpConfFile);
}
}
#endregion Public Constructors
#region Public Methods
/// <summary>
/// Processo i task richiesti e li elimino dalla coda
/// </summary>
/// <param name="task2exe"></param>
public override Dictionary<string, string> executeTasks(Dictionary<string, string> task2exe)
{
// il compito della richiesta è SEMPRE scrivere folder dell'ODL corrente SE NON LA TROVASSE
// uso metodo base x salvare esito scrittura
var writeResult = base.executeTasks(task2exe);
/*---------------------------------------------------------------------------
* va creata una folder x ogni ODL (una volta LANCIATO da tablet) APERTO
* - nella folder scriviamo un file con articolo, qta, commessa
* - la folder sarà usata x salvare OGNI file necessario e di rilevazione
*---------------------------------------------------------------------------*/
// aggiungo comportamento custom: se ho impostato nome ricetta (programma) --> imposto
// richiesta caricamento se ho richiesto reset o fine lavoro --> imposto azzeramento
// esco restituendo risutlato scrittura iniziali
if (task2exe != null)
{
// controllo se memMap != null...
if (memMap != null)
{
bool taskOk = false;
string taskVal = "";
// cerco task specifici x OMP
foreach (var item in task2exe)
{
taskOk = false;
taskVal = "";
// converto richiesta in enum...
taskType tName = taskType.nihil;
Enum.TryParse(item.Key, out tName);
// controllo sulla KEY...
switch (tName)
{
#if false
case taskType.setProg:
// recupero dati da memMap...
if (memMap != null && memMap.mMapWrite != null)
{
if (memMap.mMapWrite.ContainsKey(item.Key))
{
dataConf currMem = memMap.mMapWrite[item.Key];
string addr = currMem.memAddr;
taskVal = $"SET task: {item.Key} --> {item.Value} | mem: {currMem.memAddr} - {currMem.size} byte";
// salvo il nuovo valore nella memoria... così prox invio lo trasmetterà
memMap.mMapWrite[item.Key].value = item.Value;
}
else
{
taskVal = $"NO DATA MEM, SET task: {item.Key} --> {item.Value}";
}
}
else
{
taskVal = $"NO MemMap found, SET task: {item.Key} --> {item.Value}";
}
// salvo in currProd..
saveProdData(new KeyValuePair<string, string>(item.Key, item.Value));
break;
case taskType.startSetup:
setFineLotto();
break;
case taskType.stopSetup:
setInizioProd();
break;
case taskType.syncDbData:
processDataSync();
break;
#endif
default:
taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC";
lgInfo($"Chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}");
break;
}
}
}
else
{
lgError($"Attenzione! memMap è nullo, non posso eseguire task2exe!");
}
}
return writeResult;
}
/// <summary>
/// Effettua processing CUSTOM x FTP:
/// - prende ogni conf specifica
/// - esegue step
/// - registra eventuali DynData da salvare
/// </summary>
public override void processCustomTaskMF()
{
lgInfo($"Richiesto processCustomTaskLF");
// verifico di avere compiti da svolgere...
if (currFtpTaskList != null && currFtpTaskList.ListTask != null && currFtpTaskList.ListTask.Count > 0)
{
Manager ftpClient = new Manager("", "", "", "", false);
foreach (var srvFtp in currFtpTaskList.ListTask)
{
// ora setup server FTP x item...
ftpClient = new Manager(srvFtp.ServerAddr, srvFtp.ConnUser, srvFtp.ConnPasswd, srvFtp.RawCert, srvFtp.SkipCert);
serverTest(ftpClient);
}
}
#if false
var currBatch = IcoelSizer.GetCurrentBatch();
lgTrace("SOAP: effettuata chiamata IcoelSizer.GetCurrentBatch()");
if (currBatch != null)
{
// verifico se i batch siano variati... e quindi da inviare...
bool doSend = (currBatchList == null || currBatchList.Count == 0);
if (currBatch.Count > 0 && !doSend)
{
foreach (var item in currBatch)
{
// se variato ID è cambiato
doSend = doSend || (currBatchList[item.Key].Id != item.Value.Id);
}
}
// se devo inviare impacchetto dati
if (doSend)
{
accodaRawData(rawTransfType.IcoelBatch, currBatch);
currBatchList = currBatch;
}
}
#endif
lastReadPLC = DateTime.Now;
}
/// <summary>
/// Effettua lettura semafori principale <paramref name="currDispData">Parametri da
/// aggiornare x display in form</paramref>
/// </summary>
public override void readSemafori(ref newDisplayData currDispData)
{
// lo stato è come ping machine, x ora puntato a IP unico (WiFi?)
DateTime adesso = DateTime.Now;
byte[] MemBlock = new byte[2];
try
{
currDispData.semIn = Semaforo.SV;
// in primis salvo data ping comunque...
lastPING = DateTime.Now;
// salvo esito ping
bool pingOK = testPingMachine == IPStatus.Success;
addTest(pingOK);
// se passa il ping faccio il resto...
if (pingStatusOk())
{
connectionOk = true;
lastReadPLC = DateTime.Now;
lastWatchDog = DateTime.Now;
}
else
{
connectionOk = false;
}
if (connectionOk)
{
B_input = 1;
}
else
{
B_input = 0;
}
// annullo lettura bit signal IN pre/post x evitare invio automatico...
B_output = B_input;
B_previous = B_input;
}
catch
{
currDispData.semIn = Semaforo.SR;
}
}
#endregion Public Methods
#region Protected Fields
/// <summary>
/// Dimensione coda di ping x valutazione
/// </summary>
protected int maxQueuePing = 11;
/// <summary>
/// Coda degli esiti di ping x calcolo stato macchina
/// </summary>
protected DataQueue PingQueue = new DataQueue("000", "PingQueue", false);
protected int PoweroffTimeoutSec = 100;
/// <summary>
/// Veto controllo status x log...
/// </summary>
protected DateTime vetoCheckStatus = DateTime.Now;
#endregion Protected Fields
#region Protected Methods
protected void addTest(bool pingOk)
{
int score = pingOk ? 1 : 0;
// controllo: se era spenta e risulta ping ok --> reset coda!
if (B_input == 0 && pingOk)
{
B_input = 1;
PingQueue = new DataQueue("000", "PingQueue", false);
lgTrace($"PingQueue resetted on addTest");
}
PingQueue.Enqueue($"{score}");
while (PingQueue.Count > maxQueuePing)
{
string res = "";
PingQueue.TryDequeue(out res);
}
}
/// <summary>
/// Calcola status ping:
/// - se ha 50% coda richiesta -- true
/// - se ha 50% coda richiesta -- true se è maggior parte a 1 (true)
/// </summary>
/// <returns></returns>
protected bool pingStatusOk()
{
bool answ = true;
int numVal = PingQueue.Count;
if (numVal > maxQueuePing / 2)
{
var listaValori = PingQueue.ToList();
int numOk = listaValori.Where(x => x == "1").Count();
int numKo = numVal - numOk;
answ = numOk >= numKo;
lgTrace($"PING ok per: {numOk} > {numKo}");
}
else
{
lgTrace("PING ok per mancanza dati minimi test");
}
return answ;
}
#endregion Protected Methods
#region Private Properties
/// <summary>
/// Oggetto configurazione gestione FTP
/// </summary>
private FtpTaskList currFtpTaskList { get; set; } = new FtpTaskList();
#endregion Private Properties
#region Private Methods
/// <summary>
/// Effettuo lettura file di conf
/// </summary>
/// <param name="fileName"></param>
private void loadFtpConfFile(string fileName)
{
string jsonFullPath = $"{System.Windows.Forms.Application.StartupPath}/DATA/CONF/{fileName}";
lgInfo($"Apertura file {jsonFullPath}");
using (StreamReader reader = new StreamReader(jsonFullPath))
{
string jsonData = reader.ReadToEnd().Replace("\n", "").Replace("\r", "");
if (!string.IsNullOrEmpty(jsonData))
{
lgDebug($"File json composto da {jsonData.Length} caratteri");
try
{
currFtpTaskList = JsonConvert.DeserializeObject<FtpTaskList>(jsonData);
lgDebug($"Decodifica aree FtpTaskList: trovati {currFtpTaskList.ListTask.Count} gruppi di task FTP");
}
catch (Exception exc)
{
lgError($"Eccezione in decodifica conf json FTP:{Environment.NewLine}{exc}");
}
}
else
{
lgError("Errore in loadFtpConfFile: file json vuoto!");
}
}
}
#endregion Private Methods
}
}