Conteúdo


Criar um aplicativo de bate-papo em HTML5 no IBM Cloud com Node.js, Redis e Socket.io

Comments

Até recentemente, a criação de um aplicativo de bate-papo baseado na web não era um projeto simples. O protocolo HTTP torna o bate-papo baseado na web algo difícil de implementar porque sua arquitetura de solicitação-resposta não se adapta bem à natureza em constante atualização do bate-papo. Este artigo mostra que isso tudo mudou, graças ao HTML5 e ao WebSocket API. Você aprenderá a usar a biblioteca Socket.io para criar um aplicativo de bate-papo em tempo real muito rapidamente.

O aplicativo é executado no IBM Cloud, uma plataforma que facilita muito a divulgação de seus aplicativos para todos.

No lado do servidor, o aplicativo descrito neste artigo é alimentado pelo Node.js, o popular tempo de execução do lado do servidor em JavaScript desenvolvido com o V8 JavaScript engine. Ele serve solicitações HTTP regulares usando a estrutura do Express e o mecanismo Jade template . A maior parte do trabalho pesado desse aplicativo é feita pelo Socket.io, mas é fácil implementar no servidor e no cliente. O aplicativo também armazena em cache as 100 mensagens mais recentes em um armazenamento de dados Redis . O aplicativo é executado no IBM Cloud, uma plataforma que facilita muito a divulgação de seus aplicativos para todos.

Executar o aplicativoObtenha o código

O que é necessário para desenvolver o aplicativo

  • Uma familiaridade básica com HTML, CSS e JavaScript
  • Node.js
  • Redis
  • Uma conta do IBM Cloud
  • A interface da linha de comando do IBM Cloud (cf)

Observação: O código-fonte completo para o aplicativo está disponível no IBM DevOps Services. Para resumir, o artigo não inclui listagens completas de código-fonte. Faça o download do código-fonte (clique em Obtenha o código acima) para que seja possível realizar um acompanhamento.

Etapa 1: Criar o aplicativo

Crie um diretório para o aplicativo em seu computador e inclua o arquivo package.json.

    {
      "name": "bluemixchat",
      "version": "0.0.1",
      "private": true,
      "scripts": {
        "start": "node server.js"
      },
      "dependencies": {
      }
}

Instale os módulos de npm necessários:

  • Express
  • Jade
  • Redis
  • Socket.io

Instale esses módulos usando npm install --save express jade redis socket.io.

Este comando instala os módulos do npm (e quaisquer outros módulos que são dependentes) no subdiretório node_modules do seu projeto, e o comando inclui automaticamente esses módulos como dependências em seu arquivo package.json. Como mostrado abaixo, a próxima etapa é fazer com que um esqueleto do aplicativo Express (server.js) seja instalado e esteja funcionando.

    // Inicializar o Aplicativo Express
    var express = require('express');
    var app = express();
    app.listen(process.env.PORT || 3000);

    // Configurar o mecanismo de modelo Jade
    var path = require('path');
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'jade');
    app.use(express.static(path.join(__dirname, 'public')));

    // manipular a solicitação HTTP GET ao "/" URL
    app.get('/', function(req, res) {
      res.render('index');
    });

Na listagem de código anterior, o aplicativo lida com solicitações de entrada para a / URL e renderiza um índice nomeado de visualização. Criar essa visão agora. Primeiro, crie um subdiretório chamado views, e nele, inclua o arquivo index.jade. O conteúdo deste arquivo é mostrado na seguinte listagem de código.

Observação: Este código carrega uma folha de estilo para o estilo do aplicativo a partir do subdiretório público/folha de estilo. Este arquivo de folha de estilo não é abordado no artigo. O arquivo de folha de estilo que contém o código CSS está no código que você transferiu por download do DevOps Services.

    doctype html
    html(lang='en')
      head
        meta(charset='utf-8')
        title Bluemix Chat
        meta(name='viewport', content='initial-scale=1.0, width=device-width, \
         height=device-height, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no')
        link(rel='stylesheet', href='//cdn.jsdelivr.net/normalize/3.0.1/normalize.min.css')
        link(rel='stylesheet', href='/stylesheets/style.css')    
      body
        h1 Bluemix Chat
        form
          input(id='msg', autocomplete='off', autofocus)
          button(type='submit') Send
        ul#messages

O mecanismo do modelo Jade oferece uma forma abreviada de definir páginas em HTML. Observe que ele usa um espaço em branco para determinar a estrutura do documento. Certifique-se de não misturar espaços e tags, e tenha muito cuidado com a forma como você indenta o seu código.

