• Non ci sono risultati.

3.2 Tecnologie

3.2.2 API

WebSocket sono un set di API nato per permettere ai browser e server di parlarsi in maniera asincrona e senza bisogno dell’interazione dell’utente. La comunicazione asincrona `e quella comunicazione in cui il mittente invia il messaggio e poi continua la propria esecuzione;

asincrona sta proprio a significare l’asincronicit`a che vi `e tra l’invio di un messaggio e la risposta al messaggio stesso.

Per l’applicazione `e stato scelto di utilizzare jWebSocket, un’implementazione open source in Java e Javascript del protocollo WebSocket con alcune estensioni molto interessanti. Il package jWebSocket contiene:

• jWebSocket Server : un WebSocket server scritto interamente in Java per streaming[g]

di dati server-to-client(S2C) e controllo comunicazioni client-to-client (C2C);

• jWebSocket Clients: un WebSocket client scritto interamente in JavaScript con la possibilit`a di utilizzare diversi sottoprotocolli, sessioni e timeout-management. Non richiede l’installazione di plug-in nel broser.

Il server fornito da jWebSocket fornisce gi`a di default le caratteristiche richieste dall’appli-cazione, come fornire l’accesso al client, effettuare il broadcast[g] dei messaggi per una chat e fornire la divisione in stanze separate delle comunicazioni. Una caratteristica molto im-portante che ha portato all’adozione di jWebSocket `e che `e possibile integrarlo in maniera molto semplice ed efficace in applicazioni web esistenti, come ambienti Tomcat. L’unica richiesta `e che sia installata nel sistema Java. Molto interessante `e anche la possibilit`a che jWebSocket server fornisce di poter scrivere dei plug-in, dei listener o dei filtri e integrarli con molta facilit`a nel server. Nell’applicazione questa possibilit`a non `e stata sfruttata dato che le funzionalit`a richieste erano gi`a presenti in un’installazione di default del server.

Per il client la situazione `e un attimo diversa. Con jWebSocket vengono fornite le librerie pi`u importanti, le quali contengono i metodi basilari per la connessione e autenticazione, ma

`e necessario scrivere a mano tutti i metodi che permettono la comunicazione tra il client e il server. Nell’applicazioni sono state usate due librerie:

• jWebSocket.js: questa `e la libreria pi`u importante dato che contiene tutti i metodi necessari per stabilire una connessione con il server. Qualsiasi applicazione che voglia usare jWebSocket deve includere questa libreria;

• jwsChannelPlugIn.js: questa libreria fornisce i metodi per poter avere una divisione in stanze per le comunicazioni. Viene fornita con il jWebSocket Clients dato che nel server `e gi`a implementata la possibilit`a di suddivisione in stanze, e permette una facile implementazione da parte del programmatore nelle proprie applicazioni.

jWebSocket.js

// O p t i o n a l l y d i s a b l e GUI c o n t r o l s h e r e v a r lMsg = j w s .MSG WS NOT SUPPORTED ; a l e r t ( lMsg ) ;

}

Creare un’istanza di jWebSocketClient `e molto semplice. jWebSocket fornisce la classe jWeb-SocketJSONClient la quale contiene i metodi per connettersi, disconnettersi e scambiare messaggi con il server usando il formato JSON. Questa classe `e inclusa in un specifico na-mespace per non andare in conflitto con altri framework.

Autenticazione sul jWebSocket server:

Per iniziare la connessione tra il client e il server viene usato il metodo logon presente nella libreria jWebSocket.js. Questo metodo connette il client al server passandoli username e password per l’autenticazione. Il server assegner`a un ID unico per un client, cos`ı se un uten-te si auuten-tentica al server con diversi browser dalla suten-tessa macchina apparir`a come pi`u persone.

Spedire un messaggio con jWebSocket:

Se la connessione `e avvenuta con successo un client pu`o spedire un messaggio ad un altro preciso client utilizzando il metodo send oppure spedirlo a tutti gli altri presenti usando il metodo broadcast ; entrambi appartenenti alla libreria jWebSocket.js. L’azione di spedizione di un messaggio `e sempre non bloccante, i metodi send e broadcast non attendono che la spedizione ritorni un avviso di successo, che `e opzionale.

Processare messaggi in arrivo:

