-
Notifications
You must be signed in to change notification settings - Fork 4
06.Websocket API
In questa esercitazione vedremo come utilizzare le connessioni Websocket di HTML5 realizzando una chat.
# git checkout websocket-dev
https://github.com/marcocasario/codemotion2014/tree/websocket-dev
facciamo partire il server!
per fermare l'istanza precedente, premi 'CTRL+C'.
La versione precedente del server realizzato in node js non espone connessioni WebSocket. In questo esercizio ci serve una nuova versione.
La nuova versione apre una connessione websocket all'indirizzo: localhost:8890 Se la porta è occupata, potete cambiarla aprendo il file server.js che trovate nella root directory
Per poter funzionare, il server websocket realizzato con nodejs ha bisogno di un nuovo modulo, che non viene installato di default da node.js.
Installiamolo direttamente da command line, utilizzando sempre npm
:
# npm install nodejs-websocket
Per verificare che tutto sia andato a buon fine, all'interno del nostro progetto è stata creata una nuova cartella node_modules. Se esploriamo il contenuto di questa cartella possiamo vedere al suo interno una cartella nodejs-websocket
.
Di seguito è possibile dare uno sguardo al server che utilizzeremo in questo esercizio:
//includiamo il nuvo modulo websocket installato
ws = require("nodejs-websocket"),
/* websocket server */
//creiamo una nuova istanza websocket
var server = ws.createServer(function (connection) {
//valorizziamo le variabili nowTime per avere on oggetto di tipo data sempre a disposizione
var nowTime = new Date();
// new message per ospitare l'oggetto message
var newMessage = {status: "", message: "", time: nowTime.toJSON() };
//impostiamo il nickname alla connessione a null
connection.nickname = null;
//ad ogni messaggio ricevuto ne inviamo uno in broadcast a tutti gli utenti collegati
connection.on("text", function (str) {
if(connection.nickname === null) {
connection.nickname = str;
newMessage.status="in"
newMessage.message= str +" è entrato";
broadcast(JSON.stringify(newMessage));
}else{
newMessage.status="msg"
newMessage.message= connection.nickname +": "+ str;
broadcast(JSON.stringify(newMessage));
}
});
//mettiamo il server in ascolto su eventuali chiusure di connessione
connection.on("close", function () {
newMessage.status="out"
newMessage.message= connection.nickname +": è uscito";
broadcast(JSON.stringify(newMessage));
});
//mettiamo il server in ascolto su eventuali errori generici
connection.on("error", function (e) {
console.error(nowTime + "# Error:" + connection.nickname, e);
connection.close();
});
});
//mettiamo in ascolto il server sulla porta 8890
server.listen(8890);
//questa funzione ci permette di ciclare per tutti gli utenti connessi ed inviare il relativo messaggio in broadcase
function broadcast(str) {
server.connections.forEach(function (connection) {
connection.sendText(str);
});
}
Creiamo una nuova area dove saranno visualizzati i messaggi, sostituiamo il codice attuale:
<section class="banner_section"></section>
con il seguente codice:
<section id="support_section" class="support_section text_style">
<div class="welcome_message_area">Benvenuto, il supporto tecnico ti fornirà le informazioni necessarie per ogni tua esigenza.</div>
<div class="title_message_area hide">Dashboard</div>
<ul class="message_area"></ul>
</section>
Possiamo notare come siano cambiati gli id e le classi degli oggetti. Il primo ospita l'intera area, il secondo visualizzerà tutti i messaggi che saranno inviati dal server.
All'interno del nostro
inseriremo invece le informazioni necessarie per dare la possibilità all'utente di scegliere un nickname, ed una volta effettuato il "login" di inviare un nuovo messaggio.Ecco il codice per fare il login:
<article class="article clearfix nickname_area">
<form id="form_nickname" class="form_box">
<fieldset class="fieldset">
<ol>
<li class="left">
<label class="label" for="nickname">Nickname *</label><br>
<input class="input" id="nickname" name="nickname" type="text" placeholder="Inserisci il tuo nickname" required autofocus>
</li>
<li><br><button class="submit" type=submit>Send</button></li>
</ol>
</fieldset>
</form>
</article>
Aggiungiamo subito dopo anche il codice per scrivere un nuovo messaggio:
<article class="article clearfix send_message_area hide">
<form id="form_message" class="form_box">
<fieldset class="fieldset">
<ol>
<li class="left">
<label class="label" for="message">Inserisci il messaggio</label><br>
<input class="input" id="message" name="message" type="text" placeholder="nuovo messaggio" required autofocus>
</li>
<li><br><button class="submit" type=submit>Send</button></li>
</ol>
</fieldset>
</form>
</article>
I moduli appena inseriti sono dei semplici input type:text con relativo submit per inviare i dati al server.
Effettuati questi passaggi il risultato ottenuto sarà molto simile a questo:
aggiungiamo una nuova regola per il contenitore ed il box che ospiterà i messaggi che arrivano dal server.
.support_section { width: 880px; height: 200px; padding: 0 40px; background: #fff; }
.message_area{ height: 150px }
Aggiungiamo gli stili che devono essere associati ai form nickname e new message:
.support_section .form_box { padding: 0 10px; }
.support_section .form_box .input { width: 268px; }
.support_section .form_box .submit { width: 298px; float: none; }
infine aggiungiamo tre semplici classi per cambiare il colore dei messaggi che appariranno in base al tipo di informazione visualizzata.
.user_message{ list-style: none; margin-bottom: 10px; border-bottom: 1px solid #e8e8e8;}
.in{color: green;}
.out{color: red;}
.msg{ color: #888888; }
Apriamo il file js/helpdesk.js
Cominciamo con il definire l'oggetto che si occuperà di gestire la nostra micro applicazione help-desk:
//inizializziamo app
var app = {
connection: {},
nickname: '',
status: 'closed'
};
Utilizzeremo Modernizr per verigicare se il browser ha le funzioni websocket. Creiamo quindi una nuova parte di codice che sarà istanziata non appena il documento è pronto, utilizzando jQuery:
$(document).ready( function (){
if (!Modernizr.websockets) {
alert("No WebSocket here");
}
});
Aggiungiamo al suo interno anche il controllo per intercettare l'evento al submit del form con il relativo al nickname:
//form event submit
$('#form_nickname').submit(function (event) {
//evitiamo il submit del form
event.preventDefault();
if ( setNickname() ){
hide( $('.nickname_area') );
show( $('.send_message_area') );
setWSConnection();
}
//evitiamo il submit del form
return false;
});
Fatto questo, aggiungiamo l'evento al submit del form per l'invio del messaggio:
$('#form_message').submit(function (event) {
//evitiamo il submit del form
event.preventDefault();
sendWsMessage();
//evitiamo il submit del form
return false;
});
Se analizziamo il codice appena scritto per l'invio del form relativo al nickname, possiamo notare come prima della funzione setWSConnection() venga richiamata la setNickname(), vediamo nel dettaglio di cosa si occupa:
//valorizza l'oggetto app.nickname
function setNickname(){
var newNickname = $('#nickname').val();
if ( isNotNull( newNickname ) && newNickname.length > 3){
app.nickname = newNickname;
return true;
}
return false;
}
Valorizza l' oggetto app.nickname, con il nickname inserito dall'utente.
Passiamo ora alla funzione setWSConnection():
// si occupa dell'invio dei messaggi al server websocket.
function setWSConnection(){
if (isNotNull( app.nickname )){
clearDomMessages();
app.connection = new WebSocket("ws://"+window.location.hostname+":8890")
app.connection.onopen = function () {
console.log("Connection opened");
app.connection.send(app.nickname);
app.connection.status = 'open';
}
app.connection.onclose = function () {
var newMessage = {"status":"out", "msg": "connection closed", "time": new Date()};
setDomMessage(newMessage);
app.connection.status = 'close';
}
app.connection.onerror = function () {
var newMessage = {"status":"out", "msg": "Connection error", "time": new Date()};
setDomMessage(newMessage);
app.connection.status = 'close';
}
app.connection.onmessage = function (event) {
setDomMessage(event.data);
}
}
}
//ripulisce l'area messaggi alla prima connessione dell'utente.
function clearDomMessages(){
$('.welcome_message_area').hide();
$('.title_message_area').show();
$('.message_area').empty();
}
Il codice di seguito prende tutti i messaggi che arrivano dalla connessione websocket e li scrive all'interno del nostro oggetto dom.
//scrive i messaggi che arrivano dal server mentre la connessione websocket resta in ascolto
function setDomMessage( message ){
var newMessage = jQuery.parseJSON( message ),
element = document.createElement('li'),
domElement = $('.message_area'),
time = '';
function getTime(){
var newTime = new Date(newMessage.time);
return newTime.getUTCHours()+":"+newTime.getUTCMinutes();
}
time = getTime();
element.className = 'user_message'+' ' + newMessage.status;
element.appendChild (document.createTextNode("["+time+"] " + newMessage.message) );
domElement.append( element );
domElement.animate({'scrollTop': domElement[0].scrollHeight});
}
Inviamo i messaggi al server:
// funzione per inviare i messaggi al server WS
function sendWsMessage(){
var message = $('#message').val();
if ( isNotNull( message )){
console.log('Invio del messaggio al server: ' + message);
app.connection.send(message);
$('#message').val('');
}
}
Chiudiamo la connessione:
//chiude la connessione al server webSocket
function closeWSConnection(){
if (app.connection.status === 'open'){
app.connection.close();
app.connection.status = 'closed';
}
}
Di seguito alcuni screenshot con il rusultato ottenuto.