Agora, você deve ser capaz de executar o seu aplicativo. Na linha de comando no diretório do projeto, execute npm start.

Esse comando executa um servidor web em sua máquina na porta 3000. Para ver o aplicativo em ação, aponte seu navegador para http://localhost:3000. Você deverá ver uma janela semelhante à imagem a seguir.

Screen capture shows                     shell IBM Cloud chat
Screen capture shows shell IBM Cloud chat

Etapa 2: Realizar o Push do aplicativo IBM Cloud

Para implementar o aplicativo ao IBM Cloud, use a ferramenta da interface de linha de comando, cf. Se você não a tiver, acesse a página do GitHub do projeto para obter informações sobre como instalá-la. Como alternativa, é possível criar aplicativos e serviços do painel IBM Cloud, mas é necessário ter a ferramenta cf para implementar seu aplicativo; portanto, eu a uso para fazer tudo o que está neste artigo.

Para se conectar à API IBM Cloud e fazer o login usando sua conta IBM Cloud, execute os seguintes comandos:

    cf api https://api.bluemix.net
    cf login

Forneça seu endereço de email e senha depois de inserir o segundo comando.

Aviso: Insira nomes exclusivos e nomes de host para o seu aplicativo quando você implementá-lo ao IBM Cloud. Se usar os nomes fornecidos nestes exemplos, você obterá erros.

Agora, é possível implementá-lo no IBM Cloud usando cf push bluemixchat.

Quando o aplicativo foi implementado, uma mensagem indica que o aplicativo é iniciado e fornece a URL para o aplicativo. Para testar se o aplicativo está funcionando, aponte seu navegador para http://bluemixchat.mybluemix.net. A próxima etapa é ativar o sistema de mensagens em tempo real usando o Socket.io.

Etapa 3. Atualizar clientes em tempo real usando o Socket.io

O Socket.io é um módulo npm que torna muito simples desenvolver aplicativos que usam WebSockets em HTML5 no servidor e no cliente. Quando você ligar o Socket.io ao seu aplicativo Node.js, ele servirá automaticamente a uma biblioteca JavaScript do lado do cliente na URL /socket.io/socket.io.js e é possível usá-lo para realizar o push e receber novas mensagens do servidor.

Para incluir o servidor Socket.io ao aplicativo Express, localize a seguinte linha no arquivo server.js: app.listen(process.env.PORT || 3000);. Substitua esta linha pelo seguinte código:

    var http = require('http').Server(app);
    var io = require('socket.io')(http);
    http.listen(process.env.PORT || 3000);

Este código carrega o módulo HTTP e liga ao servidor Socket.io a ele. O código atende às solicitações de entrada na porta 3000 ou à porta definida na variável de ambiente PORT para o processo atual. Quando o aplicativo é implementado em IBM Cloud, a configuração PORT define qual porta ouvir.

Em seguida, inclua algum código para lidar com os vários eventos no aplicativo de bate-papo e enviar mensagens para os clientes conectados usando o Socket.io. No final do arquivo server.js, inclua o seguinte código.

    // socket.io ouve mensagens
    io.on('connection', function(socket) {
      // Quando uma mensagem é recebida, transmiti-la
      // a todos os usuários, exceto ao cliente autor
      socket.on('msg', function(data) {
        socket.broadcast.emit('msg', data);
      });

      // Quando um usuário se juntar ao bate-papo, enviar um aviso
      // a todos os usuários, exceto ao cliente de origem
      socket.on('join', function(nickname) {
        // Anexar apelido do usuário ao soquete
        socket.nickname = nickname;
        socket.broadcast.emit('notice', nickname + ' has joined the chat.');
      });

      // Quando um usuário se desconectar, enviar um aviso
      // a todos os usuários, exceto ao cliente de origem
      socket.on('disconnect', function() {
        socket.broadcast.emit('notice', socket.nickname + ' has left the chat.');
      });
    });

Agora que o código do lado do servidor está completo, inclua o código no lado do cliente para interagir com o Socket.io. Inclua o seguinte código ao final do arquivo views/index.jade. Observe que esse código deve ser indentado dentro do elemento do corpo no modelo Jade. Se não for, você pode ter problemas.

    script(src='//cdn.jsdelivr.net/jquery/2.1.1/jquery.min.js')
    script(src='/socket.io/socket.io.js')
    script(src='/javascripts/client.js')