I messaggi dal server al client sono spediti asincronamente. Pertanto la classe jWebSocket-Client fornisce l’evento OnMessage. Basta semplicemente aggiungere un listener per questo evento nell’applicazione il quale all’arrivo di un messaggio lo processer`a come desiderato.

Chiudere la connessione:

i f ( j W e b S o c k e t C l i e n t ) { j W e b S o c k e t C l i e n t . c l o s e ( ) ; }

Sia il server che il client possono terminare la connessione su richiesta. Per il client esiste il metodo close fornito dalla classe jWebSocketClient. Il server termina automaticamente la connessione dopo un certo periodo di inattivit`a nella linea. Se questo succede il client riceve un evento intercettabile dal listener OnClose il quale disconnetter`a il client permettendo all’applicazione di comportarsi nel modo giusto. In ogni caso il timeout del server pu`o essere configurato a piacimento oppure si pu`o avvisare il server che deve rimanere connesso con il client anche se non c’`e attivit`a tra di loro oppure si pu`o fornire il client di un metodo che lo ricconnette al server se questo si disconnette.

jwsChannelPlugIn.js

Utilizzando la libreria jwsChannelPlugIn.js `e possibile creare delle stanze separate dove po-ter accedere e effettuare operazioni senza che le persone presenti nelle altre stanze se ne accorgano. Grazie a questa libreria `e molto semplice, basta inserire un nome, un id e una password che serve per tenerne traccia, accederci o eliminarla e una password per permettere agli utenti di pubblicare in quel canale.

Accedere ad un canale:

Molto semplice `e anche l’accesso al canale. Formalmente si parla di canali, perch`e il server divide le comunicazioni in canali. ´E il programmatore che pu`o usare questa distinzione in canali per creare stanze separate tra loro per fare comunicare i client in privato.

Spedire un messaggio in un canale:

Naturalmente `e possibile inviare messaggi solo dal canale con cui si ha l’accesso.

getUserMedia

Queste API permettono al browser di catturare l’audio e il video della webcam integrata (o installata) e visualizzarlo nella pagina grazie ad un nuovo tag <video> introdotto con l’HTML5. Questa API `e recentissima pertanto solo in Chrome e Opera funziona attualmen-te, e solo nelle versioni beta. In Chrome `e necessario abilitare un flag specifico (Attiva l’API Media Source per gli elementi <video>) altrimenti non funziona.

Per ottenere l’accesso alla webcam o al microfono `e necessario richiedere all’utente di confer-mare il loro utilizzo da parte della pagina web. Nella richiesta `e possibile specificare a quale media vogliamo accede: o solo il video o il video e l’audio. Ottenuto l’accesso otteniamo un oggetto LocalMediaStream che rappresenta la webcam dal quale possiamo ottenere un Blob URL che, se assegnato ad un tag video, ci permette di visualizzare lo stream della webcam.

Un Blob URL rappresenta sostanzialmente un insieme di dati grezzi immutabili.

