DEV Community

Ankit Patel
Ankit Patel

Posted on • Updated on

Complete guide to achieving WebSocket real-time communication with Laravel Broadcast using Pusher, Laravel echo & Web socket

Nowadays, many advanced applications require real-time communication. Laravel has many inbuilt features to cover up the latest technologies and easy implementation. Laravel supports pusher, Redis, and socket.io to develop web socket interfaces.
I'm going to discuss how to set up a web socket communication channel using a self-hosted pusher, laravel echo, and laravel web socket. Using this tutorial, you would be able to configure the setup for your own chat application.

I've divided this tutorial into three steps,

  1. Server-side setup
  2. Client-side setup
  3. Final Execution - Create Broadcast Event & Listen to channel

Server-Side Setup

Step 1

If you're using broadcasting events, you should install a pusher package. Laravel - version 5.3 and above has built-in support for Pusher Channels as a Broadcasting backend.

composer require pusher/pusher-php-server "~4.0" 
Enter fullscreen mode Exit fullscreen mode

Pusher Compatible Laravel Websockets

The laravel-websockets is a pure PHP, Pusher compatible WebSocket package for Laravel. This package allows you to leverage the full power of Laravel broadcasting without an external WebSocket provider or Node. For more information on installing and using this package, please consult its official documentation.

composer require beyondcode/laravel-websockets 
Enter fullscreen mode Exit fullscreen mode

Change in .env

BROADCAST_DRIVER=pusher
APP_URL=http://127.0.0.1:8000
Enter fullscreen mode Exit fullscreen mode

you should add the host and port configuration key to your config/broadcasting.php and add it to the pusher section. The default port of the Laravel WebSocket server is 6001.

'pusher' => [
    'driver' => 'pusher',
    'key' => env('PUSHER_APP_KEY'),
    'secret' => env('PUSHER_APP_SECRET'),
    'app_id' => env('PUSHER_APP_ID'),
    'options' => [
        'cluster' => env('PUSHER_APP_CLUSTER'),
        'encrypted' => true,
        'host' => '127.0.0.1',
        'port' => 6001,
        'scheme' => 'http'
    ],
],
Enter fullscreen mode Exit fullscreen mode

Run Webocket & Test

php artisan websocket:server
Enter fullscreen mode Exit fullscreen mode

Open this URL : http://127.0.0.1:8000/laravel-websockets

Step 2

We use laravel broadcaster service, Let's uncomment following line from config/app.php

 

App\Providers\BroadcastServiceProvider::class
Enter fullscreen mode Exit fullscreen mode

Step 3

By installing pusher package in step 1, We get a new configuration file in the config folder, Let's configure config/broadcasting.php

'pusher' => [
            'driver' => 'pusher',
            'key' => env('PUSHER_APP_KEY'),
            'secret' => env('PUSHER_APP_SECRET'),
            'app_id' => env('PUSHER_APP_ID'),
            'options' => [
                'cluster' => env('PUSHER_APP_CLUSTER'),
                'useTLS' => true,
            ],
        ],
Enter fullscreen mode Exit fullscreen mode

Step 4

As we are not using pusher.com, It's time to change some dummy value in .env. The values shown below are just demoed purposes. It would be more realistic values on production. Why do we want to set dummy values here? You remember in step1 we install the pusher package that enables pusher on hour host, We're using the pusher broadcast driver supported by laravel so let's configure default environment variables.

PUSHER_APP_ID=123456
PUSHER_APP_KEY=scvbmzkmvc
PUSHER_APP_SECRET=xcnmcxdfgvc
PUSHER_APP_CLUSTER=mt1
BROADCAST_DRIVER=pusher
QUEUE_CONNECTION=sync
Enter fullscreen mode Exit fullscreen mode

Step 5

Don't forget to check csrf tag in app.blade.php. Channel authentication will need csrf-token.

<meta name="csrf-token" content="{{ csrf_token() }}">
Enter fullscreen mode Exit fullscreen mode

Configuration on Client Side

We're going to add client-side code that enables communication from HTTP to a socket server using laravel echo

Step 1

You need client-side pusher js library that supports web browsers, web workers, Node.js and React Native.

npm install - save pusher-js
Enter fullscreen mode Exit fullscreen mode

Step 2

Laravel Echo is a JavaScript library that makes it painless to subscribe to channels and listen for events broadcast by Laravel.
npm install - save laravel-echo pusher-js

Step 3

Comment Vue.js in resources/js/app.js, if you're not using it. 

Step 4

Remove comment from resources/js/bootstrap.js and add Hosts

 