Esse código carrega jQuery de uma Content Delivery Network (CDN), o Socket.io do local padrão do servidor torna-o disponível e um arquivo Client.js é armazenado no diretório público/javascripts no seu aplicativo. Criar este arquivo agora. Os seus conteúdos são mostrados abaixo.

    $(document).ready(function() {
      var socket = io(), nickname, msgList = $('#messages');

      // Verificar se o apelido está armazenado em localStorage
      if('localStorage' in window && localStorage.getItem('nickname')) {
        nickname = localStorage.getItem('nickname');
      } else {
        // Se não estiver em localStorage, solicita ao usuário o apelido
        nickname = prompt('Please enter your nickname');
        if('localStorage' in window) {
          localStorage.setItem('nickname', nickname);
        }
      }

      // Enviar mensagem para o servidor avisando que o usuário passou a fazer parte
      socket.emit('join', nickname);

      // Função para incluir uma mensagem à página
      var newMessage = function(data) {
        var who = $('<div class="who">').text(data.nickname),
            when = $('<div class="when">').text(new Date().toString().substr(0, 24)),
            msg = $('<div class="msg">').text(data.msg),
            header = $('<div class="header clearfix">').append(who).append(when),
            li = $('<li>').append(header).append(msg);

        msgList.prepend(li);
      };

      // Manipular o formulário para enviar uma nova mensagem
      $('form').submit(function(e) {
        var msgField = $('#msg'),
            data = { msg: msgField.val(), nickname: nickname, when: new Date() };

        e.preventDefault();
        // Enviar mensagem para o servidor Socket.io
        socket.emit('msg', data);
        // Incluir mensagem à página
        newMessage(data);
        // Limpar o campo de mensagem
        msgField.val('');
      });

      // Quando uma mensagem for recebida do servidor
      // incluí-la à página usando newMessage()
      socket.on('msg', function(data) { newMessage(data); });

      // Quando um aviso for recebido do servidor
      // (o usuário ingressa ou se desconecta), inclua-o à página
      socket.on('notice', function(msg) {
        msgList.prepend($('<div class="notice">').text(msg));
      });
    });

Este código verifica se o usuário já inseriu um apelido, observando o armazenamento localStorage do navegador. Se não, o código solicita que o usuário insira um. O código armazena o apelido no localStorage para uso futuro. Quando a página é carregada, uma mensagem é enviada ao Socket.io para especificar que um novo usuário passou a fazer parte. Quando o formulário de mensagem é enviado, o aplicativo inclui a mensagem na página e envia-a ao servidor. Na última etapa, o aplicativo atende dois eventos do Socket.io, msg enotice, e atualiza a página toda vez que recebe dados desses eventos.

Execute o aplicativo novamente para inserir mensagens e vê-las exibidas na tela. É possível ativar outro navegador e se conectar ao aplicativo para enviar mensagens em um navegador e vê-las por outro. Experimente-o com alguns navegadores e dispositivos — você acabou de desenvolver um aplicativo de bate-papo funcional.

Em seguida, aprenda a armazenar essas mensagens usando um armazenamento de dados Redis.

Etapa 4. Armazene o histórico de mensagens no Redis

Quando você usar o aplicativo, tal como está, observe que quando você atualizar a página, todo o histórico do bate-papo será perdido. Se você estiver usando o aplicativo em um dispositivo móvel, isso cria um problema adicional, pois os usuários móveis tendem a usar aplicativos como este de forma intermitente. Quando os dispositivos forem bloqueados e eles reabrirem o navegador, ele poderá atualizar a página, o que faz com que o histórico seja perdido.

Para resolver isso, armazene o histórico de bate-papo em um armazenamento de dados. O armazenamento Redis facilita o armazenamento de dados como pares de valores-chave, listas, etc. É muito mais rápido do que um banco de dados regular, porque ele armazena dados na memória em vez de armazenar no disco. É perfeito para armazenar dados em cache, o que o torna uma excelente opção para armazenar o histórico de mensagens no aplicativo de bate-papo.

Certifique-se de que o Redis esteja sendo executado em sua máquina local. (Normalmente, isso é feito por meio da execução do comando redis-server). Em seguida, localize a seguinte linha no arquivo server.js: http.listen(process.env.PORT || 3000);. Insira o seguinte código abaixo dessa linha.

    // Configure a conexão do cliente Redis
    var redis = require('redis');
    var credentials;
    // Verifique se estamos no Bluemix ou localhost
    if(process.env.VCAP_SERVICES) {
      // No Bluemix, leia as configurações de conexão da
      // variável de ambiente VCAP_SERVICES
      var env = JSON.parse(process.env.VCAP_SERVICES);
      credentials = env['redis-2.6'][0]['credentials'];
    } else {
      // Em localhost, basta codificar os detalhes da conexão
      credentials = { "host": "127.0.0.1", "port": 6379 }
    }
    // Conecte-se ao Redis
    var redisClient = redis.createClient(credentials.port, credentials.host);
    if('password' in credentials) {
      // No Bluemix, precisamos autenticar com relação ao Redis
      redisClient.auth(credentials.password);
    }

