Utilizzare il REST per inviare dati nel cloud

» Home » Article » Utilizzare il REST per inviare dati nel cloud
  1. Home
  2. Knowledge Base
  3. Controllori SlimLine
  4. Esempi
  5. Utilizzare il REST per inviare dati nel cloud

Web Service Restful

Se sei uno sviluppatore Web avrai sentito sicuramente parlare di Web Service Restful, REST definisce un insieme di principi per la progettazione di un sistema distribuito in alternativa ad altre specifiche di computing distribuito come SOAP. Basato su un architettura Client-Server dove la comunicazione tra utente del servizio (client) e servizio (server) deve essere senza stato tra le richieste, in pratica ogni richiesta è come se fosse la prima richiesta e non è correlata ad una richiesta precedente. Puoi eseguire il download di un progetto in cui si trova sia il programma client da installare  su SlimLine che il programma server scritto in PHP.


Blocco funzione RESTClient

Questo blocco funzione gestisce la connessione verso un server REST con protocollo HTTP. In HostAddress occorre definire l’indirizzo IP o l’URL del server è possibile definire anche l’HostName che sarà utilizzato nella richiesta (Di solito è uguale a HostAddress). In HostPort si definisce la porta del servizio (Di solito è la standard HTTP 80) ed in Page si definisce lo script di gestione del servizio.

La connessione al server REST è delegata al FB HTTPClient che deve essere istanziato nel proprio programma ed il cui indirizzo di istanza deve essere passato al FB. La comunicazione con il server REST è in formato JSON, quindi anche i dati scambiati con il server sono codificati in JSON.

Il FB ad ogni tempo definito in HBitTime invia un messaggio di heartbeat al server REST per permettere di controllare il corretto funzionamento del servizio anche in assenza di messaggi da inviare al server. In questo modo è garantito il controllo della connessione con il server indicata dalla attivazione dell’uscita RSvcOn.

Per garantire la storicizzazione di tutti gli eventi da inviare al server anche se molto rapidi il FB ne gestisce il buffering appoggiandosi ad un FIFO. La gestione del FIFO è delegata al FB FIFOFile_v1 che deve essere istanziato nel proprio programma ed il cui indirizzo di istanza deve essere passato al FB. Caricando i dati nel FIFO saranno trasferiti nel suo buffer su disco abbinandoli ad un timestamp in GMT, poi inviati al server. Il buffering garantisce che anche in assenza di connessione al server i dati non vengano persi, al ripristinarsi della connessione saranno inviati con il relativo timestamp.

Test funzionamento

Per testare il funzionamento del servizio REST occorre disporre di un server nel cloud che risponda ai messaggi inviati dal FB in esecuzione su di un sistema SlimLine. Abbiamo messo in servizio su un hosting gratuito, altervista.org, che consigliamo a tutti quelli che desiderano cimentarsi con il REST un semplice script in PHP.

Per il test quindi basterà trasferire su di un sistema SlimLine il programma di esempio che si collegherà al nostro script. A scopo didattico abbiamo volutamente  ridotto al minimo le operazioni, il programma di test si limita ad inviare al server REST due variabili (Divident e Divisor). Lo script in PHP sul server esegue la divisione e ritorna il risultato che viene salvato in una variabile sullo SlimLine.


Programma SlimLine

Sviluppato in linguaggio ST (Structured Text) esegue il FB RESTClient inviando i dati al server REST sul cloud.

Inizializzazione variabili

In testa al programma troviamo la sezione che si occupa di inizializzare tutte le variabili. Siccome il programma RESTCommunication è inserito nella task di back dello SlimLine e viene eseguito ciclicamente, l’inizializzazione verrà eseguita solo al primo  loop.

IF (SysFirstLoop) THEN
  TimeBf:=SysGetSysTime(TRUE); (* Time buffer (uS) *)
  REST.SpyOn:=TRUE; (* Spy On *)

  REST.FIFOFile:=ADR(FIFO); (* FIFO on file *)
  REST.FIFOFilename:=ADR('C:/REST.bin'); (* Path and name of FIFO file *)
  REST.FIFOSize:=1000; (* FIFO file size *)
  REST.FIFOIDx:=ADR(FIFOIDx); (* FIFO indexes *)

  REST.HostAddress:=ADR('www.slimline.altervista.org'); (* Host address server REST *)
  REST.HostName:=REST.HostAddress; (* Host name server REST *)
  REST.Page:=ADR('Utilities/RESTSvcDemo/RESTSvc.php'); (* REST server script *)
  REST.HostPort:=80; (* REST server port *)

  REST.HTTPClient:=ADR(HTTP); (* HTTP Client *)
  REST.HBitTime:=5; (* Heartbeat time (S) *)
  REST.BLength:=512; (* REST Request/Answer buffers length *)
END_IF;