window . n a v i g a t o r . webkitGetUserMedia ( { a u d i o : t r u e , v i d e o : t r u e } , f u n c t i o n ( strm ) {

Geolocation API

La funzionalit`a offerta da Geolocation API `e abbastanza semplice: definire una struttura dati atta a contenere vari dati geospaziali e impostare alcune funzioni di accesso a tali dati.

Nessuna specifica viene definita in merito ai meccanismi che il browser deve utilizzare per re-cuperare questi dati, ogni piattaforma `e infatti tenuta ad utilizzare al meglio le informazioni provenienti dal device. Su di un dispositivo mobile di ultima generazione avremo quindi un set di coordinate provenienti dal sensore GPS, mentre su di un portatile potremo avvalerci del posizionamento legato all’ip della connessione internet.

Esistono solo due metodi, molto simili tra loro ma con una semplice differenza: getCurrent-Position restituisce la posizione di dove attualmente ci si trova, watchgetCurrent-Position restituisce la posizione ogni volta che quest’ultima cambia.

n a v i g a t o r . g e o l o c a t i o n . g e t C u r r e n t P o s i t i o n ( i n C a s o D i S u c c e s s o , o p z I n C a s o D i E r r o r e , o p z i o n i ) ;

n a v i g a t o r . g e o l o c a t i o n . w a t c h P o s i t i o n ( i n C a s o D i S u c c e s s o , o p z I n C a s o D i E r r o r e , o p z i o n i ) ;

La sintassi dei metodi `e semplice, il primo argomento contiene il riferimento ad una funzione da eseguire in caso di successo, il secondo argomento `e opzionale e punta ad una funzione da esegure in caso di errore. L’ultimo parametro anch’esso facoltativo pu`o essere usato per specificare alcune opzioni utilizzando la struttura opzione1:valore1,... Sono disponibili tre opzioni:

• enableHighAccuracy (true/false): questo flag pu`o essere utilizzato per notificare allo user-agent la necessit`a o meno di ottenere dati il pi`u accurati possibile;

• timeout (millisecondi): l’opzione rappresenta il tempo massimo concesso al browser per recuperare la posizione dell’utente;

• maximuAge (millisecondi): indica al browser di effettuare una ricerca preventiva nella cache di un dato geospaziale non pi`u vecchio dei millisecondi specificati. Se dispo-nibile tale dato verr`a restituito come posizione corrente, altrimenti verr`a eseguita la procedura classica.

La funzione invocata in caso di successo deve accettare un singolo argomento, un oggetto di tipo Position che contiene tutte le informazioni recuperate cos`ı come un timestamp delle data e ora di recupero.

Queste API sono state utilizzate in una prima versione dell’applicazione per farsi restituire l’orario e la posizione di quando veniva effettuata una fotografia.

PeerConnection API

Queste API sono molto potenti e permettono di scambiare dati tra due browser direttamente senza uso di un server come con i WebSocket. I pregi di una comunicazione di questo tipo `e maggior efficienza nell’utilizzazione della rete e una latenza minore. In ogni caso `e necessario uno scambio di informazioni iniziale tramite un server per poi permettere ai due browser di connettersi direttamente tra di loro e trasferirsi informazioni. Nell’applicazione come canale di comunicazione `e stato utilizzato il server fornito da jWebSocket.

Essendo una comunicazione p2p[g](Peer-to-peer) quella instaurata tra i due browser `e ne-cessario fornire al momento della creazione della comunicazione l’indirizzo di un server STUN(Session Traversal Utilities for Network Address Translators)/TURN(Traversal Using Relays around NAT). Se i peer sono nella stessa rete non servirebbe neanche fornire l’indi-rizzo di un server STUN/TURN per`o in questo modo si uscirebbe dagli standard definiti. Il protocollo STUN permette alle applicazioni dietro un NAT[g](network address translation) di scoprire la presenza del traduttore di indirizzi(NAT) e di ottenere l’IP pubblico mappa-to e il numero della porta che il NAT ha allocamappa-to per la connessione UDP con l’indirizzo remoto. Il protocollo richiede la presenza di un server (STUN server) situato dalla parte opposta (parte pubblica) del NAT. Dopo che il client ha scoperto il suo indirizzo esterno, pu`o usarlo per connettersi e comunicare con un altro peer direttamente comunicandoli il suo indirizzo esterno al NAT piuttosto che quello interno che per definizione `e privato e quindi non raggiungibile da altri peer tramite internet.

Una volta che ognuno dei due peer viene a conoscenza del proprio indirizzo di rete esterno devono stabilire una comunicazione tra di loro. Per fare questo viene utilizzata la tecnica dell’ UDP hole punching. UDP Hole punching consente di stabilire delle connessioni tra due host attraverso uno o pi`u NAT. Per funzionare, questa tecnica richiede che i due host A e B iniziano una trasmissione UDP con un server S ed essendo entrambi appartenenti a reti private interviene il NAT che assegna alla trasmissione UDP delle porte esterne temporanee.

Il server S controlla se le porte sorgenti usate da A e B sono le stesse usate per spedire il messaggio (se il NAT crea le porte randomicamente l’UDP hole punching non pu`o venire effettuato) e se lo sono A e B scelgono due nuove porte X e Y per instaurare la comunicazione e avvisano S di questa scelta. S allora avvisa A di inviare un pacchetto UDP verso la porta Y di B e B di connettersi con la porta X di A, in questo modo ora i due host A e B possono comunicare direttamente tra di loro senza problemi.

Il metodo che permette la creazione della comunicazione `e semplice, accetta solamente due parametri. Il primo `e l’indirizzo del server STUN/TURN e il secondo `e la funzione che viene richiamata per poter procedere con il primo scambio di informazioni tramite jWebSocket.

Per lo scambio die dati si utilizza il protocollo SDP che serve per arrivare ad un comune accordo su dettagli riguardanti l’imminente trasmissione p2p dei video. In pratica tramite questo protocollo vengono stabiliti vari parametri quali codec e l’indirizzo della trasmissione video. Poi bisogna dichiarare degli ascoltatori che richiamano funzioni quando si verifica un determinato evento. Per esempio quando la connessione `e attiva tra i due peer e uno dei due invia lo stream catturato dalla webcam, l’altro peer riceve un evento onAddStream il quale permette al peer di creare al volo un tag video dove mostrare lo stream in arrivo.

PC=new window . w e b k i t D e p r e c a t e d P e e r C o n n e c t i o n ( t h i s . s e r v e r C o n f i g , f u n c t i o n ( sdp ) { c o n s o l e . l o g ( ” t o s e n d SDP s t u f f t o i d : ”+ID ) ;

jWebSocket . sendText ( ID , { ” s c o p o ” : ” realTcomm ” , ” m o t i v a z i o n e ” : ”SDP” , ” d a t o ” : sdp } ) ; } ) ;

PC . addStream ( strm ) ;

E stato provato che `´ e possibile creare multiple PeerConnection da un host a molti altri, solo che essendo ancora molto acerbe come api, non contemplano ancora dei metodi per otimiz-zare alcuni aspetti del flusso video causando sforzi notevoli alla cpu di pc non di ultima generazione.

Come si pu`o notare dal codice sopra, sono state usate le webkitDeprecatedPeerConnection dato che attualmente sono le uniche implementate da Chrome. La bozza ufficale del w3c[g] `e aggiornata al 30 maggio 2012 ma le nuove specifiche non sono ancora state implementate. Per l’applicazione si seguono le metodologie specificate nella bozza aggiornata al 27 aprile 2012.

Questo perch`e queste api sono molto giovani, la prima bozza del w3c `e stata pubblicata nel gennaio 2012 e attualmente queste api funzionano solamente su Chrome Canary abilitando un flag(Attiva PeerConnection.) anche perch`e l’autore iniziale di queste bozze `e un dipendente della Google.

Web SQL[g] database API

Tra le varie prove per l’applicazione `e stato testato pure il salvataggio di immagini nella memoria del browser utilizzando le Web SQL database API. Queste API portano l’SQL anche nella parte client e contengono tre importanti metodi per amministrare il tutto:

• openDatabase

• transaction

• executeSql

Attualmente la compatibilit`a di queste API `e con Safari, Chrome e Opera. Firefox non implementa queste API perch`e Mozilla ritiene che esistano migliori implementazioni per il salvataggio client-side.

Creare un nuovo database `e semplice. Se si prova ad aprire un database inesistente le API lo creeranno da zero e inoltre non bisogna preoccuparsi di chiuderlo al termine delle operazioni.

Per creare e aprire un database si utilizza la seguente riga di codice

v a r db = openDatabase ( ’ mydb ’ , ’ 1 . 0 ’ , ’my f i r s t d a t a b a s e ’ , 2 ∗ 1024 ∗ 1 0 2 4 ) ;

Dopo aver creato o aperto un database si pu`o iniziare ad operare con i dati. Per fare questo dobbiamo creare una transazione. Questo perch`e le transazioni contengono le istruzioni SQL e forniscono all’applicazione la possibilit`a di fare rollback[g]. Questo significa che se una transazione fallisce, i cambiamenti non vengono effettuati nel database come se la transazione non fosse mai partita.

db . t r a n s a c t i o n ( f u n c t i o n ( t x ) { // h e r e be t h e t r a n s a c t i o n

// do SQL magic h e r e u s i n g t h e t x o b j e c t } ) ;

Per eseguire le query SQL si utilizza il comando executeSql sia per leggere che per scrivere.

Se una query fallisce le sucessive presenti nella stessa transizione non vengono eseguite.

db . t r a n s a c t i o n ( f u n c t i o n ( t x ) {

t x . e x e c u t e S q l ( ’CREATE TABLE f o o ( i d unique , t e x t ) ’ ) ; } ) ;

Canvas 2D API

Con l’avvento dell’HTML5 `e stato implementato un tag chiamato canvas che permette di disegnare sul browser. Il canvas per definizione `e un elemento invisibile grande 300x150px (di default) compatibile con tutti i browser. La prima cosa da fare `e ottenere tramite java-script il drawing context, il quale ci permette di avere un accesso diretto al canvas e quindi disegnarci sopra.

<s c r i p t >

Le API forniscono numerosi metodi per disegnare e settare propriet`a utili al disegno come fillStyle e strokeStyle per settare il colore con cui si andr`a a disegnare forme e linee. I colori sono gli stessi che si usano per il CSS[g] come rgb() o rgba(). Vengono forniti anche metodi per disegare forme ma nell’applicazione attualmente non vengono usati.

Per disegnare a mano libera si utilizzano le canvas paths. Per iniziare a disegnare bisogna chiamare beginPath() e poi disegnare liberamente sul canvas. Una volta disegnato bisogna chiamare closePath() altrimenti nulla di quanto disegnato sar`a visibile.

// S e t t h e s t y l e p r o p e r t i e s .

Finalmente con HTML5 viene fornito un modo standard per interagire con i file locali tramite la specifica API File. Queste API permettono ad una Web Application di richiedere uno spazio dedicato per salvare i dati in maniera temporanea o persistente, oppure di leggere dei dati presenti nel filesystem. La specifica prevede diverse interfacce per l’accesso ai dati locali:

• File - un singolo file; vengono forite informazioni come nome, grandezza, tipologia e riferimento al file.

• FileList - un arrey di oggetti File.

• Blob - Permette la divisione del file in intervalli uguali.

L’interfaccia FileReader, utilizzata in combinazione con le strutture di dati descritte sopra, permette la lettura di file in modo asincrono tramite la gestione degli eventi Javascript.

La forma pi`u comune per caricare un file `e usare la metodologia standard ¡input type=’file’¿.

Javascript ritorna la lista dei dei file selezionati all’interno dell’oggetto FileList. Un esempio

semplice che fa vedere le modalit`a di caricamento di un file. Con l’attributo multiple sul-l’input tag si permette la selezione multipla dei file. Per ogni file caricato poi si stampa il nome, la tipologia e altre informazioni semplici.

<i n p u t t y p e=” f i l e ” i d =” f i l e s ” name=” f i l e s [ ] ” m u l t i p l e />

Dopo aver ottenuto il riferimento al file si istanzia l’oggetto FileReader per leggere il conte-nuto in memoria. Al termine del caricamento avviene l’evento onload che, intercettato dal listener corretto, permette di leggere l’attributo result dell’oggetto FileReader che pu`o essere utilizzato per accedere ai dati del file.

FileReader include quattro opzioni per leggere asincronamente un file:

• FileReader.readAsBinaryString(Blob/File) - La propiet`a result conterr`a i dati del file come una stringa binaria. Ogni byte `e rappresentato come un intero nel range [0..255].

• FileReader.readAsText(Blob/File, opt encoding) - La propriet`a result conterr`a i dati del file come una stringa di testo. Di default la stringa `e codificata in UTF-8. Per differenti codifiche si pu`o usare il parametro opzionale per specificare un differente formato.

• FileReader.readAsDataURL(Blob/File) - La propriet`a result conterr`a i dati del file codificati come un Data URL.

• FileReader.readAsArrayBuffer(Blob/File) - La propriet`a result conterr`a i dati del file all’interno di un oggetto ArrayBuffer.

Una volta che uno di questi metodi di lettura `e chiamato sull’oggetto FileReader `e possibile monitorare i progressi utilizzando i listener onLoadStart, OnProgress, OnLoad,OnAbort, OnError e OnLoadEnded.

Nel progetto le File API sono utilizzate per leggere un file PDF e caricarlo in memoria utilizzando il metodo FileReader.readAsArrayBuffer(Blob/File).

Librerie

Nel progetto `e stata utilizzata una libreria open source ancora in via di sviluppo ma molto innovativa.

PDF.js Questa libreria permette la visualizzazione di file PDF nel browser senza neces-sit`a di plug in aggiuntivi perch`e `e scritta interamente in javascript. Sta venendo utiliz-zata anche da Mozilla per il PDF reader integrato che nelle ultime versioni di Firefox `e presente. Per utilizzarla `e necessario passarle un file ArrayBuffer contenente i dati del PDF da visualizzare. Per questo `e stato scelto di leggere i dati con il metodo FileRea-der.readAsArrayBuffer(Blob/File) fornito dalle File API. La libreria si occupa della trafor-mazione e visualizza ogni singola pagina all’interno di un canvas definito dall’utente.

Il funzionamento `e molto semplice. Dopo aver incluso la libreria nell’applicazione basta pas-sare l’ArrayBuffer o l’url del file PDF all’oggetto PDFJS che si occupa del lavoro principale e salva il file pdf all’interno di un oggetto. Questo oggetto contiene il numero di pagine totali e grazie ai metodi forniti `e possibile renderizzare una singola pagina sapendo solo il numero della stessa.

Questa libreria purtroppo `e ancora in via di sviluppo ed `e stato notato che a volte la pagina pdf che viene renderizzata nel canvas risulta essere storta. Non succede sempre, si presenta in modo randomico per`o `e stato notato che se la transizione da una pagina all’altra avviene con calma e non in fretta tutto viene visualizzato correttamente.

Documenti correlati