Criando uma aplicação de Chat simples com NodeJS e Socket.io

janeiro 5, 2017 12:00 pm Publicado por Deixe um comentário

Neste tutorial iremos abordar alguns conceitos do Socket.io criando um simples sistema de chat para browser.

https://raw.githubusercontent.com/dericeira/Simple-Chat-Socket.io/master/example.gif

O que é Socket.io?

Socket.io é um uma biblioteca Javascript feita para construir aplicações real-time, possibilitando uma comunicação bi-direcional entre cliente e servidor. O socket.io utiliza as especificações de Web Sockets (para quem quer saber mais, recomendo dar uma olhada neste ótimo artigo da HTML5 Rocks).

O Socket.io roda, no lado do servidor, em NodeJS, e, no lado do cliente, ele roda diretamente no browser, possibilitando uma enorme gama de possibilidades de aplicações, como jogos, sistemas de notificações, real-time analytics e sistemas de chats e conversas em tempo real.

Setando o projeto

Primeiramente, temos que instalar algumas bibliotecas que iremos utilizar no projeto, para isso usarei o yarn.

Em primeiro lugar, vou adicionar ao projeto a biblioteca do Socket.io que rodará do lado do servidor.

yarn add socketio

Também iremos utilizar o express:

yarn add express

Também precisamos adicionar o Socket.io para o cliente (você pode utilizar a CDN oficial disponibilizada no site deles também):

yarn add socket.io-client

E, por último, usarei a biblioteca jQuery para manipular a DOM.

yarn add jquery

Fazendo o HTML+CSS

Vamos criar um arquivo index.html e já deixar preparado o nosso template do sistema de chat.

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Simple chat</title>
 <link rel="stylesheet" href="assets/css.css">
</head>
<body>
<div class="nickname_container" id="nick">

 <span>Type your nickname:</span>
 <form id="submit"><input type="text" id="nickname" /></form>

</div>

<div id="chat" hidden>

 <div class="menu" =>
 <div class="name" id="name">Alex</div>
 <div class="last" id="time">18:09</div>
 </div>

 <ol class="chat">
 
 </ol>
 
 <input class="textarea" type="text" placeholder="Type here!" id="textarea" />
</div>
 <script src="node_modules/jquery/dist/jquery.min.js"></script>
 <script src="node_modules/socket.io-client/socket.io.js"></script>
 <script src="assets/js.js"></script>
</body>
</html>

Repare que eu também criei o diretório assets, e criei os arquivos css.css e js.js.

Não entrarei na parte do CSS, pois o foco aqui é o javascript, mas você pode ver o resultado no github. Eu utilizei como base este pen para construir o layout.

Server-side

Vamos iniciar com a criação da parte de servidor do Socket.io, ou seja, iremos lidar com os eventos server-side.

Iniciaremos criando um arquivo app.js no diretório raíz e importaremos os módulos e faremos algumas operações iniciais:

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

var clients = {};

app.get('/', function(req, res){
res.send('server is running');
});

//SocketIO vem aqui

http.listen(3000, function(){
console.log('listening on port 3000');
});

Este script implementa um servidor Node utilizando os módulos http e express (para roteamento).

A variável clientes que está sendo criada servirá para armazenar nossa lista de clientes.

Agora iremos adicionar o nosso primeiro evento do Socket.io, que será o connection, que dispara a cada vez que um cliente se conecta ao socket.

io.on("connection", function (client) {
    console.log('user connected');
});

Para nossa sala de chat, precisaremos implementar outros 3 eventos: join, senddisconnect:

io.on("connection", function (client) {
  client.on("join", function(name){
    console.log("Joined: " + name);
    clients[client.id] = name;
    client.emit("update", "You have connected to the server.");
    client.broadcast.emit("update", name + " has joined the server.")
  });

  client.on("send", function(msg){
    console.log("Message: " + msg);
    client.broadcast.emit("chat", clients[client.id], msg);
  });

  client.on("disconnect", function(){
    console.log("Disconnect");
    io.emit("update", clients[client.id] + " has left the server.");
    delete clients[client.id];
  });
});

O evento join deverá ser disparado quando o cliente entrar no servidor, adicionando o id do cliente no array e emitindo dois novos eventos, nomeando-os de update.

