Artigo original: How to use Laravel with Socket.IO
Escrito por: Adnan Sabanovic
Nota da tradução: no momento da tradução, o Laravel já está em sua versão 10. Algumas coisas podem ter mudado da versão anterior para esta. A documentação da versão 5.6, porém, segue disponível no site.
Websockets são legais. Eles são realmente úteis se você quiser mostrar atividades dos seus usuários em tempo real (ou talvez alguns trabalhos de fila).
Bem, se você tiver medo da palavra "Websockets", pode se tranquilizar. Apresentarei aqui as instruções sobre como você pode usá-lo e estarei por perto para responder às suas perguntas, se precisar.
Eu passei por esse desafio onde eu precisava de websockets para mostrar uma lista de pessoas que estavam naquele momento visualizando um URL específico no Laravel. Então, comecei a pensar. Parte de mim queria fazer um ajuste rápido (felizmente, esse não é o meu lado mais forte). O outro, porém, queria construir algo legal, reutilizável e duradouro.
"Por que não usar o Pusher, simplesmente?"
Pois então...
O Laravel vem com o Pusher habilitado. Embora o Pusher pareça uma solução rápida "Plug and play" (e é), ele vem com limitações. Confira https://pusher.com/channels/pricing
A maioria dos tutoriais engana você com seu título de implementação de Websockets quando, na realidade, eles só querem empurrar o Pusher (minha parte favorita é quando eles dizem que você pode facilmente mudar para o socket.io).
"Queremos um número ilimitado de conexões"
Não queremos ter de nos preocupar com limitações.
Então, vamos começar.
Estou usando o vagrant/homestead.
Para isso, precisaremos ler sobre broadcasting de eventos (texto em inglês).
Algumas coisas que merecem ser observadas (para eu não precisar repeti-las depois):
1. Interface ShouldBroadcast para eventos
2. Permitir rotas de broadcasting e usar routes/channels.php
para autenticar os usuários
3. Canal público — todos podem usar
4. Canal privado — você precisa autorizar os usuários antes que eles possam entrar no canal
5. Canal de presença — como no canal privado, mas você pode passar diversos metadados adicionais no canal e obter uma lista das pessoas que entraram no canal por meio do método de evento channel.broadcastOn()
.
Crie seu evento
php artisan make:event MessagePushed
Você pode até mesmo seguir o exemplo específico na documentação de broadcasting (algo que realmente deveríamos fazer).
Instale o Redis
Antes disso, eu configurei, de fato, filas com o Supervisor/Redis/Horizon. O Horizon é ótimo e você pode encontrar informações sobre ele aqui (em inglês): https://laravel.com/docs/5.6/horizon
Depois de botar as filas a funcionar, aquele evento MessagePushed
precisará usar as filas.
Nota: para que tudo isso funcione, não se esqueça de editar seu arquivo .env
:
BROADCAST_DRIVER=redis
QUEUE_DRIVER=redis
(essa linha, na verdade, é da configuração do Horizo, mas precisaremos dela depois)
REDIS_PASSWORD=null
REDIS_PORT=6379
Instale o Laravel Echo Server
Esta é a parte onde instalamos realmente o servidor do socket.io, que vem com o laravel-echo-server
. Você pode encontrar mais sobre isso aqui: https://github.com/tlaverdure/laravel-echo-server
Nota: confira os requisitos na parte superior do documento!
Execute o seguinte (conforme indicado na documentação)
npm install -g laravel-echo-server
Depois, execute o init para obter o arquivo laravel-echo-server.json
gerado na raiz (pois precisamos configurá-lo).
laravel-echo-server init
Ao gerar o arquivo laravel-echo-server.json, ele deve ter esta aparência:
{
"authHost": "http://local-website.app",
"authEndpoint": "/broadcasting/auth",
"clients": [
{
"appId": "my-app-id",
"key": "my-key-generated-with-init-command"
}
],
"database": "redis",
"databaseConfig": {
"redis": {},
"sqlite": {
"databasePath": "/database/laravel-echo-server.sqlite"
},
"port": "6379",
"host": "127.0.0.1"
},
"devMode": false,
"host": null,
"port": "6601",
"protocol": "http",
"socketio": {},
"sslCertPath": "",
"sslKeyPath": "",
"sslCertChainPath": "",
"sslPassphrase": ""
}
Nota: se quiser enviar isso para seu servidor público, não se esqueça de adicionar o laravel-echo-server.json ao seu .gitignore. Gere esse arquivo no servidor, ou precisará alterar o authHost toda a hora.
Execute o Laravel Echo Server
Você precisa executá-lo para iniciar os websockets.
laravel-echo-server start
(na raiz do projeto — onde se encontra o laravel-echo-server.json)
Ele deve iniciar com sucesso. Agora, queremos adicioná-lo ao supervisor em seu servidor, de maneira que seja iniciado automaticamente e reiniciado caso ocorra algum erro.
Em /etc/supervisor/conf.d/laravel-echo.conf (simplesmente crie esse arquivo dentro da pasta conf.d), coloque o seguinte:
[program:laravel-echo]
directory=/var/www/pasta-do-site
process_name=%(nome_do_programa)s_%(nome_do_processo)02d
command=laravel-echo-server start
autostart=true
autorestart=true
user=your-linux-user
numprocs=1
redirect_stderr=true
stdout_logfile=/var/www/pasta-do-site/storage/logs/echo.log
Vá para o diretório raiz do projeto do Laravel e execute pwd
para obter o caminho para o directory
acima e para o prefixo de stdout_logfile
.
Seu usuário será o usuário do Linux (vagrant, Ubuntu, ou algum outro)
Salve o arquivo e saia.
Se você usou vim laravel-echo.conf
, dentro dele, pressione I (de 'Igreja') no teclado para editar um arquivo com o VIM e ESC seguido de :wq! para fechar o arquivo e salvá-lo.
Em seguida, precisamos executar os comandos abaixo:
sudo supervisorctl stop all sudo supervisorctl reread
sudo supervisorctl reload
Depois disso, conferimos se o Laravel Echo está em execução
sudo supervisorctl status
Instale o Laravel Echo e o client do Socket IO
npm install --save laravel-echo
npm install --save socket.io-client
Depois, no seu bootstrap.js (estou usando o Vue.js), registre o Echo
import Echo from "laravel-echo"window.io = require('socket.io-client');
// Use isso no caso de parar de executar o laravel echo server
if (typeof io !== 'undefined') { window.Echo = new Echo({ broadcaster: 'socket.io', host: window.location.hostname + ':6001', });}
Agora, conferimos novamente como "escutar" eventos nos canais específicos (na documentação). Seguindo a documentação de broadcasting do Laravel que compartilhamos acima, se você definir seu método broadcastOn() para que retorne um new PresenceChannel (explicarei meu caso específico, mas fique à vontade para perguntar caso precise implementar alguma outra coisa – acho isso bastante complexo, mais do que simplesmente usar um canal público, para que possamos dimensionar sem problemas). Então, precisamos "escutar" naquele canal no lado do Javascript (front-end).
Aqui vai um exemplo concreto:
- Enviei um evento para um canal de presença (estava tratando de pesquisas – em inglês, "surveys")
public function broadcastOn()
{
return new PresenceChannel('survey.' . $this->survey->id);
}
2. Depois de enviar o evento, ele passará por channels.php. Lá, queremos criar uma autorização para esse usuário (lembre-se de retornar um array para autorização de canal de presença e não um booleano).
Broadcast::channel('survey.{survey_id}', function ($user, $survey_id) {
return [
'id' => $user->id,
'image' => $user->image(),
'full_name' => $user->full_name
];
});
3. Em seguida, no meu componente do VueJs que carrega na página que eu quero monitorar, defini um método que será iniciado a partir do método created()
no carregamento:
listenForBroadcast(survey_id) {
Echo.join('survey.' + survey_id)
.here((users) => {
this.users_viewing = users;
this.$forceUpdate();
})
.joining((user) => {
if (this.checkIfUserAlreadyViewingSurvey(user)) {
this.users_viewing.push(user);
this.$forceUpdate();
}
})
.leaving((user) => {
this.removeViewingUser(user);
this.$forceUpdate();
});
},
Logicamente, retirei parte desse código de um contexto aqui, mas tenho esse array chamado users_viewing
para acompanhar os usuários que entraram naquele canal.
Em princípio, era isso.
Espero que você tenha conseguido acompanhar. Tentei ser o mais detalhado possível.
Uma ótima programação para você!