using EgwProxy.Ftp; using FluentFTP; using IOB_UT_NEXT; using MapoSDK; using Newtonsoft.Json; using OpenQA.Selenium.Remote; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Packaging; using System.Linq; using System.Net.NetworkInformation; using System.Text; using System.Threading.Tasks; using System.Xml.Linq; using static System.Windows.Forms.VisualStyles.VisualStyleElement; namespace IOB_WIN_NEXT.IobNet { /// /// Classe gestione sync via FTP /// public class Ftp : Iob.Generic { #region Public Constructors /// /// 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 /// /// /// public Ftp(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) { lgInfo("Init IobFtp Client"); // imposto B_input = 0; // 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 VETO_PING_SEC = getOptPar("VETO_PING_SEC"); if (!string.IsNullOrEmpty(VETO_PING_SEC)) { int.TryParse(VETO_PING_SEC, out vetoPingSec); } var VETO_CHECKDIR_SEC = getOptPar("VETO_CHECKDIR_SEC"); if (!string.IsNullOrEmpty(VETO_CHECKDIR_SEC)) { int.TryParse(VETO_CHECKDIR_SEC, out vetoCheckDirSec); } 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); // mi calcolo ed imposto la ftpClientMan + Remote BaseDir... string actKey = "RemoteDir"; if (currFtpTaskList != null && currFtpTaskList.ListTask.Count > 0) { // prendo i task foreach (var fTask in currFtpTaskList.ListTask) { if (string.IsNullOrEmpty(RemoteBaseDir)) { foreach (var fAct in fTask.StepsList) { // cerco nei parametri... if (fAct.ParamList.ContainsKey(actKey)) { RemoteBaseDir = fAct.ParamList[actKey]; break; } } } if (!ftpClientMan.IsConfigured) { // setup ftpClientMan! ftpClientMan = new Manager(fTask.ServerAddr, fTask.ConnUser, fTask.ConnPasswd, fTask.RawCert, fTask.SkipCert); } } } } forceMemMap(); // invio conf macchina all'inizio SendMachineConf(); } #endregion Public Constructors #region Public Methods /// /// Processo i task richiesti e li elimino dalla coda /// /// public override Dictionary executeTasks(Dictionary 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 * - per farlo si creeano degli ActionStep specifici e vengono poi richiamati... *---------------------------------------------------------------------------*/ // Verificare il protocollo: dovrebbe togliere SOLO i task eseguiti... Dictionary taskDone = new Dictionary(); ActionConfig currAct = new ActionConfig(); var currActParam = new Dictionary(); string actKey = "RemoteDir"; string newDir = ""; bool taskOk = false; string taskVal = ""; string fNameOdl = "ODL_ATTIVO.txt"; string basePath = System.Windows.Forms.Application.StartupPath; string remFile = ""; string fileContent = ""; string locFile = ""; // cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4 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) { case taskType.setArt: case taskType.setPzComm: // L'articolo ed il numPz li salva nei dati di produzione... SE disponibili // li indicherà nel file ODL ATTIVA... upsertKey(item.Key, item.Value); // salvo nei taskVal il valore acquisito... taskVal = $"Saved {item.Key} = {item.Value} on ProdData"; break; case taskType.setComm: /*------------------------------------------------------------------ * La commessa è la cartella DI BASE per poter poi procedere con acquisizione dati... * - step 1: check folder * - step 2: creazione folder * - step 3: salva file ODL_attiva * - step 4: salva parametro dell'ODL corrente ------------------------------------------------------------------*/ // compongo remDir dai 2 parametri... actKey = "RemoteDir"; newDir = $"{RemoteBaseDir}/{item.Value}"; currActParam.Add(actKey, newDir); currAct = new ActionConfig() { Id = "01", Description = "Verifica esistenza directory", Action = ActType.CheckDir, ParamList = currActParam }; //eseguo step... bool dirOk = doStep(currAct); // se la cartella mancasse if (!dirOk) { // nuovo act x crearla! currAct = new ActionConfig() { Id = "02", Description = "Creazione directory", Action = ActType.CreateDir, ParamList = currActParam }; //eseguo step... dirOk = doStep(currAct); if (dirOk) { taskVal = $"DIR Created: {item.Key} --> {item.Value}"; } } else { taskVal = $"DIR Already Exists: {item.Key} --> {item.Value}"; } // ora creo il file interno... remFile = $"{newDir}/{fNameOdl}"; // cerco se disponibili info in prodData x art/pezzi string setArt = getCurrProdData("setArt", "ND"); string setPzComm = getCurrProdData("setPzComm", "?"); fileContent = $"NEW ODL activated | {item.Value} | ART: {setArt} x {setPzComm} pz | {DateTime.Now}"; locFile = Path.Combine(basePath, "temp", fNameOdl); taskOk = SendOdlActFile(locFile, remFile, fileContent); if (taskOk) { taskVal += $"{Environment.NewLine}File uploaded | locFile: {locFile} | remFile: {remFile}"; } else { lgError($"Error in startSetup | fileUpload | locFile: {locFile} | remFile: {remFile}"); } // salvo in currProd.. upsertKey(item.Key, item.Value); break; case taskType.startSetup: case taskType.stopSetup: //verifico odl x prima cosa... pzCntReload(true); // faccio pulizia preliminare della commessa corrente... bool cleanDone = RemPlaceholder(RemoteBaseDir, fNameOdl); if (cleanDone) { lgInfo($"Cleaned {fNameOdl} during startSetup | remDir: {RemoteBaseDir}"); } // verifico di avere già un ODL corrente... if (currIdxODL == 0) { lgTrace($"Manca ODL corrente: non procedo con impostazione start/stop setup"); } else { string odlFolder = $"ODL{currIdxODL:00000000}"; remFile = $"{RemoteBaseDir}/{odlFolder}/{fNameOdl}"; fileContent = item.Value; // scrivo file ultima richiesta setup locFile = Path.Combine(basePath, "temp", fNameOdl); taskOk = SendOdlActFile(locFile, remFile, fileContent); if (taskOk) { taskVal = $"File uploaded: {item.Key} --> {item.Value} | locFile: {locFile} | remFile: {remFile}"; } else { lgError($"Error in startSetup | fileUpload | locFile: {locFile} | remFile: {remFile}"); } } break; case taskType.endProd: bool okRemove = RemPlaceholder(RemoteBaseDir, fNameOdl); if (okRemove) { taskVal = $"Cleaned CurrOdlFile: {item.Key} --> {item.Value} | remDir: {RemoteBaseDir} | fName: {fNameOdl}"; } else { lgError($"Error in CurrOdlFile | remDir: {RemoteBaseDir} | fName: {fNameOdl}"); } break; default: taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; lgInfo($"Chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}"); break; } // aggiungo task SE svolto! if (!string.IsNullOrEmpty(taskVal)) { taskDone.Add(item.Key, taskVal); } } return taskDone; } /// /// Effettua processing CUSTOM x FTP: /// - prende ogni conf specifica /// - esegue step /// - registra eventuali DynData da salvare /// public override void processCustomTaskLF() { lgInfo($"Richiesto processCustomTaskLF"); // verifico di avere compiti da svolgere... if (currFtpTaskList != null && currFtpTaskList.ListTask != null && currFtpTaskList.ListTask.Count > 0) { foreach (var srvFtp in currFtpTaskList.ListTask) { // verifico eventuale veto all'esecuzione... if (ActionEnabled(srvFtp)) { // imposto nuovo veto... ActionResetVeto(srvFtp); // ora setup server FTP x item... ftpClientMan = new Manager(srvFtp.ServerAddr, srvFtp.ConnUser, srvFtp.ConnPasswd, srvFtp.RawCert, srvFtp.SkipCert); // test server ok... if (ftpClientMan.ServerOk()) { int stepDone = 0; string srvType = ftpClientMan.ServerType(); lgTrace($"Connesso a server {srvType} | {srvFtp.ServerAddr} | inizio processing {srvFtp.StepsList.Count} steps"); // ciclo tra i vari steps! foreach (var step in srvFtp.StepsList) { bool fatto = doStep(step); stepDone += fatto ? 1 : 0; } lgInfo($"Completata esecuzione steps FTP | {srvFtp.ActionId} | {stepDone}/{srvFtp.StepsList.Count} Done/Req"); } else { // FixMe ToDo verificare se necessario... //connectionOk = false; //tryDisconnect(); lgError($"Impossibile connettersi al server {srvFtp.ServerAddr}"); } } else { lgTrace($"Saltata esecuzione {srvFtp.ActionId} | veto attivo"); } } } lastReadPLC = DateTime.Now; } /// /// Effettua lettura semafori principale Parametri da /// aggiornare x display in form /// public override void readSemafori(ref newDisplayData currDispData) { DateTime adesso = DateTime.Now; // procedo solo se ftp è configurato (altrimenti inutile controllare...)ù if (ftpClientMan.IsConfigured) { // salto se fosse attivo il veto ping... if (lastPING.AddSeconds(vetoPingSec) < adesso) { // lo stato è come ping machine, x ora puntato a IP unico (WiFi?) byte[] MemBlock = new byte[2]; try { currDispData.semIn = Semaforo.SV; // in primis salvo data ping comunque... lastPING = adesso; // salvo esito ping bool pingOK = testPingMachine == IPStatus.Success; addTest(pingOK); bool ftpOk = ftpClientMan.ServerOk(); // se passa il check ping + folder faccio il resto... if (pingStatusOk() && ftpOk) { // salto se fosse attivo il veto controllo folder... if (lastCheckDir.AddSeconds(vetoCheckDirSec) < adesso) { lastCheckDir = adesso; // verifico SE HO una folder da ODL in currProdData e se è disponibile... string reqFolder = getCurrProdData("setComm", ""); if (!string.IsNullOrEmpty(reqFolder)) { // verifico se ci sia... ActionConfig currAct = new ActionConfig(); var currActParam = new Dictionary(); // compongo remDir dai 2 parametri... currActParam.Add("RemoteDir", $"{RemoteBaseDir}/{reqFolder}"); currAct = new ActionConfig() { Id = "01", Description = "Verifica esistenza directory", Action = ActType.CheckDir, ParamList = currActParam }; //eseguo step... bool dirOk = doStep(currAct); if (dirOk) { numErroriCheck = numErroriCheck > 0 ? numErroriCheck-- : 0; } else { lgInfo($"Rilevata mancanza folder ODL: inizio ripristino tramite task setComm"); numErroriCheck++; // altrimenti eseguo task2exe x crearla... Dictionary task2ExeSetOdl = new Dictionary(); task2ExeSetOdl.Add($"setComm", reqFolder); var res = executeTasks(task2ExeSetOdl); } } } // se supero soglia errori lettura --> disconnetto e resetto if (numErroriCheck > maxErroriCheck) { lgError($"numErroriCheck: {numErroriCheck} --> disconnessione adapter con tryDisconnect"); numErroriCheck = 0; connectionOk = false; tryDisconnect(); } else { connectionOk = true; } lastReadPLC = adesso; lastWatchDog = adesso; } else { connectionOk = false; } if (connectionOk) { B_input = 3; // aggiungo NON emergenza... B_input += (1 << 7); } else { B_input = 0; } } catch { currDispData.semIn = Semaforo.SR; } } } } public override void startAdapter(bool resetQueue) { base.startAdapter(resetQueue); // 2023.09.05 imposto anche primo ping e check disconnected... DateTime adesso = DateTime.Now; lastWatchDog = adesso; //lastPING = adesso; lastReadPLC = adesso; lastDisconnCheck = adesso; // faccio un primo check POST ritardo tryConnect(); } /// /// Override connessione /// public override void tryConnect() { bool doLog = (verboseLog || periodicLog); lgDebug($"FTP: tryConnect step 01 | connectionOk: {connectionOk}"); if (!connectionOk) { //// resetto coda... //PingQueue = new DataQueue("000", "PingQueue", false); // controllo che il ping sia stato tentato almeno pingTestSec fa... if (DateTime.Now.Subtract(lastPING).TotalSeconds > vetoPingSec) { if (doLog) { lgInfo("FTP: ConnKO - tryConnect"); } lgDebug("FTP: tryConnect step 04"); lgDebug("FTP: Reset PingQueue"); bool pingOK = testPingMachine == IPStatus.Success; addTest(pingOK); // se passa il ping faccio il resto... if (pingStatusOk()) { // in primis salvo data ping... lastPING = DateTime.Now; connectionOk = true; queueInEnabCurr = true; lgInfo("FTP - ping OK"); } else { // loggo no risposta ping ... lgError("FTP - ping KO"); } } } } /// /// Override disconnessione /// public override void tryDisconnect() { lgInfo("Richiesta disconnessione adapter FTP!"); connectionOk = false; queueInEnabCurr = false; } #endregion Public Methods #region Protected Methods /// /// Imposta la memoria PLC in modo forzato (es x oggetti gestiti da FTP come setComm) /// protected override void forceMemMap() { // simulo setup mappa memoria in scrittura... memMap = new plcMemMapExt(); // area READ Dictionary ftpMemRead = new Dictionary(); ftpMemRead.Add("FtpSync", new dataConfTSVC() { description = "Last FTP sync", name = "FtpSync", tipoMem = plcDataType.String, displOrdinal = 10 }); memMap.mMapRead = ftpMemRead; // area WRITE Dictionary ftpMemWrite = new Dictionary(); ftpMemWrite.Add("setComm", new dataConf() { description = "Commessa", name = "setComm", tipoMem = plcDataType.String, displOrdinal = 1 }); ftpMemWrite.Add("setArt", new dataConf() { description = "Articolo", name = "setArt", tipoMem = plcDataType.String, displOrdinal = 2 }); ftpMemWrite.Add("setPzComm", new dataConf() { description = "Qta Richiesta", name = "setPzComm", tipoMem = plcDataType.Int, displOrdinal = 3 }); memMap.mMapWrite = ftpMemWrite; // eseguo setup + invio info configurazione... setupMemMap(); } #endregion Protected Methods #region Private Fields private static Stopwatch sw = new Stopwatch(); /// /// Ultima verifica presenza dir corrente /// private DateTime lastCheckDir = DateTime.Now.AddHours(-1); /// /// Dimensione coda di ping x valutazione /// private int maxQueuePing = 11; /// /// Coda degli esiti di ping x calcolo stato macchina /// private DataQueue PingQueue = new DataQueue("000", "PingQueue", false); private int PoweroffTimeoutSec = 100; /// /// Dizionario dei divieti di esecuzione x i vari step /// private Dictionary StepsVeto = new Dictionary(); /// /// Periodo veto controllo directory FTP corrente /// private int vetoCheckDirSec = 5; /// /// Veto controllo status x log... /// private DateTime vetoCheckStatus = DateTime.Now; #endregion Private Fields #region Private Properties /// /// Oggetto configurazione gestione FTP /// private FtpTaskList currFtpTaskList { get; set; } = new FtpTaskList(); /// /// CLient connessioni FTP /// private Manager ftpClientMan { get; set; } = new Manager("", "", "", "", false); /// /// Directpry remota di abse /// private string RemoteBaseDir { get; set; } = ""; #endregion Private Properties #region Private Methods /// /// Verifica se l'azione sia permessa o in stato veto a tempo /// /// /// private bool ActionEnabled(FtpActConf currAct) { bool enabled = true; // se veto presente if (StepsVeto.ContainsKey(currAct.ActionId)) { // controllo scadenza enabled = StepsVeto[currAct.ActionId] < DateTime.Now; } return enabled; } /// /// Imposta veto azione corrente /// /// /// private bool ActionResetVeto(FtpActConf currAct) { bool fatto = false; if (StepsVeto.ContainsKey(currAct.ActionId)) { StepsVeto[currAct.ActionId] = DateTime.Now.AddSeconds(currAct.ReExecVeto); } else { StepsVeto.Add(currAct.ActionId, DateTime.Now.AddSeconds(currAct.ReExecVeto)); } return fatto; } private 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); } } /// /// Esegue l'azione configurata /// /// /// /// private bool doStep(ActionConfig step) { bool fatto = false; string remoteVal = ""; string localVal = ""; string sVal = ""; string actKey = ""; string actVal = ""; // faccio switch in base al tipo di azione da eseguire... switch (step.Action) { case ActType.CheckDir: if (step.ParamList != null && step.ParamList.Count > 0) { sw.Restart(); remoteVal = step.ParamList["RemoteDir"] ?? ""; //verifico dir remota fatto = ftpClientMan.DirExists(remoteVal); } else { lgError("Error: missing parameters!"); } sw.Stop(); if (fatto) { lgInfo($"Check RemDir: {remoteVal} | {sw.ElapsedMilliseconds:N1} ms"); } break; case ActType.CheckFile: break; case ActType.CreateDir: if (step.ParamList != null && step.ParamList.Count > 0) { sw.Restart(); remoteVal = step.ParamList["RemoteDir"] ?? ""; //verifico dir remota bool dirExist = ftpClientMan.DirExists(remoteVal); if (dirExist) { lgTrace("Error: Folder already exists!"); } else { fatto = ftpClientMan.CreateDir(remoteVal); } } else { lgError("Error: missing parameters!"); } sw.Stop(); if (fatto) { lgInfo($"Directory {remoteVal} created!| {sw.ElapsedMilliseconds:N1} ms"); } break; case ActType.DelDir: break; case ActType.DelFile: break; case ActType.DownloadDir: break; case ActType.DownloadFile: break; case ActType.GenRandomDir: break; case ActType.ListContent: break; case ActType.MirrorDirL2R: break; case ActType.MirrorDirR2L: // eseguo mirroring directory actKey = "FtpSync"; actVal = "SRC --> DEST | Size"; if (step.ParamList != null && step.ParamList.Count > 1) { sw.Restart(); remoteVal = step.ParamList["RemoteDir"] ?? ""; localVal = step.ParamList["LocalDir"] ?? ""; // verifico esistenza dir locale... if (!Directory.Exists(localVal)) { Directory.CreateDirectory(localVal); } //verifico dir remota var preTest = ftpClientMan.DirExists(remoteVal); if (preTest) { // chiamo metodo MIRROR x calcolare esattamente se ci siano stati // download di sync... var mirResult = ftpClientMan.MirrorRemoteDir(localVal, remoteVal, FluentFTP.FtpFolderSyncMode.Mirror); // ciclo cercando eventuali info da emttere in DynData... foreach (var result in mirResult) { // processo solo se size > 0... if (result.Size > 0 && result.IsDownload && result.IsSuccess && !result.IsSkipped) { string objSize = MeasureUtils.SizeSuffix(result.Size, 3); actVal = $"Rem2Loc | {result.Name} | {objSize} | {result.RemotePath}"; sVal = $"{actKey} | {actVal}"; accodaFLog(sVal, qEncodeFLog(actKey, actVal)); } else { lgTrace($"Skipped sync | {actVal}"); } } // risultato sintetico come successi... fatto = mirResult != null && mirResult.Where(x => !x.IsSuccess).Count() == 0; if (!fatto) { lgError($"Error: {remoteVal} NOT mirrored!"); } } else { lgError($"Dir remota non trovata! RemDir: {remoteVal}"); } } else { lgError("Error: missing parameters!"); } sw.Stop(); if (fatto) { lgInfo($"Mirror Rem2Loc | RemDir: {remoteVal} | {sw.ElapsedMilliseconds:N1} ms"); } break; case ActType.PingServer: break; case ActType.RemoveFileByName: string fName2Del = ""; int numRem = 0; if (step.ParamList != null && step.ParamList.Count > 1) { sw.Restart(); remoteVal = step.ParamList["RemoteDir"] ?? ""; fName2Del = step.ParamList["FileName2Del"] ?? ""; //verifico dir remota fatto = ftpClientMan.DirExists(remoteVal); if (fatto) { // recupero elenco di TUTTI i file presenti List resList = ftpClientMan.GetRemoteList(remoteVal, true); List list2del = new List(); // cerco tutti i file che indicano ODL attivo e li elimino foreach (var flItem in resList) { if (flItem.Type == FluentFTP.FtpObjectType.File && flItem.Name.EndsWith(fName2Del)) { list2del.Add(flItem); } } // elimino quelli trovati if (list2del.Count > 0) { var fList = list2del.Select(x => x.FullName).ToList(); numRem = ftpClientMan.DeleteFileList(fList); } } } else { lgError("Error: missing parameters!"); } sw.Stop(); if (fatto) { lgInfo($"RemoveFileByName | path: {remoteVal} | name: {fName2Del} | # del: {numRem} | {sw.ElapsedMilliseconds:N1} ms"); } break; case ActType.UploadDir: break; case ActType.UploadFile: if (step.ParamList != null && step.ParamList.Count > 1) { sw.Restart(); localVal = step.ParamList["LocalFile"] ?? ""; remoteVal = step.ParamList["RemoteFile"] ?? ""; //verifico dir remota string remoteDir = remoteVal.Substring(0, remoteVal.LastIndexOf("/")); bool dirExist = ftpClientMan.DirExists(remoteDir); if (!dirExist) { fatto = ftpClientMan.CreateDir(remoteDir); } fatto = ftpClientMan.SendFile(localVal, remoteVal); if (!fatto) { lgError($"Error: {localVal} NOT uploaded!"); } } else { lgError("Error: missing parameters!"); } sw.Stop(); if (fatto) { lgInfo($"Upload File: {remoteVal} | {sw.ElapsedMilliseconds:N1} ms"); } break; default: break; } return fatto; } /// /// Effettuo lettura file di conf /// /// private void loadFtpConfFile(string fileName) { string jsonFullPath = Path.Combine(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(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!"); } } } /// /// Calcola status ping: /// - se ha ‹ 50% coda richiesta --› true /// - se ha › 50% coda richiesta --› true se è maggior parte a 1 (true) /// /// private bool pingStatusOk() { bool answ = false; 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 check: {answ} per mancanza dati minimi test"); } return answ; } /// /// Rimuove eventuali file placeholder di ODL corrente preesistenti /// /// /// private bool RemPlaceholder(string remDir, string fNameOdl) { bool fatto = false; try { Dictionary currActParam = new Dictionary(); currActParam.Add("RemoteDir", remDir); currActParam.Add("FileName2Del", fNameOdl); ActionConfig currAct = new ActionConfig() { Id = "01", Description = "Clean Curr ODL Files", Action = ActType.RemoveFileByName, ParamList = currActParam }; // eseguo step... fatto = doStep(currAct); } catch (Exception exc) { lgError($"Eccezione in RemPlaceholder{Environment.NewLine}{exc}"); } return fatto; } /// /// Invia il file dell'ODL attivo /// /// /// /// private bool SendOdlActFile(string locFile, string remFile, string fileContent) { bool taskOk = false; Dictionary currActParam = new Dictionary(); // creo file locale File.WriteAllText(locFile, fileContent); // invio file x ODL attivo currActParam.Add("LocalFile", locFile); currActParam.Add("RemoteFile", remFile); ActionConfig currAct = new ActionConfig() { Id = "01", Description = "Upload File", Action = ActType.UploadFile, ParamList = currActParam }; // eseguo step... taskOk = doStep(currAct); return taskOk; } #endregion Private Methods } }