IMPORTANT: Per accedir als fitxer de subversion: http://acacha.org/svn (sense password). Poc a poc s'aniran migrant els enllaços. Encara però funciona el subversion de la farga però no se sap fins quan... (usuari: prova i la paraula de pas 123456)

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.

Conceptes i requeriments

Configuració

La configuració la trobareu al fitxer:

config/broadcasting.php

Laravel suporta múltiples drivers per a broadcasting:

  • Pusher: pusher/pusher-php-server ~2.0
  • Redis: predis/predis ~1.0
  • log

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'),

Fer que un esdeveniment faci un Broadcast

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];
}

Redis

Configuració amb Homestead

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

Tutorials

Pusher

Vegeu Pusher

Redis

Laravel echo

Vegeu Laravel echo

Vegeu també

Enllaços externs