Note que há uma diferença entre o método client.emit e o client.broadcast.emit. O client.emit enviará a notificação somente para o cliente atual, ou seja, o cliente que acabou de entrar na sala de chat. O client.broadcast.emit irá emitir para todos os clientes conectados, com exceção do que está executando a ação. Se utilizássemos o método io.emit, a mensagem seria enviada a todos os clientes conectados ao socket. Abaixo uma série de exemplos de métodos disponíveis:

// enviar apenas para o cliente atual
client.emit('message', "this is a test");

// enviar para todos os clientes, inclusive o atual
io.emit('message', "this is a test");

// enviar para todos os clientes, exceto o atual
client.broadcast.emit('message', "this is a test");

// enviar para todos os clientes (com exceção do atual) para uma sala específica
socket.broadcast.to('game').emit('message', 'nice game');

// enviar para todos os clientes em uma sala específica
io.in('game').emit('message', 'cool game');

// enviar para o atual, caso ele esteja na sala
client.to('game').emit('message', 'enjoy the game');

// enviar para todos os clientes em um namespace 'namespace1'
io.of('namespace1').emit('message', 'gg');

// enviando para um socketid individual
client.broadcast.to(socketid).emit('message', 'for your eyes only');

Com todos esses métodos, conseguiríamos implementar salas específicas, mensagens individuais, etc. Porém nosso foco é mostrar a parte mais básica e entender o funcionamento.

Client-side

Com nosso servidor concluido e rodando, vamos passar para a parte de client-side de nossa aplicação de chat. Vamos ao js.js.

Primeiramente, inicializaremos o socket.io e criaremos uma variável ready, setada como false. Esta variável será responsável por indicar se o usuário já informou ou não o seu nickname.

$(document).ready(function(){
    var socket = io.connect("http://localhost:3000");
    var ready = false;
});

Com esta implementação, já conseguimos disparar o evento connection em nosso servidor. Porém, precisamos fazer com que o servidor receba a informação cada vez que um novo usuário entrar na sala informando o seu nickname.

$("#submit").submit(function(e) {
    e.preventDefault();
    $("#nick").fadeOut();
    $("#chat").fadeIn();
    var name = $("#nickname").val();
    var time = new Date();
    $("#name").html(name);
    $("#time").html('First login: ' + time.getHours() + ':' + time.getMinutes());

    ready = true;
    socket.emit("join", name);
});

A função jQuery acima captura a submissão do formulário de nickname, fecha a tela de seleção de nick, mostra a tela de chat, seta a variável ready para true e executa um comando de socket, o socket.emit, que informa para o nosso servidor que um novo usuário acabou de entrar na sala.

Nada irá acontecer, pois ainda não temos o receptor do evento update, que está sendo disparado no nosso servidor, então vamos criá-lo:

socket.on("update", function(msg) {
    if (ready) {
        $('.chat').append('<li class="info">' + msg + '</li>')
    }
});

Este código fará com que, a cada vez que o servidor emitir um update, o jQuery adicione uma nova linha no chat com a mensagem retornada.

Agora, iremos fazer com que nossa aplicação envie as mensagens ao servidor a cada vez que o cliente apertar o enter no input de texto:

$("#textarea").keypress(function(e){
    if(e.which == 13) {
         var text = $("#textarea").val();
         $("#textarea").val('');
         var time = new Date();
         $(".chat").append('<li class="self"><div class="msg"><span>'
                      + $("#nickname").val() + ':</span>    <p>' + text + '</p><time>' + 
                      time.getHours() + ':' + time.getMinutes() + '</time></div></li>');
         socket.emit("send", text);
    }
});

E, para concluir, precisamos fazer com que o socket.io observe todas as mensagens referente ao chat em si, e adicione à DOM:

socket.on("chat", function(client,msg) {
 if (ready) {
    var time = new Date();
    $(".chat").append('<li class="other"><div class="msg"><span>' + 
                 client + ':</span><p>' + msg + '</p><time>' + time.getHours() + ':' + 
                 time.getMinutes() + '</time></div></li>');
 }
});

Conclusão

Na minha opinião,  as sockets são uma das melhores funcionalidades do HTML5, e possuem uma infinidade de aplicação. O ganho de performance é espetacular se bem aplicado, uma vez que evita o uso de requisições HTTP em aplicações onde a necessidade de atualização é grande (baixa latência).

Disponibilizei o código do tutorial no github para quem se interessar, e estou aberto a tirar dúvidas.


Este artigo foi escrito por Daniel Campos.

Visite o nosso site para mais posts sobre desenvolvimento web! Tableless.

Source: Tableless

Categorizados em:

Este artigo foi escrito pormajor

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *