Monday 22 January 2024

laravel websocket setup and example how to use it

For Laravel Websocket Integration Step By Step


  1. Install Laravel Websocket Packages

    Official site : Laravel Websocket

    

Step 1
 
  Command : composer require beyondcode/laravel-websockets


  

  

  Facing Issue Some time using above command laravel-websocket not install so you can write below

  Command


  Command : composer require beyondcode/laravel-websockets -w


  Get Reference : Link


 

Step 2

Command : php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="migrations"




Step 3

Command : php artisan migrate





Step 4
You need to publish the WebSocket configuration file:

Command :  php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="config"



2) Install Pusher


Step 1 :
  Command : composer require pusher/pusher-php-server




Step2 :
  Open your .env and Change Below things
If you using http then change below thing in env
Http
  BROADCAST_DRIVER=pusher

  PUSHER_APP_ID=anyappid
PUSHER_APP_KEY=anyappkey
PUSHER_APP_SECRET=anyappsecret
PUSHER_HOST=
PUSHER_PORT=
PUSHER_SCHEME=
PUSHER_APP_CLUSTER=mt1
REDIS_PREFIX=
LARAVEL_WEBSOCKETS_PORT=6001
If you are using https then change below thing in .env
Https
  BROADCAST_DRIVER=pusher

  PUSHER_APP_ID=anyappid
PUSHER_APP_KEY=anyappkey
PUSHER_APP_SECRET=anyappsecret
PUSHER_HOST=
PUSHER_PORT=
PUSHER_SCHEME=
PUSHER_APP_CLUSTER=mt1
REDIS_PREFIX=
//for this parameter added if are using https give you ssl certificate path
LARAVEL_WEBSOCKETS_SSL_LOCAL_CERT = /var/www/html/b_laravel/ssl_cert/apache-selfsigned.pem
LARAVEL_WEBSOCKETS_SSL_LOCAL_PK   = /var/www/html/b_laravel/ssl_cert/apache-selfsigned-key.pem
LARAVEL_WEBSOCKETS_SSL_PASSPHRASE = ""
LARAVEL_WEBSOCKETS_PORT=6001



Step 3 :

config/broadcasting.php

In this if Two way Setup if you are using http then socket work on ws and if you are using https
Wss

1)If You are using Http then below change in your config/broadcasting.php file

  Reference site :link

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

2)If You are using Https then below change in your config/broadcasting.php file
'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'),
            'host' => '127.0.0.1',
            'encrypted' => true,
            'port' => 6001,      
            'scheme' => 'https',
            'debug' => true,
            'useTLS' => true,
            'curl_options' => [
            CURLOPT_SSL_VERIFYHOST => 0,
            CURLOPT_SSL_VERIFYPEER => 0,
            ]
    ],

'client_options' => [
    'verify' => false,
    // Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
],


3) Change in  config/websockets.php

1)If You are using Http then below change in your config/websockets.php file
 
'apps' => [
        [
            'id' => env('PUSHER_APP_ID'),
            'name' => env('APP_NAME'),
            'key' => env('PUSHER_APP_KEY'),
            'secret' => env('PUSHER_APP_SECRET'),
            'path' => env('PUSHER_APP_PATH'),
            'capacity' => null,
            'enable_client_messages' => false,
            'enable_statistics' => true,
        ],

1)If You are using Https then below change in your config/websockets.php file
'apps' => [
        [
            'id' => env('PUSHER_APP_ID'),
            'name' => env('APP_NAME'),
            'key' => env('PUSHER_APP_KEY'),
            'secret' => env('PUSHER_APP_SECRET'),
            'path' => env('PUSHER_APP_PATH'),
            'capacity' => null,
            'enable_client_messages' => false,
            'enable_statistics' => true,
        ],

  

In ssl part you have to add below three parameter
 
  1)verify_peer
  2)verify_peer_name
  3)allow_self_signed

  'ssl' => [
        /*
        * Path to local certificate file on filesystem. It must be a PEM encoded file which
        * contains your certificate and private key. It can optionally contain the
        * certificate chain of issuers. The private key also may be contained
        * in a separate file specified by local_pk.
        */
        'local_cert' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_CERT', null),

        /*
        * Path to local private key file on filesystem in case of separate files for
        * certificate (local_cert) and private key.
        */
        'local_pk' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_PK', null),

        /*
        * Passphrase for your local_cert file.
        */
        'passphrase' => env('LARAVEL_WEBSOCKETS_SSL_PASSPHRASE', null),

        'verify_peer' => false,
        'verify_peer_name' => false,
        'allow_self_signed' => true,
    ],


4)routes/web.php
Add this line
  Route::post('/broadcasting/auth', function () {
  return Auth::user();
});




5)config/app.php

In order to turn on broadcasting for any Laravel application, we need to go to config/app.php and uncomment:

App\Providers\BroadcastServiceProvider::class,




3) Install Laravel Echo and Pusher.js

   Command : npm install --save laravel-echo pusher-js


  

Step1 : Change in resources/js/bootstrap.js

import axios from 'axios';
window.axios = axios;

let token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}


window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

/**
* Echo exposes an expressive API for subscribing to channels and listening
* for events that are broadcast by Laravel. Echo and event broadcasting
* allows your team to easily build robust real-time web applications.
*/

import Echo from 'laravel-echo';

import Pusher from 'pusher-js';


window.Pusher = Pusher;
//console.log(window.location.hostname);
window.Echo = new Echo({
    broadcaster: 'pusher',
    key: 'anyappkey',
    cluster: 'mt1',
    wsHost: window.location.hostname,
    wsPort: 6001,
    wssPort: 6001,
    forceTLS: true,
    disableStats: true,
   
});

If you are using http then you to connect using below code
window.Pusher = Pusher;
window.Echo = new Echo({
    broadcaster: 'pusher',
    key: 'anyappkey',
    cluster: 'mt1',
    wsHost: window.location.hostname,
    wsPort: 6001,
    wssPort: 6001,
    forceTLS: false,
    disableStats: true,
   
});

wsPort and wssPort port you can change with your requirement 



4)Install supervisord


   Command : sudo apt install supervisor

 
How config Supervisor in ubuntu system
  1) Go to : cd /etc/supervisor/conf.d/

  1. Create file websockets.conf using sudo nao websockets.conf

  2. Write below details

Change your laravel project path : /var/www/html/b_laravel/artisan

[program:websockets]

command=/usr/bin/php /var/www/html/b_laravel/artisan websockets:serve

numprocs=1

autostart=true

autorestart=true

user=root

  4)sudo service supervisor restart


  5)check status your websocket : sudo service supervisor status



 5)How to setup virtual host in nginx for https



Official website : Link

Need to add only this thing


map $http_upgrade $type {
  default "web";
  websocket "ws";
}

location @web {
        try_files $uri $uri/ /index.php?$query_string;
    }
   
    location @ws {
        proxy_pass             http://127.0.0.1:6001;
        proxy_set_header Host  $host;
        proxy_read_timeout     60;
        proxy_connect_timeout  60;
        proxy_redirect         off;

        # Allow the use of websockets
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }

6)How to setup virtual host in apache2 for https


Add this proxy pass parameter in you apache2 also check that in you apache proxy pass enable or not

Please check in this site : Link
Fire below command

sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_balancer
sudo a2enmod lbmethod_byrequests

sudo systemctl restart apache2


SSLEngine on

                SSLCertificateFile      /etc/ssl/certs/apache-selfsigned.crt
                SSLCertificateKeyFile /etc/ssl/private/apache-selfsigned.key

                ProxyPass /ws ws://localhost:6001/
                ProxyPassReverse /ws ws://localhost:6001/



Note : When anything Change Then Please restart the supervisor. If you have not use
We supervisor then you have to restart websocket


1)if you use supervisor restart : sudo service supervisor restart


2)if you use websocket direct   : php artisan websockets:restart

You have clean websocket log using scheduler and manually command also

php artisan websockets:clean 


Link




//app/Console/Kernel.php

protected function schedule(Schedule $schedule)
{
  $schedule->command('websockets:clean')->daily();
}


7)Laravel WebSocket Example step by step




1)Create ChatController
php artisan make:controller ChatController


2)import app.js and app.css if not in global level
  For reference : https://stackoverflow.com/questions/73331352/how-import-own-js-file-into-vite
  @vite(["resources/css/app.css","resources/js/app.js"])


3)fire command :  npm run build 


4)Create Event Using below Command
  Command : php artisan make:event NewMessage


  Below Change you have to do


 

<?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 ChatEvent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;
    public $somedata;
    /**
    * Create a new event instance.
    */
    public function __construct($somedata)
    {
        $this->somedata = $somedata;
    }

    /**
    * Get the channels the event should broadcast on.
    *
    * @return array<int, \Illuminate\Broadcasting\Channel>
    */
    public function broadcastOn(): Channel
    {
        return new Channel('ChatMessageChannel');
    }
}



1)class ChatEvent  to class ChatEvent implements ShouldBroadcast

2)create : public $somedata;

3)__construct method pass $somedata and assing $this->somedata = $somedata;

public function __construct($somedata)

    {

        $this->somedata = $somedata;

    }

4)

  - Change public function broadcastOn(): Array to  public function broadcastOn(): Channel

  -  return [ new PrivateChannel('channel-name'),];  to return new Channel('ChatMessageChannel');


public function broadcastOn(): Channel

{

    return new Channel('ChatMessageChannel');

}



5)routes/channels.php

Add This

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


6)routes/web.php


  

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ChatController;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "web" middleware group. Make something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});
Route::get('chat', [ChatController::class, 'index'])->name('chat');
Route::Post('sendmessage', [ChatController::class, 'sendmessage'])->name('sendmessage');
Route::get('broadcastmessage', [ChatController::class, 'getmessage'])->name('broadcastmessage');

Route::post('/broadcasting/auth', function () {
  return Auth::user();
});



1)in this three method need to add

1)Route::get('chat', [ChatController::class, 'index'])->name('chat');

  -For Message Send UI

2)Route::Post('sendmessage', [ChatController::class, 'sendmessage'])->name('sendmessage');

  -For Message Send 

3)Route::get('broadcastmessage', [ChatController::class, 'getmessage'])->name('broadcastmessage');

-for received socket message



7)app/Http/Controllers/ChatController.php


<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
use Pusher\Pusher;
class ChatController extends Controller
{
    public function index()
    {
    return view('chat');
    }
    public function sendmessage(Request $request)
    {
    //dd($request->all());
    $sendData['name'] = $request->your_name;
    $sendData['message'] = $request->send_meesage;
    $paramater['chanel'] = "guest_user";
    $paramater['event'] = "ChatEvent";
    $paramater['data'] = $sendData;
    try {
$pusher = new Pusher(

    config('broadcasting.connections.pusher.key'),
    config('broadcasting.connections.pusher.secret'),
    config('broadcasting.connections.pusher.app_id'),
    config('broadcasting.connections.pusher.options', []),
    new \GuzzleHttp\Client(['verify' => false]),
);
  $pusher->trigger($paramater['chanel'], $paramater['event'], $paramater['data']);
} catch (Exception $e) {
// Handle Pusher API error
// You might log the error, notify administrators, or respond to the client accordingly
  dd($e->getMessage());
}
return Redirect::to('/chat')->with(['type' => 'success','message' => 'Your message sent sucessfully']);
    }
    public function getmessage()
    {
    return view('get_message');
    }
}


1)In controller first you have to add two namespace

1) use Illuminate\Support\Facades\Redirect;

-for redirect 

2) use Pusher\Pusher;

--for pusher message send


2)

public function index()

    {

     return view('chat');

    }

 -in this i have added for ui Message sent



 3)function sendmessage


  - for pusher throw send message you have to manage 

  1)channel - which channel you have to send data

  2)event  - which event you have to pass data throw

  3)data   - you have to pass data to create array



  -

 

$pusher = new Pusher(

    config('broadcasting.connections.pusher.key'),
    config('broadcasting.connections.pusher.secret'),
    config('broadcasting.connections.pusher.app_id'),
    config('broadcasting.connections.pusher.options', []),
    new \GuzzleHttp\Client(['verify' => false]),
);


-this code for configure pusher message in this new \GuzzleHttp\Client(['verify' => false]),

this option we have to pass when we have use self signed certificate or our ssl not working then

we have to use this option


     - 

     $pusher->trigger($paramater['chanel'], $paramater['event'], $paramater['data']);


     -this line triggers data for a particular channel.



     4)getmessage

       - in this blade file we have to listen particular channel




8) send message ui blade file : resources/views/chat.blade.php


<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Laravel</title>

        <!-- Fonts -->
        <link rel="preconnect" href="https://fonts.bunny.net">
        <link href="https://fonts.bunny.net/css?family=figtree:400,600&display=swap" rel="stylesheet" />
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
        <script src="https://code.jquery.com/jquery-1.12.4.js" integrity="sha256-Qw82+bXyGq6MydymqBxNPYTaUXXq7c8v3CwiYwLLNXU=" crossorigin="anonymous"></script>
        @vite(["resources/css/app.css","resources/js/app.js"])
        <meta name="csrf-token" content="{{ csrf_token() }}">
    </head>
    <body class="antialiased">
        <div class="container">
      <form method="post" action="{{route('sendmessage')}}">
          <div class="form-group">
            <label for="your_name">Your Name</label>
            <input type="text" class="form-control" id="your_name" name="your_name">   
          </div>
          <div class="form-group mb-2">
            <label for="send_meesage">Your Message</label>
            <textarea id="send_meesage" name="send_meesage" class="form-control" ></textarea>
          </div>
            <input type="hidden" name="_token" id="csrf-token" value="{{ Session::token() }}" />
            <button type="submit" class="btn btn-primary">Send</button>
        </form>
    </div>
    </body>
</html>



9) get message ui blade file  : resources/views/get_message.blade.php



<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Laravel</title>

        <!-- Fonts -->
        <link rel="preconnect" href="https://fonts.bunny.net">
        <link href="https://fonts.bunny.net/css?family=figtree:400,600&display=swap" rel="stylesheet" />
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
        <script src="https://code.jquery.com/jquery-1.12.4.js" integrity="sha256-Qw82+bXyGq6MydymqBxNPYTaUXXq7c8v3CwiYwLLNXU=" crossorigin="anonymous"></script>
        @vite(["resources/css/app.css","resources/js/app.js"])
        <meta name="csrf-token" content="{{ csrf_token() }}">
    </head>
    <body class="antialiased">
        <div class="container">
        <div class="row" >
          <div class="col-4"></div>
          <div class="col-4">
            <label>User Name </label> <span style="color: red" id="user_name"></span>
            <br/>
            <label>MessageSend By User </label> <span style="color: red" id="send_user_msg"></span>
          </div>
          <div class="col-4"></div>
        </div>
    </div>
    <script type="text/javascript">
      var chanelName = "guest_user"
     
        $(window).on('load', function () {
            var checkEcho = window.Echo;
          if (typeof checkEcho !== "undefined") {
              window.Echo.channel(chanelName)
              .listen('.ChatEvent', (e) => {
                      alert('socket Send Message Please read on Screen'
                      $("#user_name").html(e.name);
                      $("#send_user_msg").html(e.message);       
              });
         
          }
        });
    </script>
    </body>
</html>



1)in this we have listen particular chanel which send data from socket


var chanelName = "guest_user"
     
        $(window).on('load', function () {
            var checkEcho = window.Echo;
          if (typeof checkEcho !== "undefined") {
              window.Echo.channel(chanelName)
              .listen('.ChatEvent', (e) => {
                      alert('socket Send Message Please read on Screen'
                      $("#user_name").html(e.name);
                      $("#send_user_msg").html(e.message);       
              });
         
          }
        });

  - i have pass data in guest_user so i have listen this channel using laravel echo




10)below Url 

1){Domain Name}/chat

2){Domain Name}/broadcastmessage   - this is open different tab or browser when you can get message form pusher you can get alert here and message

3){Domain Name}/laravel-websockets - this graph which you to change socket connect or not


[program:websockets]
command=/usr/bin/php /var/www/html/b_laravel/artisan websockets:serve
numprocs=1
autostart=true
autorestart=true
user=root









2 comments:

  1. The book's background is more attention-grabbing than the textual content. Please consider doing a redesign and adding code highlights if possible.

    ReplyDelete
  2. Live savin, thank you very much!

    ReplyDelete

Thank You For Comment