giovedì 22 novembre 2018

Bash script come cgi in Apache

Cosa succede quando scrivi uno script bash che funziona bene e non vuoi convertirlo in Php? Semplice...ritorni indietro di venti anni e lo fai diventare un cgi script

Per prima cosa si devono abilitare gli script CGI in Apache

a2enmod cgi

service apache2 restart

in Debian la directory di default per i CGI e' in /usr/lib/cgi-bin...si copia quindi lo script e lo si rende eseguibile
Per prima cosa c'e' da dire che lo script non deve rispondere in modo arbitrario (per esempio con un semplice testo) ma con un file html altrimenti verranno generati errori del tipo 500 di output non correttamente formattato

In Bash si possono leggere anche le variabile GET passate sulla URL e cio' mediante IFS
Nell'esempio sottostante e' prevista una sola variabile (che corrisponde ad un id numerico) e che e' stata salvata nell'array parm all'indice 1
----------------------------------------------------
#!/bin/bash

echo "Content-type: text/html"
echo ""

echo '<html>'
echo '<head>'
echo '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
PATH="/bin:/usr/bin:/usr/opt/bin"
export $PATH

saveIFS=$IFS
IFS='=&'
parm=($QUERY_STRING)
IFS=$saveIFS


stringa="$(xidel --silent --extract "//img/@src" "http://xxxxxxxxxxxx.it/?utf8=true&size=micro&mode=double&idc=${parm[1]}" | grep idraulico | awk 'FNR==1')"


echo '</head>'
echo '<body>'
#echo ${parm[1]}
file="$(basename $stringa)"

echo $file

echo '</body>'
echo '</html>'

exit 0
----------------------------------------------------

Xidel

Xidel e' un comodo programma a linea di comando che permette di estrarre informazioni da un file HTML. Non esiste nei repository di Debian ma il pacchetto .deb puo' essere comodo scaricato da questo link http://www.videlibri.de/xidel.html

Nell'esempio sottostante viene richiamata una pagina html da cui estrarre un link (che varia in modo non predefinito) in modo automatico

in pratica xidel richiama il file dall'indirizzo xxxxx.wp, estrae tutti gli HRef incontrati, si estraggono solo quelli che hanno la stringa "filename", poi con awk si prende solo il primo della lista e con sed si eliminano dei caratteri (in questo caso ..)


#!/bin/bash
cd "$(dirname "$0")";

stringa="$(xidel --silent --extract "//a/@href" xxxxxxxxxxxx.wp | grep filename | awk 'FNR==1' | sed 's/..//')"
echo "${stringa}"

martedì 20 novembre 2018

Estrarre dati da un XML a linea di comando

Per estrarre dati in modo semplice da un XML una soluzione puo' essere xml_grep
Questo comando e' incluso nel pacchetto Debian xml-twig-tools

si procede quindi con

apt-get install xml-twig-tools

supponiamo di avere un XML tipo

---------------
<?xml version='1.0' encoding='UTF-8'?>
<alert xmlns="urn:oasis:names:tc:emergency:cap:1.2">
  <identifier>XXXXXX</identifier>
  <sender>XXXXXX</sender>
  <sent>2018-11-14T15:24:00+01:00</sent>
  <status>Actual</status>
  <msgType>Alert</msgType>
  <scope>Public</scope>
  <note>XXXXXXX</note>
  <info>
    <category>Met</category>
    <event>XXXXX</event>
............
---------------
e che si voglia estrarre il contenuto di <note>
si puo' usare la semplice sintassi

xml_grep 'note' test.xml --text_only

lunedì 19 novembre 2018

Scheletro di progetto NodeJS

I comandi di base per creare un progetto NodeJS

mkdir test
cd test
npm init --yes
npm install request --save (viene installato via npm il modulo "request" nella subdir /node_modules)

si crea quindi il file del programma (per esempio app.js) e si lo si mette in esecuzione con 
node app.js

HTTP Async request in Alexa

Per fare interagire Alexa con server esterni la cosa piu' semplice e' usare il modulo http perche' e' un built-in e non necessita di supporto esterno. Si dichiara l'uso all'inizio della Lambda function

--------------------------------------------------------------------
const Alexa = require('ask-sdk');
var http = require('http'); 
--------------------------------------------------------------------

si crea poi una funzione di richiesta http. Attenzione: questa funzione e' di tipo asincrono e si deve inserire la Promise per fare in modo che il risultato entri nello scope della funzione principale
--------------------------------------------------------------------
function httpGet() {
  return new Promise(((resolve, reject) => {
    var options = {
        host: '80.211.xxxx,xxxx',  //solo ip o nome dominio ..niente http od https prima
        port: 80,
        path: '/dpc.php',
        method: 'GET',
    };
    
    const request = http.request(options, (response) => {
      response.setEncoding('utf8');
      let returnData = '';

      response.on('data', (chunk) => {
        returnData += chunk;
      });

      response.on('end', () => {
        resolve(returnData);
        console.log("returnData "+returnData);
      });

      response.on('error', (error) => {
        reject(error);
      });
    });
    request.end();
  }));
}
--------------------------------------------------------------------

