using IOB_UT; using Newtonsoft.Json; using OpenQA.Selenium; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Firefox; using System; using System.Collections.Generic; using System.IO; using System.Net.NetworkInformation; using System.Threading; using System.Threading.Tasks; namespace IOB_WIN { /// /// Generica classe per implementare WebPageScraping (scaricamento web pages anche js-based x recupero informazioni) /// public class IobWPS : IobGeneric { /* -------------------------------------------------------------------------------- * Controlli dotati di GENERICA pagina WEB in cui cercare e recuperare informazioni * * - il file di conf deve contenere l'URL di base * - il file di conf deve contenere COSA cercare (es il "contenitore" del dato da estrarre) * * -------------------------------------------------------------------------------- */ /// /// Vettore della frequenza di ogni status trovato... invio ogni 100 rilevazioni (modulo 100, resto == 1) /// protected Dictionary freqUnknStatus = new Dictionary(); /// /// Pagina web da scaricare /// protected string baseUri = "http://127.0.0.1"; /// /// Array di configurazione degli oggetti da cercare x decodifica e recupero info /// protected Dictionary dataLocatorLUT; /// /// Driver per gestione chiamate crawling/scraping /// protected IWebDriver driver; /// /// Oggetti decodificati da pagina /// protected MonitoredItemsConf monitoredItems; /// /// Elementi da recuperare nella apgina web /// protected IWebElement element; /// /// Estende l'init della classe base... /// /// /// public IobWPS(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) { lgInfo("INIT IobWPS"); reloadAdapterConf(); } /// /// Ricarica conf adapter... /// private void reloadAdapterConf() { lgInfo("BEGIN reloadAdapterConf"); // inizializzo LUT decodifica string jsonConf = getOptPar("LUT_CONF"); if (jsonConf != "") { StreamReader reader = new StreamReader($"DATA/CONF/{jsonConf}"); string jsonData = reader.ReadToEnd(); if (jsonData != "") { try { monitoredItems = JsonConvert.DeserializeObject(jsonData); // salvo baseUri baseUri = monitoredItems.SrvData.baseUri; lgInfo($"baseUri = {baseUri}"); // imposto a zero la bitmap x riavvio! B_input = 0; // FORZO invio dati... accodaSigIN(); // loggo! lgInfo($"init input bitmap to zero: {B_input}"); } catch (Exception exc) { lgError(exc, "Eccezione in decodifica conf json"); } } } lgInfo("DONE reloadAdapterConf"); } #region Metodi specifici (da verificare/completare in implementazione) public override void startAdapter(bool resetQueue) { // in primis RICARICO conf specifica... reloadAdapterConf(); // continuo con start... base.startAdapter(resetQueue); } /// /// Override x chiusura driver... /// /// /// public override void stopAdapter(bool tryRestart, bool forceDequeue) { try { // in primis chiudo driver... if (driver != null) { driver.Quit(); } } catch (Exception exc) { lgError(exc, "Eccezione in tryDisconnect"); } // continuo base.stopAdapter(tryRestart, forceDequeue); } /// /// Connessione /// public override void tryConnect() { // controllo ping --> segno connected... connectionOk = (testPing == IPStatus.Success); if (connectionOk) { try { var t = TaskEx.Run(() => startDriver()); //t.Wait(); // vecchia modalità sincrona //startDriver(); } catch (Exception exc) { lgError(exc, "Eccezione in tryConnect"); } } else { // aspetto prima di riprovare... Thread.Sleep(200); } } /// /// Avvio del WebDriver /// private void startDriver() { if (monitoredItems.SrvData.driverName == "CHROME") { lgInfo("Starting CHROME Driver"); // preparo opzione headless x CHROME var o = new ChromeOptions(); o.AddArgument("headless"); ChromeDriverService service = ChromeDriverService.CreateDefaultService(Environment.CurrentDirectory); service.HideCommandPromptWindow = true; driver = new ChromeDriver(service, o); //driver = new ChromeDriver(Environment.CurrentDirectory, o); } else { lgInfo("Starting FIREFOX Driver"); // preparo opzione headless x CHROME var o = new FirefoxOptions(); o.AddArgument("-headless"); FirefoxDriverService service = FirefoxDriverService.CreateDefaultService(Environment.CurrentDirectory); service.HideCommandPromptWindow = true; driver = new FirefoxDriver(service, o); //driver = new FirefoxDriver(Environment.CurrentDirectory, o); } // aggiungo timeout x JScripts driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10); driver.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(10); // imposto pagina di acquisizione driver.Navigate().GoToUrl(baseUri); } /// /// Disconnessione /// public override void tryDisconnect() { connectionOk = false; try { // in primis chiudo driver... if (driver != null) //if (driver != null && driver.WindowHandles.Count > 0) { driver.Quit(); } } catch (Exception exc) { lgError(exc, "Eccezione in tryDisconnect"); } } /// /// Effettua processing del recupero delle OVERRIDE (spindle, feedrate, rapid) /// public override void processOverride() { } /// /// Recupero dati dinamici in formato dictionary /// /// public override Dictionary getDynData() { lgInfo("Chiamata getDynData x IOB WebPageScraping!"); Dictionary outVal = new Dictionary(); try { /* ---------------------------------------------------------- * Recupero dalla TUTTE le chiavi richieste... * */ string cKey = ""; string cVal = ""; // processo tutti i DynData... foreach (var item in monitoredItems.DynData) { // cerco elemento indicato element = driver.FindElement(By.Id(item.val)); cVal = element.Text; // verifico nome o key... if (item.name != "") { cKey = item.name; } else { element = driver.FindElement(By.Id(item.key)); cKey = element.Text; } // controllo se devo inviare (per tipo di dato, x scadenza) if (monItem2Send(cVal, item)) { item.actVal = cVal; item.DTScad = DateTime.Now.AddSeconds(item.sPeriod); // accodo! outVal.Add(cKey, cVal); } } } catch (Exception exc) { lgError(exc, "Errore in getDynData x IOB WPS"); } return outVal; } /// /// Effettua lettura dati di status da apposite variabili /// public override void readSemafori() { // init a zero... B_input = 0; // ciclo! try { string cKey = ""; string cVal = ""; // IPOTESI: un UNICO oggetto decodifica status if (monitoredItems.Status.Count == 1) { var item = monitoredItems.Status[0]; // cerco elemento indicato element = driver.FindElement(By.Id(item.val)); cKey = element.Text; // verifico se mancasse il mapping... if (!item.codeMapping.ContainsKey(cKey)) { processUnknStatus(cKey); } else { // ora decodifico da variabile status a valore secondo impostazione "codeMapping" cVal = item.codeMapping[cKey]; B_input = int.Parse(cVal, System.Globalization.NumberStyles.HexNumber); } } } catch (Exception exc) { lgError(exc, "Errore in getDynData x IOB WPS"); } } /// /// Processo stati unknown... /// /// private void processUnknStatus(string cKey) { // cerco se avevo già una key nella dictionary... if (freqUnknStatus.ContainsKey(cKey)) { freqUnknStatus[cKey]++; // se è 1 ogni 100 (%100, resto ==1) --> loggo... if (freqUnknStatus[cKey] % 100 == 1) { lgInfo($"Errore in decodifica status: MAPPING non trovato per {cKey} | freq: {freqUnknStatus[cKey]}"); // accodo come invio di tipo FLOG... string sVal = string.Format("[UnknStatus] {0}, freq: {1}", cKey, freqUnknStatus); // chiamo accodamento... accodaFLog(sVal, qEncodeFLog("UnknStatus", sVal)); } } else { // creo chiave con freq = 1 freqUnknStatus.Add(cKey, 1); // log iniziale lgInfo($"Errore in decodifica status: MAPPING non trovato per {cKey}"); } } #endregion } }