Neste tutorial, mostrarei como implementar um aplicativo de bate-papo em tempo real com Node.js, Socket.IO e MongoDB e, em seguida, implantaremos esse aplicativo no Modulus juntos.
Antes de mais nada, deixe-me mostrar o visual final do aplicativo que teremos no final do artigo.
Node.js será o núcleo da aplicação, com Express como MVC, MongoDB para o banco de dados e Socket.IO para comunicação em tempo real. Quando terminarmos, implantaremos nosso aplicativo no Modulus. A parte MongoDB realmente existe dentro do Modulus.
1. Cenário
- João deseja usar nosso aplicativo e o abre no navegador.
- Na primeira página, ele seleciona um apelido para usar durante o bate-papo e faz login no bate-papo.
- Na área de texto, ele escreve algo e pressiona Enter.
- O texto é enviado para um serviço RESTful (Express) e esse texto é gravado no MongoDB.
- Antes de escrever no MongoDB, o mesmo texto será transmitido para os usuários que estão logados no aplicativo de bate-papo.
Como você pode ver, este é um aplicativo muito simples, mas cobre quase tudo para um aplicativo da web. Não há sistema de canal neste aplicativo, mas você pode bifurcar o código-fonte e implementar o módulo de canal para praticar.
2. Design do projeto do zero
Vou tentar explicar as pequenas partes do projeto primeiro e combiná-las no final. Vou começar do back-end para o front-end. Então, vamos começar com os objetos de domínio (modelos MongoDB).
2.1. Modelo
Para abstração de banco de dados, usaremos Mongoose. Neste projeto, temos apenas um modelo chamado
Message
. Este modelo de mensagem contém apenas text
, createDate
, e author
User
, porque não implementaremos totalmente um sistema de registro/login de usuário. Haverá uma página simples de fornecimento de apelidos, e esse apelido será salvo em um cookie. Isso será usado na Message
modelo como texto no arquivo author
campo. Você pode ver um exemplo de modelo JSON abaixo:{ text: "Hi, is there any Full Stack Developer here?" author: "john_the_full_stack", createDate: "2015.05.15" }
Para criar documentos como este, você pode implementar um modelo usando as funções do Mongoose abaixo:
var mongoose = require('mongoose') var Message = new mongoose.Schema({ author: String, message: String, createDate: { type: Date, default: Date.now } }); mongoose.model('Message', Message)
Basta importar o módulo Mongoose, definir seu modelo com seus campos e atributos de campo no formato JSON e criar um modelo com o nome
Message
. Este modelo será incluído nas páginas que você deseja usar. Talvez você tenha alguma dúvida sobre por que estamos armazenando a mensagem no banco de dados, quando já transmitimos essa mensagem para o usuário no mesmo canal. É verdade que você não precisa armazenar mensagens de bate-papo, mas eu só queria explicar a camada de integração do banco de dados. De qualquer forma, usaremos este modelo em nosso projeto dentro dos controladores. Controladores?
2.2. Controlador
Como eu disse anteriormente, usaremos o Express para a parte MVC. E
C
aqui significa o Controller
. Para nossos projetos, haverá apenas dois endpoints para mensagens. Um deles é para carregar mensagens de bate-papo recentes e o segundo é para lidar com mensagens de bate-papo enviadas para armazenar no banco de dados e depois difundir no canal. ..... app.get('/chat', function(req, res){ res.sendFile(__dirname + '/index.html'); }); app.get('/login', function(req, res){ res.sendFile(__dirname + '/login.html'); }); app.post('/messages', function(req, res, next) { var message = req.body.message; var author = req.body.author; var messageModel = new Message(); messageModel.author = author; messageModel.message = message; messageModel.save(function (err, result) { if (!err) { Message.find({}).sort('-createDate').limit(5).exec(function(err, messages) { io.emit("message", messages); }); res.send("Message Sent!"); } else { res.send("Technical error occurred!"); } }); }); app.get('/messages', function(req, res, next) { Message.find({}).sort('-createDate').limit(5).exec(function(err, messages) { res.json(messages); }); }); .....
O primeiro e o segundo controladores são apenas para servir arquivos HTML estáticos para as páginas de bate-papo e login. O terceiro é para lidar com a solicitação de postagem para o arquivo
/messages
endpoint para criar novas mensagens. Nesse controlador, primeiro o corpo da solicitação é convertido para o modelo Message e, em seguida, esse modelo é salvo no banco de dados usando a função Mongoose save
. Não vou me aprofundar muito no Mongoose - você pode dar uma olhada na documentação para mais detalhes. Você pode fornecer uma função de retorno de chamada para a função salvar para verificar se há algum problema ou não. Se for bem-sucedido, buscamos os últimos cinco registros classificados em ordem decrescente por
createDate
, e transmitiram cinco mensagens para os clientes no canal. Ok, terminamos
MC
. Vamos mudar para a View
papel. 2.3. Visualizar
Em geral, um mecanismo de modelo como Jade, EJS, Handlebars, etc., pode ser usado no Express. No entanto, temos apenas uma página, e essa é uma mensagem de bate-papo, então servirei estaticamente. Na verdade, como eu disse acima, há mais dois controladores para veicular esta página HTML estática. Você pode ver o seguinte para servir uma página HTML estática.
app.get('/chat', function(req, res){ res.sendFile(__dirname + '/index.html'); }); app.get('/login', function(req, res){ res.sendFile(__dirname + '/login.html'); });
Esse endpoint simplesmente veicula index.html e login.html usando
res.sendFile
. Ambos index.html e login.html estão na mesma pasta que server.js, razão pela qual usamos __dirname
antes do nome do arquivo HTML. 2.4. Front-end
Na página de front-end, usei o Bootstrap e não há necessidade de explicar como consegui fazer isso. Simplesmente, vinculei uma função a uma caixa de texto e sempre que você pressiona a tecla Enter chave ou Enviar botão, a mensagem será enviada para o serviço de back-end.
Esta página também tem um arquivo js necessário do Socket.IO para ouvir o canal chamado
message
. O módulo Socket.IO já é importado no back-end e, quando você usa esse módulo no lado do servidor, ele adiciona automaticamente um endpoint para servir o arquivo Socket.IO js, mas usamos aquele que é servido a partir do cdn <script src="//cdn.socket.io/socket.io-1.3.5.js"></script>
. Sempre que uma nova mensagem chegar a este canal, ela será automaticamente detectada e a lista de mensagens será atualizada com as últimas cinco mensagens. <script> var socket = io(); socket.on("message", function (messages) { refreshMessages(messages); }); function refreshMessages(messages) { $(".media-list").html(""); $.each(messages.reverse(), function(i, message) { $(".media-list").append('<li class="media"><div class="media-body"><div class="media"><div class="media-body">' + message.message + '<br/><small class="text-muted">' + message.author + ' | ' + message.createDate + '</small><hr/></div></div></div></li>'); }); } $(function(){ if (typeof $.cookie("realtime-chat-nickname") === 'undefined') { window.location = "/login" } else { $.get("/messages", function (messages) { refreshMessages(messages) }); $("#sendMessage").on("click", function() { sendMessage() }); $('#messageText').keyup(function(e){ if(e.keyCode == 13) { sendMessage(); } }); } function sendMessage() { $container = $('.media-list'); $container[0].scrollTop = $container[0].scrollHeight; var message = $("#messageText").val(); var author = $.cookie("realtime-chat-nickname"); $.post( "/messages", {message: message, author: author}, function( data ) { $("#messageText").val("") }); $container.animate({ scrollTop: $container[0].scrollHeight }, "slow"); } }) </script>
Há mais uma verificação no código acima:a parte do cookie. Se você não escolheu nenhum apelido para o bate-papo, significa que o cookie não está definido para o apelido e você será redirecionado automaticamente para a página de login.
Caso contrário, as últimas cinco mensagens serão buscadas por uma simples chamada Ajax para o arquivo
/messages
ponto final. Da mesma forma, sempre que você clicar no botão Enviar ou pressione o botão Enter key, a mensagem de texto será buscada na caixa de texto, e o apelido será buscado no cookie, e esses valores serão enviados ao servidor com uma solicitação de postagem. Não há uma verificação rigorosa para o apelido aqui, porque eu queria focar na parte em tempo real, não na parte de autenticação do usuário. Como você pode ver, a estrutura geral do projeto é muito simples. Vamos para a parte de implantação. Como disse anteriormente, usaremos o Modulus, um dos melhores PaaS para implantar, dimensionar e monitorar sua aplicação no idioma de sua escolha.
3. Implantação
3.1. Pré-requisitos
A primeira coisa que me vem à mente é mostrar como implantar, mas para uma implantação bem-sucedida, precisamos de um banco de dados funcional. Vamos dar uma olhada em como criar um banco de dados no Modulus e, em seguida, realizar a implantação.
Vá para o painel do Modulus depois de criar uma conta. Clique em Bancos de dados menu à esquerda e clique em Criar banco de dados.
Preencha os campos obrigatórios no formulário pop-up conforme abaixo.
Ao preencher os campos obrigatórios e clicar em Criar, ele criará um banco de dados MongoDB para você e você verá a URL do banco de dados na tela. Usaremos MONGO URI , então copie esse URI.
Em nosso projeto, o Mongo URI é obtido da variável de ambiente
MONGO_URI
, e você precisa definir essa variável de ambiente no painel. Vá para o painel, clique em Projetos menu, selecione seu projeto na lista e clique em Administração no menu esquerdo. Nesta página, você verá a seção de variáveis de ambiente ao rolar a página, conforme mostrado abaixo. Você pode implantar no Modulus de duas maneiras:
- fazer upload do arquivo ZIP do projeto usando o painel
- implantação a partir da linha de comando usando o Modulus CLI
Vou continuar com a opção de linha de comando, porque a outra é fácil de fazer. Primeiro de tudo, instale o Modulus CLI:
npm install -g modulus
Vá para a pasta do seu projeto e execute o seguinte comando para fazer login no Modulus.
modulus login
Ao executar o comando acima, você será solicitado a inserir um nome de usuário e senha:
Se você criou uma conta usando o GitHub, pode usar o comando
--github
opção. modulus login --github
Agora você está logado no Modulus e é hora de criar um projeto. Use o seguinte comando para criar um projeto:
modulus project create "Realtime Chat"
Ao executar esta função, será solicitado o tempo de execução. Selecione a primeira opção, que é Node.js, e a segunda será solicitado o tamanho do servo, podendo mantê-lo como padrão.
Criamos um projeto, e desta vez vamos implantar nosso projeto atual no Modulus. Execute o seguinte comando para enviar o projeto atual para o Realtime Chat projeto no lado do módulo.
modulus deploy
Ele implantará seu projeto e você obterá a URL do projeto em execução no final da mensagem de implantação bem-sucedida:
Realtime Chat running at realtime-chat-46792.onmodulus.net
Como você pode ver, a implantação no Modulus é muito fácil!
O Modulus CLI tem comandos muito úteis para usar durante a implantação do projeto ou em tempo de execução. Por exemplo, para encerrar os logs do seu projeto em execução, você pode usar
modulus project logs tail
, para criar um banco de dados MongoDB use modulus mongo create <db-name>
, para definir uma variável de ambiente, use modulus env set <key> <value>
, etc. Você pode ver uma lista completa de comandos usando a ajuda do Modulus.