Observação: Quando você implementar o aplicativo Bluemix mais tarde, ele lerá as configurações de conexão para o Redis a partir do VCAP_SERVICES . Este código se conecta e se autentica com relação ao servidor Redis.

Atualize o aplicativo de servidor para realizar o push das novas mensagens para o Redis quando forem recebidas. Localize o seguinte bloco:

    socket.on('msg', function(data) {        
      socket.broadcast.emit('msg', data);        
    });

No início da função anônima, inclua as seguintes linhas.

    redisClient.lpush('messages', JSON.stringify(data));
    redisClient.ltrim('messages', 0, 99);

Este código realiza o push da última mensagem para a lista messages no Redis e, então, corta a lista com os 100 itens mais recentes (se ela possuir mais de 100 itens). A última peça do quebra-cabeça é procurar mensagens existentes no Redis quando o cliente faz a ativação. Para fazer isso, localize o seguinte bloco:

    app.get('/', function(req, res) {
      res.render('index');
    });

Substitua este bloco pelo seguinte código.

    app.get('/', function(req, res) {
      // Receber as 100 mensagens mais recentes do Redis
      var messages = redisClient.lrange('messages', 0, 99, function(err, reply) {
        if(!err) {
          var result = [];
          // Percorrer a lista, analisando cada item em um objeto
          for(var msg in reply) result.push(JSON.parse(reply[msg]));
          // Visualizar a lista de mensagens
          res.render('index', { messages: result });
        } else res.render('index');
      });
    });

Este código obtém os 100 itens mais recentes na lista Redis de messages, percorra-as e analise-as com o JSON em objetos JavaScript. Em seguida, passe um array desses objetos para visualização. Abra o arquivo views/index.jade e aninhe o seguinte código dentro de ul#messages .

    - for(var i=0,ln=messages.length;i<ln;i++)      
      li
        .header.clearfix
          .who= messages[i].nickname
          .when= new Date(messages[i].when).toString().substr(0, 24)
        .msg= messages[i].msg

Ative o aplicativo novamente e envie algumas mensagens. Observe que quando você recarrega a página, o histórico de mensagens é restaurado. Atualmente, o aplicativo não armazena os avisos de join edisconnect do usuário, mas é possível estendê-lo para fazer isso facilmente. Como última etapa, configure o Redis no IBM Cloud e envie por push do produto final para o mundo.

Etapa 5: Criar e ligar-se a um serviço de Redis no IBM Cloud

Realizar o push das mudanças mais recentes no IBM Cloud, fazer a provisão de uma instância de serviço Redis e vinculá-la ao seu aplicativo. Para criar o serviço, use cf create-service redis 100 bmcredis.

Altere o nome do banco de dados (bmcredis no comando anterior) para algo exclusivo. Para que o aplicativo seja capaz de se conectar ao banco de dados, é preciso vinculá-lo: cf bind-service bluemixchat bmcredis.

Reinicie o aplicativo para a ligação se tornar ativa. Envie por push de suas mudanças no IBM Cloud usando o cf push.

Parabéns! Você já desenvolveu um aplicativo de bate-papo usando o Node.js, Redis e o Socket.io, e você o implementou para o IBM Cloud. É possível ver que o aplicativo está instalado e funcionando.

Screen captures                     show IBM Cloud chat in action
Screen captures show IBM Cloud chat in action

Conclusão

O aplicativo que você desenvolveu é um aplicativo de bate-papo totalmente funcional, mas há muitas maneiras possíveis de estendê-lo. É possível permitir que os usuários alterem os seus apelidos ou vejam uma lista de outros usuários conectados. É possível incluir suporte a várias salas, mensagens privadas e muito mais. Como você implementou este aplicativo no IBM Cloud, todos os recursos que você incluir poderão ser implementados com um simples cf push . Não dá para ser muito mais fácil do que isso.


Recursos para download


Temas relacionados


Comentários

Acesse ou registre-se para adicionar e acompanhar os comentários.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Cloud computing
ArticleID=981914
ArticleTitle=Criar um aplicativo de bate-papo em HTML5 no IBM Cloud com Node.js, Redis e Socket.io
publish-date=07222014