https://laravel.com/docs/5.4/broadcasting
En moltes aplicacions web modernes s'utilitzen els web sockets com una opció per a implementar aplicacions en temps real en web. Quan alguna o algunes dades són actualitzades al servidor el servidor envia un missatge (missatge push o push notification) utilitzant una connexió preestablerta mitjançant web socket per tal que el client reaccioni a aquest canvi. En l'entorn web i concretament amb Laravel el servidor executa codi PHP i el client codi Javascript.
Per tal d'ajudar-nos en la creació d'aquest tipus d'aplicacions Laravel ens proporciona a través dels esdeviments (vegeu Laravel Events) una forma que aquests events no només tinguin un handler (és a dir un codi que reaccioni al succeir l'esdeveniment) en la part del servidor sinó que també pugui reaccionar el client. A aquest tipus d'esdeveniments se'ls anomena de broadcast i es una forma de comunicació entre Laravel i Javascript o el Framework Javascript que haguem escollit per al client.
La configuració la trobareu al fitxer:
config/broadcasting.php
Laravel suporta múltiples drivers per a broadcasting:
Pusher és l'opció per defecte. És un servei de pagament (https://pusher.com/pricing) amb una compte inicial gratis amb un límit de recursos. El servidor push es troba als servidors de pusher i cal tenir en compte que el rendiment serà una mica menor (latència entre servidor propi i servidors pusher)
Redis requereix d'infraestructura pròpia (s'ha de configurar el servidor de notificacions push/Broadcast events) però és gratuït. Amb aquest sistema el servidor web i el servidor de notificacions poden estar a la mateixa màquina eliminant problemes de latència.
Podeu establir el driver amb una variable d'entorn:
$ cat .env | grep BROADCAST BROADCAST_DRIVER=redis
Que s'utilitzarà al fitxer de configuració:
$ cat config/broadcasting.php
... /* |-------------------------------------------------------------------------- | Default Broadcaster |-------------------------------------------------------------------------- | | This option controls the default broadcaster that will be used by the | framework when an event needs to be broadcast. You may set this to | any of the connections defined in the "connections" array below. | */ 'default' => env('BROADCAST_DRIVER', 'pusher'),
Només cal implementar la interfície ShouldBroadcast
class ServerCreated extends Event implements ShouldBroadcast
I com que estem implementant un paradigma Pub/Sub cal indicar el canal al qual publicarem l'esdeveniment amb el mètode broadcastOn:
/** * Get the channels the event should be broadcast on. * * @return array */ public function broadcastOn() { return ['nom del canal']; }
El nom de l'esdeveniment que publicarem al canal ve determinat pel nom de la classe Event (amb els \\, per exemple App\\Event\\EventName) o el podeu canviar amb el mètode:
public function broadcastAs() { return ['app.server-created']; }
i el missage de Broadcast portarà de sèrie com a payload (contingut del missatge) les properties públiques de la classe Event
IMPORTANT: Es poden enviar Models sencers de Laravel, el sistema s'encarrega de serialitzar l'objecte!
També es poden determinar a mida el contingut del missatge amb broadcastWith:
<pre class="brush:php"> /** * Get the data to broadcast. * * @return array */ public function broadcastWith() { return ['user' => $this->user->id]; }
A homestead node.js i npm ja es troba instal·lat comproveu amb:
$ homestead ssh $ node --version v4.1.1 $ npm --version 2.14.4
També trobareu Redis instal·lat comproveu amb:
$ redis-cli ping PONG
I funcionant el servidor redis-server al port 6379:
$ ps aux | grep redis redis 986 0.0 0.3 121276 26660 ? Ssl Oct17 1:37 /usr/bin/redis-server *:6379
Cal instal·lar les llibreries de node.js (es guardaran a la carpeta node_modules) socket.io i ioredis amb:
$ sudo npm install express ioredis socket.io --save
L'opció save modificarà packages.json per tal de poder instal·lar a posteriori amb npm install.
Ara cal crear un fitxer node.js que faci de websocket servidor per al Broadcasting de missatges. Creeu una carpeta al vostre projecte Laravel
$ cd Code/MyLaravel $ mkdir node/broadcast_server/
I aquí creeu un fitxer anomenat socket.js:
$ editor socket.js
//Initialitze library requirements: express, socket.io and ioredires var app = require('express')(); var http = require('http').Server(app); var io = require('socket.io')(http); var Redis = require('ioredis'); //Create new Redis instance var redis = new Redis(); //Example howto subscribe to only one Redis channel //redis.subscribe('test-channel', function(err, count) { //}); //Subscribe to all Redis Channels redis.psubscribe('*', function(err, count) { console.log('Subscribed to ' + count + ' channels') if (err) { console.log('Errors subscribing to channel'); } }); //Broadcast message when recieved from Redis on all channels redis.on('pmessage', function(subscribed,channel, message) { console.log('Message Recieved at channel(' + channel + '): ' + message); message = JSON.parse(message); io.emit(channel + ':' + message.event, message.data); }); //Listen web socket on port 300 http.listen(3000, function(){ console.log('Listening on Port 3000'); });
Ara aquest servei es pot executar manualment amb:
$ node socket.js Listening on Port 3000
Però lo ideal es convertir aquest servidor en un servidor permanent tipus dimoni. Ho podem fer amb Supervisor creeu un fitxer:
$ sudo editor /etc/supervisor/conf.d/socket.conf [program:socket] process_name=%(program_name)s_%(process_num)02d command=/usr/bin/node /home/vagrant/Code/MyLaravel/node/broadcast_server/socket.js autostart=true autorestart=true user=vagrant numprocs=1 redirect_stderr=true stdout_logfile=/home/vagrant/Code/MyApp/storage/logs/socket.log
Apliqueu els canvis amb:
$ sudo /etc/init.d/supervisor restart
Comproveu funciona correctament:
$ ps aux | grep node | grep socket vagrant 8966 0.1 0.6 1073424 49088 ? Sl 16:55 0:00 /usr/bin/node /home/vagrant/Code/MyLaravel/node/broadcast_server/socket.js
Comproveu com si mateu el servidor es torna a executar:
$ kill -9 8966 $ ps aux | grep node | grep socket vagrant 9071 0.0 0.2 701748 20416 ? Rl 17:05 0:00 /usr/bin/node /home/vagrant/Code/MyLaravel/node/broadcast_server/socket.js
I que el fitxer de log funciona correctament:
$ tail -f /home/vagrant/Code/MyLaravel/storage/logs/socket.log Listening on Port 3000
I proveu que pel log es mostren els missatge publicats a redis:
$ redis-cli 127.0.0.1:6379> PUBLISH nomcanal "{\"id\":1,\"name\":\"John\"}"
$ tail -f /home/vagrant/Code/MyLaravel/storage/logs/socket.log ... Message Recieved at channel(provacanal): {"id":1,"name":"John"}
Ara ja podeu utilitzar redis com a driver per a esdeveniments de broadcast (en comptes de l'altre alternativa oficial a data d'avui --acacha (discussió) 17:58, 9 maig 2016 (CEST)):
$ composer require predis/predis
I poseu a fitxer .env:
BROADCAST_DRIVER=redis
Resources
Vegeu Pusher
Vegeu Laravel echo