Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel Echo SocketIO with private channel

Hi everyone I working with Laravel Echo and SocketIO without Vue only jquery, but I have a problem with private channels here I show you that I have two events normal and private channel the normal channel (todocanales of my event HolaEvent) work fine when I lunch the event

use App\Events\HolaEvent;

Route::get('/fire', function () {

    $data = [
        'type'    => 'erhelloror',
        'title'   => 'new article has been published',
        'message' => 'check it out',
        'url'     => 'url',
    ];
    event(new HolaEvent($data));
    return 'done';
});

and in my laravel echo server console show me:

[03:04:47] - 5s6214Rlv51NUgnDAAAA joined channel: todocanales
[03:04:48] - QpxGvCjmaezgHn3aAAAB authenticated for: private-like-received.2jzwpAg1
[03:04:48] - QpxGvCjmaezgHn3aAAAB joined channel: private-like-received.2jzwpAg1
Channel: todocanales
Event: App\Events\HolaEvent
CHANNEL todocanales

and in the browser console, I get

~~~ Object {data: Object, socket: null} ~~~

all perfect, BUT with the privateChannel I have the problem Laravel Echo server don't made anything, and nothing on my console of the user logged, of course, I have running

php artisan queue:listen redis

my private channel I lunch the event in my controller

use App\Events\NewLikePostEvent;

$data = array(
     'user_id' => Hashids::encode($post->user_id),
     'user_name' => $name_user
);

event(new NewLikePostEvent($data));

In the project I have this files:

channels.php

Broadcast::channel('like-received.{id}', function ($user, $id) {
    return true;
});

Broadcast::channel('todocanales', function ($user, $id) {
    return true;
});

bootstrap.js

import Echo from "laravel-echo"

window.Echo = new Echo({
    broadcaster: 'socket.io',
    host: 'http://imagenes.dev:6001'
});

app.js

$(document).ready(function(){

    $.ajaxSetup({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content'),
                'X-Socket-Id': Echo.socketId()
            }
    });

    var receiverId = document.getElementById('receiver_id').value;


    Echo.private('like-received.'+ receiverId).listen('NewLikePostEvent', function(e) {
        console.log("Wena!, a "+e.data.user_name + " le ha gustado uno de tus aportes");
        console.log(e);
    });


    Echo.channel('todocanales').listen('HolaEvent', function(e) {
        console.log(e);
    });

});

for the receiverId I use an input hidden in the footer

<input type="hidden" id="receiver_id" value="{{Hashids::encode(Auth::user()->id)}}" />

and I have two Events

NewLikePostEvent.php

<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

class NewLikePostEvent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;
    public $data;

    public function __construct(array $data = [])
    {
        $this->data = $data;
    }

    public function broadcastOn()
    {
        return new PrivateChannel('like-received.'.$this->data->user_id);

    }
}

HolaEvent.php

<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

class HolaEvent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;
    public $data;

    public function __construct(array $data = [])
    {
        $this->data = $data;
    }

    public function broadcastOn()
    {
        return new Channel('todocanales');

    }
}

My laravel-echo-server.json

{
    "authHost": "http://imagenes.dev",
    "authEndpoint": "/broadcasting/auth",
    "clients": [
        {
            "appId": "ec69415ae1adcbf2",
            "key": "578712cd13fd83f7cadef22742d6728c"
        }
    ],
    "database": "redis",
    "databaseConfig": {
        "redis": {
            "host": "127.0.0.1",
            "port": "6379"
        },
        "sqlite": {
            "databasePath": "/database/laravel-echo-server.sqlite"
        }
    },
    "devMode": true,
    "host": "imagenes.dev",
    "port": "6001",
    "protocol": "http",
    "socketio": {},
    "sslCertPath": "",
    "sslKeyPath": ""
}

.env file (not all but the most important part)

APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:ewoyjfyNjXd0FArdsfdsfsNLV7VQH35s=
APP_DEBUG=true
APP_LOG_LEVEL=debug
APP_URL=http://imagenes.dev
SOCKET_PORT=6001

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=imagenes
DB_USERNAME=root
DB_PASSWORD=secret

BROADCAST_DRIVER=redis
CACHE_DRIVER=redis
SESSION_DRIVER=redis
QUEUE_DRIVER=redis

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

and I have running this socket io script with node server.js

server.js

require('dotenv').config();
const server = require('http').Server();
const io = require('socket.io')(server);
const Redis = require('ioredis');
const redis = new Redis();

server.listen({
    port: process.env.SOCKET_PORT
});

redis.subscribe('*');

console.log(process.env.SOCKET_PORT);


redis.on('like-received.*', function (channel, message) {
    const event = JSON.parse(message);
    io.emit(event.event, channel, event.data);
});

redis.on('todocanales', function (channel, message) {
    const event = JSON.parse(message);
    io.emit(event.event, channel, event.data);
});

and finally my

BroadcastServiceProvider.php

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Broadcast;

class BroadcastServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {

        Broadcast::routes(['middleware' => ['web', 'auth']]);

        require base_path('routes/channels.php');
    }
}

and when execute the event NewLikePostEvent with private channel in the console of queue's have a infinite get

Console Output

?[33m[2017-05-10 07:07:10] Processing:?[39m App\Events\NewLikePostEvent
?[33m[2017-05-10 07:07:12] Processing:?[39m App\Events\NewLikePostEvent
?[33m[2017-05-10 07:07:14] Processing:?[39m App\Events\NewLikePostEvent
?[33m[2017-05-10 07:07:16] Processing:?[39m App\Events\NewLikePostEvent
?[33m[2017-05-10 07:07:18] Processing:?[39m App\Events\NewLikePostEvent
?[33m[2017-05-10 07:07:20] Processing:?[39m App\Events\NewLikePostEvent
?[33m[2017-05-10 07:07:21] Processing:?[39m App\Events\NewLikePostEvent
?[33m[2017-05-10 07:07:23] Processing:?[39m App\Events\NewLikePostEvent
?[33m[2017-05-10 07:07:25] Processing:?[39m App\Events\NewLikePostEvent
?[33m[2017-05-10 07:07:27] Processing:?[39m App\Events\NewLikePostEvent
?[33m[2017-05-10 07:07:29] Processing:?[39m App\Events\NewLikePostEvent
?[33m[2017-05-10 07:07:31] Processing:?[39m App\Events\NewLikePostEvent
?[33m[2017-05-10 07:07:33] Processing:?[39m App\Events\NewLikePostEvent
?[33m[2017-05-10 07:07:35] Processing:?[39m App\Events\NewLikePostEvent
?[33m[2017-05-10 07:07:37] Processing:?[39m App\Events\NewLikePostEvent
?[33m[2017-05-10 07:07:38] Processing:?[39m App\Events\NewLikePostEvent
?[33m[2017-05-10 07:07:40] Processing:?[39m App\Events\NewLikePostEvent
?[33m[2017-05-10 07:07:42] Processing:?[39m App\Events\NewLikePostEvent
?[33m[2017-05-10 07:07:44] Processing:?[39m App\Events\NewLikePostEvent
?[33m[2017-05-10 07:07:46] Processing:?[39m App\Events\NewLikePostEvent

PS: I know the use of maxTries into the server is only a more onformation of my case the infinite cycle of event

I put the code because maybe can help in the future I hope someone can help me :D

Regards!

like image 209
Diego Cortés Avatar asked May 10 '17 16:05

Diego Cortés


People also ask

How do I listen private channels in Laravel?

Private channels require you to authorize that the currently authenticated user can actually listen on the channel. This is accomplished by making an HTTP request to your Laravel application with the channel name and allowing your application to determine if the user can listen on that channel.

Can I use socket IO with Laravel?

Web socket and Socket.IO in particular make it possible. But Laravel from it side doesn't have direct support for http socket, so we have to implement a little NodeJS Socket.IO server and make possible to push message to it from the Laravel backend.

What is pusher in Laravel?

Pusher Channels acts as a realtime layer between your client and server events, maintaining persistent connections to the clients.

Is Laravel echo free?

Socket servers usually were not that easy to setup, but Laravel Echo Server changes this. This is completely free, you only have to run the socket server yourself.


2 Answers

Fixed!

The problem of that the event is infinite processing and never was processed was because in my event I use:

public function broadcastOn()
{
    return new PrivateChannel('like-received.'.$this->data->user_id);

}

but $data is a array not object it was a typing error of me xD and the name of channel I replaced dot (.) for (-)

'like-received.'.$this->data->user_id

to

'like-received-'.$this->data['user_id']

finally the broadcastOn is

public function broadcastOn()
{
    return new PrivateChannel('like-received-'.$this->data['user_id']);

}

and the rest of code I mixed with the code repo of Parth Vora :) (thanks!) https://github.com/xparthx/laravel-realtime-chat

and I dont needed to use server.js file for this we use Laravel echo server

and the app.js I changed to

window.Echo.private('like-received-'+window.Laravel.user).listen('NewLikePostEvent', function(e) {
    console.log("Wena!, a "+e.data.user_name + " le ha gustado uno de tus aportes");
    console.log(e);

});

You can see that now I use window.Laravel.user this I created on blade file

<script>
        window.Laravel = {
            'csrfToken': '{{ csrf_token() }}',
            'user': '{{Hashids::encode(Auth::user()->id)}}'
        };
 </script>

I hope this will be helpful to someone because I tried 3 days on fix this hahahha :D

like image 63
Diego Cortés Avatar answered Sep 20 '22 00:09

Diego Cortés


This problem is very hard to troubleshoot without complete source code and running app.

So you have the issue with the private channel.

I have implemented all 3 types of channels(private, public & presence) in this chat app, maybe you can get some ideas from it:

https://github.com/xparthx/laravel-realtime-chat

Thanks

like image 43
Parth Vora Avatar answered Sep 17 '22 00:09

Parth Vora