Usuário B e vice-versa. Agora clique em no link "Conversar e envie mensagem para o usuário.
67
6.3. Implementando um chat real-time
Casa do Código
Figura 6.5: Usuário A conversando com Usuário B.
Figura 6.6: Usuário B respondendo mensagens do Usuário A.
Se tudo deu certo, parabéns! O web chat com o mínimo de recursos funcionais
e em tempo real esta no ar. Mesmo que você use um navegador antigo, como o
Internet Explorer 6, tudo funcionará bem! Pois o Socket.IO fará o trabalho de emular
a comunicação entre ambos, mesmo sem a presença do protocolo WebSocket.
68
Casa do Código
Capítulo 6. Programando sistemas real-time
6.4
Organizando o carregamento de Sockets
A nossa aplicação terá duas funcionalidades com resposta em tempo real: o chat e
o notificador de mensagens. Em sistemas maiores podem surgir diversas funciona-
lidades nessa modalidade e codificar todas as funções do Socket.IO em um único
arquivo ficaria terrivelmente assustador para fazer manutenções. O ideal é separar
as funcionalidades de forma modular e escalável essa prática é semelhante ao que
fizemos com as views, models e controllers. Com base nesse problema, crie o diretó-
rio sockets e adicione nele o arquivo chat.js. Para esse arquivo iremos migrar
o código Socket.IO do app.js, veja o exemplo abaixo:
module.exports = function(io) {
var sockets = io.sockets;
sockets.on('connection', function (client) {
client.on('send-server', function (data) {
var msg = "<b>"+data.nome+":</b> "+data.msg+"<br>"; client.emit('send-client', msg);
client.broadcast.emit('send-client', msg);
});
});
}
Dessa forma deixamos o app.js com menos código. Um detalhe importante
é que o chat será carregado por uma nova chamada a função load() pela qual
passaremos como parâmetro a variável io:
var express = require('express')
, app = express()
, load = require('express-load')
, error = require('./middleware/error')
, server = require('http').createServer(app)
, io = require('socket.io').listen(server)
;
// stack de configurações...
load('models')
.then('controllers')
.then('routes')
.into(app);
load('sockets')
.into(io);
// server.listen()...
69
6.5. Socket.IO e Express em uma mesma sessão
Casa do Código
E mais uma vez utilizamos boas práticas de código modular, organizando me-
lhor o projeto e preparando-o para trabalhar com diversas funções do Socket.IO em
conjunto com Express.
6.5
Socket.IO e Express em uma mesma sessão
O Socket.IO consegue acessar e manipular uma session criada pelo servidor web.
Implementaremos esse controle de session compartilhada, pois é mais seguro do que
passar os dados do usuário logado através da tag:
<input type="hidden" id="nome" value="<%- usuario.nome %>"> Como isso funciona? Na prática, quando logamos no sistema, o Express cria um
ID de session para o usuário. Essa session é persistida em memória ou disco no ser-
vidor (essa decisão fica a critério dos desenvolvedores). O Socket.IO não consegue
acessar esses dados, ele apenas possui um controle para autorizar uma conexão do
cliente. Com isso, podemos utilizar as funções de session e cookies do Express den-
tro dessa função de autorização buscando e validando uma session se o mesmo
for válido, armazenamos no cliente Socket.IO, autorizando sua conexão no sistema.
Resumindo, precisamos criar um controle para compartilhar session entre o Ex-
press e Socket.IO. Vamos configurar no Express para isolar em variáveis as funções:
express.cookieParser e express.session. Também criaremos duas cons-
tantes chamadas: KEY e SECRET que serão utilizadas para buscar o ID da session
e carregar os dados do usuário logado utilizando o objeto MemoryStore. Faremos
essas modificações no app.js, seguindo o trecho do código abaixo:
// carregamento dos módulos...
const KEY = 'ntalk.sid', SECRET = 'ntalk';
var cookie = express.cookieParser(SECRET)
, store = new express.session.MemoryStore()
, sessOpts = {secret: SECRET, key: KEY, store: store}
, session = express.session(sessOpts);
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(cookie);
app.use(session);
app.use(express.json());
app.use(express.urlencoded());
70
Casa do Código
Capítulo 6. Programando sistemas real-time
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
app.use(error.notFound);
app.use(error.serverError);
Com esses recursos habilitados, será possível utilizar session no Socket.IO. Va-
mos implementar um controle de autorização via io.set('authorization')
para que a cada conexão o Socket.IO valide o SessionID permitindo ou não recu-
perar os dados do usuário presente no sistema. A seguir, implementamos diversas
condicionais para esse validação:
// require dos módulos...
// stack de configurações...
io.set('authorization', function(data, accept) {
cookie(data, {}, function(err) {
var sessionID = data.signedCookies[KEY];
store.get(sessionID, function(err, session) {
if (err || !session) {