(* Here the REST client is managed, it's always enabled. *)

REST(Enable:=TRUE); (* REST client management *)

Viene attivato lo spionaggio del FB REST.SpyOn:=TRUE che ci permetterà di analizzare tramite la console di spionaggio il funzionamento del FB.

Viene indicato l’indirizzo della istanza di gestione FIFO REST.FIFOFile:=ADR(FIFO), il file di appoggio dei dati REST.FIFOFilename:=ADR(‘C:/REST.bin’) e la sua dimensione massima (Il FIFO ha comunque un comportamento circolare raggiunto il limite viene reinizializzato).

Viene indicato l’URL del server, il nome dello script PHP di gestione e la porta di accesso al servizio.

Viene indicato l’indirizzo della istanza di gestione HTTP Client REST.HTTPClient:=ADR(HTTP), il periodo di invio dell’heartbeat e la dimensione del buffer di invio richiesta e ricezione risposta.

Terminata l’inizializzazione si esegue il FB RESTClient, il FB è sempre abilitato, in questo modo gestisce tutte le operazioni inviando l’heartbeat e controllando se il server è raggiungibile flag RSvcOn attiva.

Invio dati al server

Ogni 10 secondi vengono inviati i dati al server REST, come valori di divedendo e divisore sono utilizzati due numeri random nel range da 0-1000. I dati inviati sono memorizzati nell’array RESTData, è stato creato un array di 3 membri in modo da contenere il dividendo, il divisore e d il risultato ritornato dal server.

IF ((SysGetSysTime(TRUE)-TimeBf) > 10000000) THEN
  TimeBf:=SysGetSysTime(TRUE); (* Time buffer (uS) *)
  RESTData[0]:=SysGetRandom(TRUE)*1000.0; (* Data exchanged with REST server *)
  RESTData[1]:=SysGetRandom(TRUE)*1000.0; (* Data exchanged with REST server *)

  i:=Sysmemset(ADR(RESTRequest), 0, SIZEOF(RESTRequest)); (* REST request *)
  JEncode(Object:=ADR(RESTRequest), OSize:=SIZEOF(RESTRequest), Name:=ADR('Dividend'), VType:=REAL_TYPE, VAddress:=ADR(RESTData[0]));
  JEncode(Object:=ADR(RESTRequest), OSize:=SIZEOF(RESTRequest), Name:=ADR('Divisor'), VType:=REAL_TYPE, VAddress:=ADR(RESTData[1]));
  FIFO(In:=TRUE, Dp:=ADR(RESTRequest), Dls:=LEN(RESTRequest)); (* Write record on FIFO *)
END_IF;

Viene inizializzata la stringa RESTRequest, poi con i FB JSONEncode creo la stringa di richiesta che è visualizzabile inserendola nella finestra di watch, la stringa è del tipo {“Dividend”:100.5,”Divisor”:10.0}.

La richiesta viene poi inserita nel registro FIFO dove gli viene automaticamente abbinato un valore di timestamp (in GMT). Utilizzando un FIFO che si appoggia su di un file è possibile inserire più stringhe di richiesta indipendentemente dal tempo necessario all’invio verso il server. Il file di appoggio del FIFO farà da “polmone” accumulandole, ed anche nel caso non sia possibile la comunicazione con il server le stringhe non verranno perse.

Il FB RESTClient “si accorge” che è stato inserita una nuova stringa nel FIFO e provvede ad inoltrarla al server, la stringa inviata oltre ai dati inseriti nel FIFO avrà ulteriori informazioni utili al server per gestire la richiesta, sarà del tipo: {“MID”:1234, “ST”:0, “UID”:10879070, “MV”:”1.0″, “FIFO”:[{“Date”:”09/06/2018 08:20:00″, “Value”:{“Dividend”:100.5, “Divisor”:10.0}}]}.

MID:ID messaggio, numero progressivo incrementato ad ogni messaggio inviato
ST:Numero di ritrasmissioni messaggio. Al primo invio il valore è 0,  viene incrementato se l’invio di un messaggio non và a buon fine ed il messaggio viene reinviato. Dopo 3 errori di invio il messaggio viene eliminato
UID:UniqueID del sistema dove è in esecuzione il FB
MV:Versione del messaggio REST. Al momento è sempre “1.0”
FIFO:Stringa caricata da programma nel registro FIFO. E’ un array di valori con il campo Date che ritorna la data (GMT) del caricamento della stringa nel FIFO, ed il campo Value con la stringa caricata.

Ricezione dati dal server

A seguito della ricezione dei dati il server REST provvede ad eseguire le operazioni richieste e se necessario può inviare dei dati in risposta. Nel nostro script PHP di esempio eseguiamo la divisione e ritorniamo il risultato con una stringa del tipo: {“Result”:10.05}.

IF (REST.SvcOk AND (REST.PBuffer <> NULL)) THEN
    i:=Sysmemset(ADR(RESTAnswer), 0, SIZEOF(RESTAnswer));
    i:=Sysstrlen(REST.PBuffer);
    IF (i > SIZEOF(RESTAnswer)) THEN i:=SIZEOF(RESTAnswer); END_IF;
    i:=Sysmemmove(ADR(RESTAnswer), REST.PBuffer, i); 

    JDecode(Object:=REST.PBuffer, Name:=ADR('Result'), VType:=REAL_TYPE, VAddress:=ADR(RESTData[2]), VSize:=SIZEOF(RESTData[2]));
END_IF;

Viene controllato l’Ok ricezione stringa dal server SvcOk, a solo scopo di debug (Visualizzazione in watch da LogicLab) la stringa ricevuta è copiata in a RESTAnswer.

Poi con l’FB JSONDecode il valore di Result è trasferito nella variabile RESTData[2].


Script PHP su server REST

Lato server ho realizzato un semplice script in linguaggio PHP che gestisce la richiesta in arrivo dalla FB RESTClient, esegue un divisione tra i due valori ricevuti e ritorna il risultato codificato  in JSON.

// This is useful only to allow to test the script directly by a browser.
// Use http://www.slimline.altervista.org/Ptp135b200/RESTSvc.php?Post={"MID":1234, "ST":0, "UID":10879070, "MV":"1.0", "FIFO":[{"Date":"09/06/2018 08:20:00", "Value":{"Dividend":100.5, "Divisor":10}}]}

isset($_REQUEST['Post'])?$RxMessage=$_REQUEST['Post']:$RxMessage=file_get_contents("php://input");

// Convert to array the JSON received string and initialize the answer array

$RESTRx=json_decode($RxMessage, true); //Received array
$RESTTx=array(); //Answer array

// The request must have the fields, MID, ST, UID, MV. exit on error.

if ($RESTRx == null ) exit("Wrong REST parameters, Received:[{$RxMessage}]");
if (!isset($RESTRx['MID'])) exit("MID not in message, Received:[{$RxMessage}]");
if (!isset($RESTRx['ST'])) exit("ST not in message, Received:[{$RxMessage}]");
if (!isset($RESTRx['UID'])) exit("UID not in message, Received:[{$RxMessage}]");
if (!isset($RESTRx['MV'])) exit("MV not in message, Received:[{$RxMessage}]");

// Checks numeric fields. If the FIFO field is not present is an heartbeat message.

if (!is_numeric($RESTRx['MID'])) exit("Wrong system MID, Received:[{$RxMessage}]");
if (!is_numeric($RESTRx['UID'])) exit("Wrong system UID, Received:[{$RxMessage}]");
$Heartbeat=(!isset($RESTRx['FIFO'])); //Messaggio di heartbeat

// This is a demo, so the message ID is not checked, if it's 0 a random number is sent back.
// The FB RESTClient increases the Resyncs counter and use this number as MID.

($RESTRx['MID'] == 0)?$RESTTx['MID']=rand(0, 65535):$RESTTx['MID']=$RESTRx['MID']; //Message ID

// If it's an heartbeat message an answer with only the MID is sent.

if ($Heartbeat) exit(json_encode($RESTTx));

// A message with the result is sent.

$RESTTx['Result']=$RESTRx['FIFO'][0]['Value']['Dividend']/$RESTRx['FIFO'][0]['Value']['Divisor'];
exit(json_encode($RESTTx));

Il FB RESTClient invia i dati in POST, lo script controlla se vi sono dati in POST se vi sono li trasferisce nella variabile $RxMessage. Per poter testare lo script da un comune browser ho previsto di gestire una richiesta in GET, quindi basterà dal browser digitare  http://www.slimline.altervista.org/Utilities/RESTSvcDemo/RESTSvc.php?Post={“MID”:1234, “ST”:0, “UID”:10879070, “MV”:”1.0″, “FIFO”:[{“Date”:”09/06/2018 08:20:00″, “Value”:{“Dividend”:100.5, “Divisor”:10}}]} per verificare la risposta.

Successivamente con la funzione json_decode vengono estratti dalla richiesta i dati JSON e trasferiti nell’array associativo $RESTRx. Avendo un array con i campi ed il loro valore abbinato, è intuitivo nel programma accedere ai dati ricevuti. Viene anche inizializzata la variabile $RESTTx per contenere i valori da inviare in risposta al RESTClient.

Viene controllata la correttezza di tutti i dati ricevuti, per quanto riguarda l’ID  di messaggio in questo demo è solo controllato il valore 0. Quando il FB RESTClient inizia la connessione parte con MID=0, il server REST invia la risposta con un MID random, da questo punto in avanti il MID di ogni messaggio è il numero successivo al MID precedente (Roll over a 65536). Un errore nella sequenza provoca una risincronizzazione (Il sever REST invia un nuovo numero random).

Se il messaggio non contiene il campo FIFO è un messaggio di heartbeat (Inviato automaticamente), in tal caso si risponde con il solo MID, messaggio del tipo {“MID”:1234}.

Se il messaggio contiene il campo FIFO è un messaggio dati, viene eseguita l’operazione e oltre al MID è ritornato anche il risultato, messaggio del tipo {“MID”:1234, “Result”:10.5}.

Nota: Il campo MID è controllato internamente dal FB RESTClient e non viene ritornato, quindi nel buffer di ritorno avrò solo i dati che sono presenti nel messaggio di risposta dopo il MID.

Ti è stato utile questo articolo ?