import Echo from 'laravel-echo'; 
window.Pusher = require('pusher-js'); 
window.Echo = new Echo({
     broadcaster: 'pusher',
     key: process.env.MIX_PUSHER_APP_KEY,
     cluster: process.env.MIX_PUSHER_APP_CLUSTER,
     forceTLS: true,
     wsHost: window.location.hostname,
     wsPort: 6001
});
Enter fullscreen mode Exit fullscreen mode

Your laravel-echo-server.json should look like this,

{
    "authHost": "http://127.0.0.1:8000",
    "authEndpoint": "/broadcasting/auth",
    "clients": [
        {
            "appId": "626725232e738e727",
            "key": "4ac7dd96bc51f1f345344381230f2644737d"
        }
    ],
    "database": "redis",
    "databaseConfig": {
        "redis": {
      "port": "6379",
      "host": "127.0.0.1",
      "keyPrefix": ""
        }
    },
    "devMode": true,
    "host": null,
    "port": "8081",
    "protocol": "http",
    "socketio": {},
    "secureOptions": 67108864,
    "sslCertPath": "",
    "sslKeyPath": "",
    "sslCertChainPath": "",
    "sslPassphrase": "",
    "subscribers": {
        "http": true,
        "redis": true
    },
    "apiOriginAllow": {
        "allowCors": true,
        "allowOrigin": "http://localhost:80",
        "allowMethods": "GET, POST",
        "allowHeaders": "Origin, Content-Type, X-Auth-Token, X-Requested-With, Accept, Authorization, X-CSRF-TOKEN, X-Socket-Id"
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 5

Compile client-side js and get ready!!!

Run - npm run dev
Enter fullscreen mode Exit fullscreen mode

Final Execution - Create Broadcast Event & Listen to channel

Step 1 - Create Event

Create TestEvent.php in App/Events

<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class TestEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
public $count;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct()
{
$this->message =  'hello';
$this->count = 1;
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn(){
    return new Channel('test');
}
public function broadcastWith(){
    return ['message' => str_random(15)];
}
}
Enter fullscreen mode Exit fullscreen mode

Step 2- Listen channel in App.blade.php

<script src="{{ asset('/js/app.js') }}"></script>
<script>
Echo.channel('private-test')
    .listen('TestEvent', (e) => {
         console.log(e);
    })
</script>
Enter fullscreen mode Exit fullscreen mode

Verify CSRF token once again!! Server-side setup - Step 5
Execution

1. Start laravel echo server

laravel-echo-server start
Enter fullscreen mode Exit fullscreen mode

2. Start websocket server

php artisan websocket:server
php artisan queue:work 
Enter fullscreen mode Exit fullscreen mode

3. Recompile app.js

npm run dev
Enter fullscreen mode Exit fullscreen mode

4. Fire an event using php tinker, you should have a console log in the browser.

php artisan tinker
event(new \App\Events\TestEvent());
Enter fullscreen mode Exit fullscreen mode

Conclusion

We've implemented a basic setup of all components required to listen to the channel for real-time communication. We've seen how to set up a web socket with help of a pusher library using laravel broadcasting on the self-host.

Discussion (9)

Collapse
anthony9981 profile image
Anthony Nguyen

Why you need laravel-echo-server here? I don't think it necessary here.

Currently, the Pusher information now required and beyondcode/laravel-websockets now require real pusher tokens. I don't know why.

Collapse
zaifsenpai profile image
Zaif Senpai

This tutorial was good in the start but it has left so many questions unanswered in the end. I think that you just copied most of the things from a different blog where laravel-echo-server was being used.

-1

Collapse
ankitmpatel profile image
Ankit Patel Author • Edited on

This was documented by me at the time when I configured everything step by step. I thought to share my steps with community. Let me know what kind of questions you have. I'll try to make this article useful with more information. I used pusher intially, and then moved to Redis

Collapse
benndip profile image
Benndip

Please your broadcastOn channel is 'test' but instead in Echo you listen instead to 'private-test'

Why ?

Collapse
eugenevdm profile image
Eugene van der Merwe

Why do you use queue:work?

Collapse
ankitmpatel profile image
Ankit Patel Author

That depends on the method you follow.

Let say, QUEUE_CONNECTION=database and When you fire an event "event(new \App\Events\TestEvent());" Those events drop in a database queue. We need queue:work at that time.

Generally, Queues are recommended that prevents block on the frontend.

Collapse
ekomuliyo profile image
Eko Muliyo

can you show, whats config in file laravel-echo-server.json, because i think your topic is missed information when run laravel-echo-server start

Collapse
ankitmpatel profile image
Ankit Patel Author

I've added sample laravel-echo-server.json in the article.

Collapse
neoacevedo profile image
neoacevedo

Where is stored the file laravel-echo-server.json?