Trabalhando com Laravel e websockets 3

Fanout.io é um serviço que traz uma maneira fácil de adicionar funções real-time para a sua aplicação.

Eu passei a usa-lo no yoble onde tenho um fórum e preciso que as mensagens sejam entregues sem que o usuário tenha que dar um refresh. A primeira opção foi usar ajax utilizando um setTimeout que buscava as mensagens a cada 2 segundos, como o site cresceu ficou inviável essa solução(consome muitos recursos). Após ler e pesquisar descobri ofanout.io que proporcionou uma diminuição de servidores e uma maneira fácil de trabalhar com real-time.

Agora chega de papo e vamos lá, vou mostrar um pequeno exemplo de aplicação real-time com fanout.io e laravel

Após baixar o laravel(suponho que você saiba fazer isso) vamos colocar o package laravel-fanout para trabalhar com fanout.

composer require fanout/laravel-fanout

Agora em config/broadcasting.php vamos adicionar dentro da connections a chaves do fanout, seu arquivo vai ficar semelhante a isso.

<?php

return [

    'default' => env('BROADCAST_DRIVER', 'fanout'),

    'connections' => [

       'fanout' => [
            'driver' => 'fanout',
            'realm_id' => '<my-realm-id>',
            'realm_key' => '<my-realm-key>',
            'ssl' => true,
            'publish_async' => false
        ],

        'redis' => [
            'driver' => 'redis',
            'connection' => 'default',
        ],

        'log' => [
            'driver' => 'log',
        ],

    ],

];

Nesse momento você pode fazer um cadastro e utilizar o plano free para testes.

adicione ao providers

LaravelFanout\FanoutBroadcastServiceProvider::class,

Podemos usar o exemplo disponibilizado no package, vamos criar o arquivo dentro de app/events

<?php namespace App\Events;

use App\Events\Event;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

class PublishToFanoutEvent implements ShouldBroadcast
{
    use SerializesModels;

    public $message;

    public function __construct($message)
    {
        $this->message = $message;
    }

    public function broadcastOn()
    {
        return ['<channel>'];
    }
}

O que esse arquivo faz é enviar uma mensagem para o fanout usando obroadcasting events do laravel, o método broadcastOn() informa o channel que é enviado.

Agora vamos criar os dois templates o index.blade.php e o form.blade.php

<!DOCTYPE html>
<html>
<head>
	<title>Exemplo Laravel e Fanout</title>
	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">

</head>
<body >

<div>
	<h1>Lista de posts</h1>
	<ul id="list">
		<li v-repeat="posts" >
	      @{{title}}
	    </li>
	</ul>
</div>
<script src="http://9b1cf4d8.fanoutcdn.com/bayeux/static/faye-browser-min.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/vue/0.12.10/vue.min.js"></script>
<script type="text/javascript" src="app.js"></script>
</body>
</html>

Agora o form.blade.php

<!DOCTYPE html>
<html>
<head>
	<title>Exemplo Laravel e Fanout</title>
	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">

</head>
<body >

<div id="add" >
	<h1>Digite o título</h1>
	<form  v-on="submit: addPost">
		 <div>
                <input v-model="title" v-el="title" ></input>
            </div>

            <button>
                Adicionar post
            </button>
	</form>	
  @{{msg}}
</div>
<script src="http://9b1cf4d8.fanoutcdn.com/bayeux/static/faye-browser-min.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/vue/0.12.10/vue.min.js"></script>
<script type="text/javascript" src="zepto.js"></script>
<script type="text/javascript" src="app.js"></script>
</body>
</html>

por conveniência vamos trabalhar ainda com vue.js e zepto.js, o importante nesse arquivo é o arquivohttp://9b1cf4d8.fanoutcdn.com/bayeux/static/faye-browser-min.js, deve-se trocar o 9b1cf4d8 pelo Realm ID da sua conta(o mesmo utilizado no config).

var app = new Vue({
  el: '#list',
  data: {
    posts: [
      {
        title: 'Como integrar o fanout com laravel'
      },
    ]
  }
})

var add = new Vue({
  el: '#add',
  data: {
        title: '',
        msg: ''
    },
  methods: {
        addPost: function(e) {
            e.preventDefault();
            if (!this.title) return;
            $.post('/novo', { title: this.title });

            this.title = '';
            this.msg = 'Adicionado com sucesso';
        }
  }      
})

var client = new Faye.Client('http://9b1cf4d8.fanoutcdn.com/bayeux');
client.subscribe('/test', function (item) {
    app.posts.push({ title: item.data.message })
});

 

aqui temos o arquivo app.js que faz a comunicação, da linha 1 a 10 é utilizada é a listagem dos posts para o index e depois é o envio para o websocket.

Você pode testa isso utilizando dois navegadores.

var client = new Faye.Client('http://9b1cf4d8.fanoutcdn.com/bayeux');
client.subscribe('/test', function (item) {
    app.posts.push({ title: item.data.message })
});

Essa última parte é responsável por ficar escutando o channel e assim a cada mensagem enviada ele insere mais um elemento no array.

O mais legal de tudo isso é que você faz apenas a uma inserção no banco de dados e envia para os outros usuários que estão “escutando” o channel e isso diminui muito a carga do servidor.

WebSockets podem ser utilizados para chats, mensagens em tempo real e muitas outras possibilidades, basta usar a imaginação.

No plano free tem uma limitação de 20 clientes e 500 mensagens por dia, não é ruim, mas o plano pago é 25 obamas e 4 obamas por milhão de mensagens enviadas.

O caso do yoble eu economizei 100 obamas em servidores por usar o fanout.

Deixa teu comentário e ai e/ou dúvidas, quem sabe eu escrevo mais.

Repositório desse exemplo: https://github.com/lemesdaniel/fanout-laravel-example

  • mlops

    Quero saber mais sobre isso. Obg, pela contribuição.

    • DanielBatistaLemes

      Vou tentar escrever mais.

  • Igor Trindade

    Muito bacana o tuto! Obrigado por compartilhar!!
    Tenho uma pequena dúvida, no caso você utilizou zepto somente para fazer o $.post? Seria um substituo para o vue resource? E se não for abusar da sua boa vontade, você poderia me dizer pq prefere utilizar zepto ao resource?