Il custom intent che deve gestire la funzione asincrona sopra indicata deve essere modificato ponendo async nell'handler e deve aspettare il ritorno della funzione httpGet prima di procedere in modo da popolare in modo corretto la variabile response
--------------------------------------------------------------------
const geo = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return (request.type === 'IntentRequest'
        && request.intent.name === 'geo');
  },
  
  
  async handle(handlerInput) {
  const response = await httpGet();

  const { intent } = handlerInput.requestEnvelope.request;
  const activity = intent.slots.luogo.value;
  var speechOutput = response;


  if (activity == "firenze")
      {
        //speechOutput = "firenze si trova in toscana";
      }
  
  if (activity == "milano")
      {
        speechOutput = "milano si trova in lombardia"
      }
  

    return handlerInput.responseBuilder
      .speak(speechOutput)
      .getResponse();
  },
};
--------------------------------------------------------------------

mercoledì 14 novembre 2018

Alexa Skills



Per usare Alexa Skill in Europa si deve usare la zona AWS denominata Ireland

Per creare un custom intent in lambda NodeJS che legga le variabili passate da Alexa ASK si procede cosi

il modello prevede un custom intent di nome geo che ha uno slot  (ovvero una variabile) di nome luogo
---------------------------------------------------------------------------
{
    "interactionModel": {
        "languageModel": {
            "invocationName": "geografia",
            "intents": [
                {
                    "name": "AMAZON.CancelIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.HelpIntent",
                    "samples": [
                        "aiuto "
                    ]
                },
                {
                    "name": "AMAZON.StopIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.NavigateHomeIntent",
                    "samples": []
                },
                {
                    "name": "geo",
                    "slots": [
                        {
                            "name": "luogo",
                            "type": "AMAZON.City"
                        }
                    ],
                    "samples": [
                        "dimmi dove si trova {luogo}",
                        "dimmi dove è {luogo}"
                    ]
                }
            ],
            "types": []
        }
    }
}
---------------------------------------------------------------------------

il custom intent deve intercettare una richiesta di tipo IntentRequest e di nome geo
le righe in azzurro servono a leggere la variabile luogo che e' passata da ASK (via JSON) e la mettono nella variabile JS ac
---------------------------------------------------------------------------
const geo = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return (request.type === 'IntentRequest'
        && request.intent.name === 'geo');
  },
  handle(handlerInput) {
    

  const { intent } = handlerInput.requestEnvelope.request;
  const ac = intent.slots.luogo.value;
  var speechOutput = "  ";
  
  if (ac == "firenze")
      {
        speechOutput = "firenze si trova in toscana"
      }
  
  if (ac == "milano")
      {
        speechOutput = "milano si trova in lombardia"
      }
  

  console.log(ac);

    //const speechOutput = activity;

    return handlerInput.responseBuilder
      .speak(speechOutput)
      .getResponse();
  },
};
---------------------------------------------------------------------------

i messaggi di console.log si leggono si Amazon CloudWatch Logs.Dalla finestra della funzione di Lambda in alto ci sono i tab Configurazione e Monitoraggio..si clicca Monitoraggio e poi visualizza log in CloudWatch



Per fare interagire Alexa con informazioni derivanti da un server esterno mediante richieste http
(lo script test.php e' semplicemente un echo("stringa");

---------------------------------------------------------------------------

var http = require('http'); 

http.get('http://80.211.xxx,xxx/test.php', (resp) => {
  let data = '';

  resp.on('data', (chunk) => {
    data += chunk;
  });

  // The whole response has been received. Print out the result.
  resp.on('end', () => {
    //console.log(JSON.parse(data).explanation);
    console.log(data);
  });

}).on("error", (err) => {
  console.log("Error: " + err.message);
});
---------------------------------------------------------------------------

martedì 13 novembre 2018

OpenWRT su GL.Inet MT300N-V2

Rispetto al GL.Inet AR150  montare OpenWRT su  MT300N-V2 e' leggermente differente


Si parte impostantdo il portatile su 192.168.1.2. Si inserisce il cavo Ethernet su  LAN del M300, si preme in tasto reset e si connette l'alimentazione USB. Dopo 3 secondi (o quando il led rosso non lampeggia piu') si lascia il tasto reset e ci si connette al 192.168.1.1 e si effettua l'upload del firmware openwrt-18.06.0-ramips-mt76x8-gl-mt300n-v2-squashfs-sysupgrade.bin

A questo punto c'e' la differenza con AR150. Non viene attivata di default l'access point per cui si deve continuare la configurazione mantenendo collegato il cavo Ethernet sulla porta LAN e dopo il reboot si deve usare LuCi all'indirizzo 192.168.1.1

Debugger integrato ESP32S3

Aggiornamento In realta' il Jtag USB funziona anche sui moduli cinesi Il problema risiede  nell'ID USB della porta Jtag. Nel modulo...