Digging Deep

Laravel Driver

Laravel

This package allows the usage of Conveyor as a broadcasting driver in Laravel. Here is the repo: (https://github.com/kanata-php/conveyor-laravel-broadcaster).

To understand how to broadcast with Laravel, visit Broadcasting.

Quick Start

Table of Contents

Step 1: Install the package via composer

1composer require kanata-php/conveyor-laravel-broadcaster

Step 2: Publish the configuration

1php artisan vendor:publish --provider="Kanata\LaravelBroadcaster\ConveyorServiceProvider"

Step 3: Add Service Provider

Laravel 10 backwards:

1<?php
2return [
3    // ...
4    'providers' => [
5        // ...
6        Kanata\LaravelBroadcaster\ConveyorServiceProvider::class,
7    ],
8    // ...
9];

Laravel 11 onwards:

1<?php
2
3return [
4    // ...
5    Kanata\LaravelBroadcaster\ConveyorServiceProvider::class,
6];

Step 4: Enable Laravel broadcasting

This is for Laravel 11 and forward, if in any other version just skip this step!

1php artisan install:broadcasting

Step 5: Add broadcasting config

Add the following to your config/broadcasting.php file:

1<?php
2
3return [
4    // ...
5    'conveyor' => [
6        'driver' => 'conveyor',
7        'protocol' => env('CONVEYOR_PROTOCOL', 'ws'),
8        'host' => env('CONVEYOR_URI', 'localhost'),
9        'port' => env('CONVEYOR_PORT', 8181),
10    ],
11];

Step 6: Protect your channels

1use App\Models\User;
2use Illuminate\Support\Facades\Broadcast;
3
4Broadcast::channel('actions-channel', function (User $user) {
5    return true; // we are authorizing any user here - update according to your needs!
6});

Step 7: Create a user for authorization - if needed

1php artisan tinker

Within tinker, you can create a user:

1App\Models\User::factory()->create(['email' => '[email protected]', 'password' => Hash::make('password')]);

Step 8: Migrate the database

Set the configurations for the WebSocket server in the .env file:

1# ...
2BROADCAST_CONNECTION=conveyor
3# ...
4CONVEYOR_DATABASE=pgsql
5JACKED_SERVER_WEBSOCKET_ENABLED=true
6# ...

CONVEYOR_DATABASE is optional and defaults to mysql.

Then run migrations:

1php artisan migrate

Step 9: Install the Conveyor JS Client:

1npm install socket-conveyor-client

Important: Don't forget to run npm run build!

Add this to the bootstrap.js file of your Laravel app so the Conveyor client is available globally:

1import Conveyor from "socket-conveyor-client";
2
3window.Conveyor = Conveyor;

Remember to run npm install and npm run dev or npm run prod to compile the assets.

Info: If you want to send one-off messages to the Conveyor WebSocket server, you can just dispatch an event like follows:

1<?php
2
3namespace App\Events;
4
5use Illuminate\Broadcasting\InteractsWithBroadcasting;
6use Illuminate\Broadcasting\PrivateChannel;
7use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
8
9class TestEvent implements ShouldBroadcastNow
10{
11    use InteractsWithBroadcasting;
12
13    public function __construct(
14        public string $message,
15        public string $channel,
16    ) {
17        $this->broadcastVia('conveyor');
18    }
19
20    public function broadcastOn(): array
21    {
22        return [
23            new PrivateChannel($this->channel),
24        ];
25    }
26}
1event(new App\Events\TestEvent( message: 'my message', channel: 'my-channel'));

Important: notice that we are using ShouldBroadcastNow instead of ShouldBroadcast. Conveyor doesn't need queueing and is much faster this way. If you want, you can still use queues.

Example of usage in a view with authorization at this point:

1<html>
2<head>
3    <title>WS Client</title>
4    @vite(['resources/css/app.css', 'resources/js/app.js'])
5</head>
6<body>
7
8<textarea id="msg"></textarea>
9<button id="btn-base">Base</button>
10<button id="btn-broadcast">Broadcast</button>
11<ul id="output"></ul>
12
13<script type="text/javascript">
14    // page elements
15    const msg = document.getElementById('msg')
16    const btnBase = document.getElementById('btn-base')
17    const btnBroadcast = document.getElementById('btn-broadcast')
18    const output = document.getElementById('output')
19
20    const connect = (token) => {
21        let conveyor = new window.Conveyor({
22            protocol: '{{ $protocol }}',
23            uri: '{{ $uri }}',
24            port: {{ $wsPort }},
25            channel: '{{ $channel }}',
26            query: '?token=' + token,
27            onMessage: (e) => output.innerHTML = e,
28            onReady: () => {
29                btnBase.addEventListener('click', () => conveyor.send(msg.value))
30                btnBroadcast.addEventListener('click', () => conveyor.send(msg.value, 'broadcast-action'))
31            },
32        });
33    };
34
35    const  getAuth = (callback) => {
36        fetch('/broadcasting/auth?channel_name={{ $channel }}', {
37            headers: {
38                'Accept': 'application/json',
39            },
40        })
41            .then(response => response.json())
42            .then(data => callback(data.auth))
43            .catch(error => console.error(error));
44    }
45
46    // for authorization:
47    document.addEventListener("DOMContentLoaded", () => getAuth(connect));
48    // for simple public connection:
49    // document.addEventListener("DOMContentLoaded", () => connect(''));
50</script>
51</body>
52</html>

Then, add the route for this view at your routes/web.php file:

1use Illuminate\Support\Facades\Route;
2use Illuminate\Support\Facades\Auth;
3
4Route::get('/ws-client', function () {
5    Auth::loginUsingId(1); // here we authorize for the sake of the example.
6
7    return view('ws-client', [
8        'protocol' => config('broadcasting.connections.conveyor.protocol'),
9        'uri' => config('broadcasting.connections.conveyor.host'),
10        'wsPort' => config('broadcasting.connections.conveyor.port'),
11        'channel' => 'private-my-channel',
12    ]);
13});

Extra: Simple Conveyor Server for this example

You can use this simple server to test your broadcasting (and in production...):

1<?php
2// file: server.php
3
4include __DIR__ . '/vendor/autoload.php';
5
6use Conveyor\ConveyorServer;
7use Conveyor\Events\MessageReceivedEvent;
8use Conveyor\Events\PreServerStartEvent;
9
10(new ConveyorServer())
11    // if you want to see messages in the console 
12    ->eventListeners([
13        Conveyor\Constants::EVENT_MESSAGE_RECEIVED => function (MessageReceivedEvent $event) {
14            var_dump($event->data);
15        },
16    ])
17    ->port(8181)
18    ->start();

Remember to install conveyor with composer require kanata-php/conveyor and run the server with php server.php.

Previous
Conveyor Server Events