kanata-php / conveyor-laravel-broadcaster
Conveyor Laravel Broadcaster
Requires
- firebase/php-jwt: ^6.4
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.41
- phpro/grumphp: *
- phpstan/phpstan: ^1.10
- squizlabs/php_codesniffer: ^3.7
README
This is a Laravel Integration for Socket Conveyor. It allows you to use the Conveyor WebSocket server as a broadcasting driver for Laravel. This package needs Jacked Server.
This package is an alternative for those who want to use Conveyor as a broadcasting driver. For that, you need to install Jacked Server or check there how to run your WebSocket server with Conveyor
Installation
Start by installing Jacked Server.
Step 1: Install the package via composer:
composer require kanata-php/conveyor-laravel-broadcaster
Step 2: Publish the configuration:
php artisan vendor:publish --provider="Kanata\LaravelBroadcaster\ConveyorServiceProvider"
Step 3: Add Service Provider to the config/app.php
file:
<?php return [ // ... 'providers' => [ // ... Kanata\LaravelBroadcaster\ConveyorServiceProvider::class, ], // ... ];
Step 4: If on Laravel 11, enable Laravel broadcasting:
php artisan install:broadcasting
Step 5: Add the following to your config/broadcasting.php
file:
<?php return [ // ... 'conveyor' => [ 'driver' => 'conveyor', ], ];
Step 6: Protect your channel with a "channel route" (a specific laravel detail). You do this by adding the following to your routes/channels.php
:
use App\Models\User; use Illuminate\Support\Facades\Broadcast; Broadcast::channel('actions-channel', function (User $user) { return true; // we are authorizing any user here - update according to your needs! });
Step 7: This package require an user to authenticate with. To quickly create a user, you can use tinker for that:
php artisan tinker
Within tinker, you can create a user:
App\Models\User::factory()->create(['email' => 'user@jacked-server.com', 'password' => Hash::make('password')]);
Step 8: Specify the configurations for the WebSocket server in the .env
file:
Important: SQLite won't work well due to its lock mechanism and how concurrency happens with this service. It is recommended to use MySQL, Postgres, or a more robust database.
# ... BROADCAST_CONNECTION=conveyor # ... # MySQL of Postgres are better alternatives that SQLite CONVEYOR_DATABASE=pgsql JACKED_SERVER_WEBSOCKET_ENABLED=true # ...
At this point you can broadcast from your Laravel instance to the Conveyor WebSocket server. To understand how to broadcast with Laravel, visit Broadcasting.
Step 9: Install the Conveyor JS Client:
npm 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:
import Conveyor from "socket-conveyor-client"; window.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:
<?php namespace App\Events; use Illuminate\Broadcasting\InteractsWithBroadcasting; use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow; class TestEvent implements ShouldBroadcastNow { use InteractsWithBroadcasting; public function __construct( public string $message, public string $channel, ) { $this->broadcastVia('conveyor'); } public function broadcastOn(): array { return [ new PrivateChannel($this->channel), ]; } }event(new App\Events\TestEvent( message: 'my message', channel: 'my-channel'));
Important: notice that we are using
ShouldBroadcastNow
instead ofShouldBroadcast
. 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:
<html> <head> <title>WS Client</title> @vite(['resources/css/app.css', 'resources/js/app.js']) </head> <body> <textarea id="msg"></textarea> <button id="btn-base">Base</button> <button id="btn-broadcast">Broadcast</button> <ul id="output"></ul> <script type="text/javascript"> // page elements const msg = document.getElementById('msg') const btnBase = document.getElementById('btn-base') const btnBroadcast = document.getElementById('btn-broadcast') const output = document.getElementById('output') const connect = (token) => { let conveyor = new window.Conveyor({ protocol: '{{ $protocol }}', uri: '{{ $uri }}', port: {{ $wsPort }}, channel: '{{ $channel }}', query: '?token=' + token, onMessage: (e) => output.innerHTML = e, onReady: () => { btnBase.addEventListener('click', () => conveyor.send(msg.value)) btnBroadcast.addEventListener('click', () => conveyor.send(msg.value, 'broadcast-action')) }, }); }; const getAuth = (callback) => { fetch('/broadcasting/auth?channel_name={{ $channel }}', { headers: { 'Accept': 'application/json', }, }) .then(response => response.json()) .then(data => callback(data.auth)) .catch(error => console.error(error)); } document.addEventListener("DOMContentLoaded", () => getAuth(connect)); </script> </body> </html>
Then, add the route for this view at your routes/web.php
file:
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Auth; Route::get('/ws-client', function () { Auth::loginUsingId(1); // here we authorize for the sake of the example. $protocol = config('jacked-server.ssl-enabled') ? 'wss' : 'ws'; $port = config('jacked-server.ssl-enabled') ? config('jacked-server.ssl-port') : config('jacked-server.port'); return view('ws-client', [ 'protocol' => $protocol, 'uri' => '127.0.0.1', 'wsPort' => $port, 'channel' => 'private-my-channel', ]); });