HTML5 Device Orientation API e WebSocket

26 luglio 2012

Veicolare le informazioni con i WebSocket

Il funzionamento dei WebSocket è abbastanza semplice, fondamentalmente queste API consentono di stabilire un canale di comunicazione bidirezionale tra un client ed un server, abilitando in questo modo la possibilità che sia il server ad inviare informazioni senza che il client le richieda.

Questo meccanismo è alla base di molte applicazioni asincrone, chat in primis, ma può essere utilizzato anche in altri ed interessanti modi.

Ad esempio cosa succedesse se decidessimo di trasmettere attraverso WebSocket le informazioni recuperate delle Device Orientation API? Lo scenario potrebbe essere il seguente: un device viene manipolato, le sue informazioni trasmesse ad un server e poi ad un altro client, all’interno del quale vengono utilizzate per agire su quanto visualizzato. Lo stesso comportamento che sperimentiamo ogniqualvolta ci cimentiamo con la console Wii.

Operiamo sull’esempio precedente facendo in modo che la rotazione del cubo possa essere pilotata da un device remoto. In questo caso quindi il cubo verrà proiettato su di uno schermo desktop mentre il device avrà il ruolo di joystick.

La comunicazione attraverso i WebSocket è sufficientemente semplice, almeno nei limiti di quanto serve per questa demo. Ecco come cambia il javascript dell’esempio precedente:

/* ricordarsi di inserire il corretto indirizzo del server */
var socket = new WebSocket("ws://0.0.0.0:8080");
socket.addEventListener("open", registratiMaster, false);
socket.addEventListener("message", stampaMessaggio, false);

function registratiMaster(evento){
  socket.send('register master');
}

function stampaMessaggio(evento){
  var angoli = JSON.parse(evento.data);
  document.getElementById('container').style['-webkit-transform'] =
         "translateZ(-400px) " +
         "rotateZ(" + ( -angoli.gamma ) + "deg) " +
         "rotateX(" + angoli.beta + "deg) " +
         "rotateY(" + angoli.alpha + "deg)";
  document.getElementById('container').style['transform'] =
  document.getElementById('container').style['-webkit-transform'];
}

Come possiamo notare in questo caso le valorizzazioni delle tre rotazioni non provengono più dall’evento deviceorientation ma da message, ovverossia dall’evento che viene generato ogniqualvolta un nuovo messaggio arrivi dal server presso il quale ci siamo registrati istanziando un nuovo oggetto WebSocket.

Ora dobbiamo costruire una pagina HTML progettata per essere eseguita nel device e per inviare le informazioni alpha beta e gamma allo stesso server, che dovrà poi provvedere ad instradarle verso il client contente il cubo che abbiamo visto poche righe fa:

<!doctype html>
<html>
<head>
<meta charset="utf8">
<title>Pilota il cubo</title>
<meta name="viewport" 
      content="width=device-width, 
	           initial-scale=1.0, 
               maximum-scale=1.0,
			   user-scalable=no"/>
<script>
/* ricordarsi di specificare l'ip del server WebSocket */
var socket = new WebSocket("ws://0.0.0.0:8080");
socket.addEventListener("open", prontoPerMuovere, false);
socket.addEventListener("message", nuovoMessaggio, false);

function prontoPerMuovere(){
  window.addEventListener ("deviceorientation", muovi, false);
}

function muovi(evento){
  socket.send(JSON.stringify({
    alpha: evento.alpha,
    beta: evento.beta,
    gamma: evento.gamma
  }));
}
</script>
</head>
<body>
</body>
</html>

Anche in questo caso il codice è molto facile da interpretare, all’apertura del socket (evento open) ci mettiamo in ascolto del solito evento deviceorientation, questa volta però, al posto che utilizzare le informazioni direttamente, le serializziamo in JSON e le inviamo al WebSocket, che dovrà inviarle a sua volta al client desktop che abbiamo sviluppato poco fa.

Non resta che sviluppare il server, il cui unico compito consiste nell’instradare correttamente i messaggi tra i due client. Utilizzeremo Ruby che riesce a mantenere un’alta leggibilità pur garantendo un codice succinto.

Ecco le poche righe che compongono il server (server.rb):

require 'em-websocket'
EventMachine.run do
  @channel = EM::Channel.new

  EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 8080) do |ws|
    ws.onmessage do |msg|
      case msg
        when 'register master'
          puts "the master is ready"
          @channel.subscribe { |m| ws.send m }
        else
          puts "sending #{msg} to master"
          @channel.push msg
      end
    end
  end

end

Come possiamo notare il server identifica il master, ovverosia il client che contiene il cubo, da un messaggio ‘register master’; una volta avvenuta questa identificazione ogni successivo messaggio proveniente da qualsiasi altro client verrà semplicemente instradato verso il master.

Ovviamente l’implementazione è molto naif, consente l’esecuzione di un solo master per volta e non tiene d’acconto di nessuna tematica relativa alla sicurezza della comunicazione, però rimane funzionante ed efficiente.

Per provare questa demo è necessario premunirsi di Ruby on Rails e della gemma ’em-websocket’ che può essere installata eseguendo da un terminale:

gem install em-websocket

Ora è sufficiente eseguire il server (ruby server.rb) e successivamente accedere alla pagina master da un qualsiasi desktop ed aprire con un device mobile l’altra pagina sviluppata. Se abbiamo impostato correttamente gli ip e le due istanze condividono la medesima rete dovremmo poter pilotare l’orientamento del cubo su desktop semplicemente inclinando il device mobile che teniamo in mano.

Conclusioni

WebSocket e Device Orientation API si prestano a tutta una serie di sviluppi molto interessanti sia per l’ambito ludico che no. Al momento purtroppo il supporto è ancora troppo scarso per poter considerare questa tecnologia production ready ma tenendo conto dell’attuale evoluzione da parte dei browser mobile sono confidente che questo problema possa risolversi nel breve periodo.

Se vuoi aggiornamenti su HTML5 Device Orientation API e WebSocket inserisci la tua e-mail nel box qui sotto:
 
X
Se vuoi aggiornamenti su HTML5 Device Orientation API e WebSocket

inserisci la tua e-mail nel box qui sotto:

Ho letto e acconsento l'informativa sulla privacy

Acconsento al trattamento di cui al punto 3 dell'informativa sulla privacy