Skip to content
Laravel broadcaster for Mercure
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
src 🎉 Initial commit Apr 2, 2019
tests 🎨 Fix code style May 19, 2019
.editorconfig
.gitattributes 🎉 Initial commit Apr 2, 2019
.gitignore
.travis.yml Add integration test Apr 8, 2019
CHANGELOG.md
CONTRIBUTING.md 🎉 Initial commit Apr 2, 2019
LICENSE.md
README.md 📝 Improve readme May 19, 2019
composer.json
phpunit.xml.dist 🎉 Initial commit Apr 2, 2019

README.md

Laravel Mercure Broadcaster

Latest Version on Packagist Build Status Total Downloads

Laravel broadcaster for Mercure for doing Server Sent Events in a breeze.

Installation

Make sure you have installed Mercure and have it running. Check their docs how to do it. (It's pretty easy)

Configure laravel to use the mercure broadcaster by editing config/broadcasting.php for example:

<?php

return [

    'default' => env('BROADCAST_DRIVER', 'mercure'),

    'connections' => [

        // ...

        'mercure' => [
            'driver' => 'mercure',
            'url' => env('MERCURE_URL', 'http://localhost:3000/hub'),
            'secret' => env('MERCURE_SECRET', 'aVerySecretKey'),
        ],

    ],

];

Usage

Add an event which implements ShouldBroadcast interface like in https://laravel.com/docs/master/broadcasting#defining-broadcast-events

<?php

namespace App\Events;

use Duijker\LaravelMercureBroadcaster\Broadcasting\Channel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

class NewsItemCreated implements ShouldBroadcast
{
    /**
     * @var NewsItem
     */
    public $newsItem;

    public function __construct(NewsItem $newsItem)
    {
        $this->newsItem = $newsItem;
    }

    public function broadcastOn()
    {
        return new Channel('http://example/news-items');
    }
}

In your frontend do something like:

var es = new EventSource('http://localhost:3000/hub?topic=' + encodeURIComponent('http://example/news-items'));
es.addEventListener('message', (messageEvent) => {
    var eventData = JSON.parse(messageEvent.data);
    console.log(eventData);
});

Private channels go a bit differently then with broadcasting through sockets. Private channels are baked in Mercure and are secured with a jwt token.

First create a http middleware so we can generate the mercure authentication cookie with the token. Don't forget to add the middleware to your route!

Example:

<?php 

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Cookie;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Signer\Hmac\Sha256;

class MercureBroadcasterAuthorizationCookie
{
    public function handle(Request $request, Closure $next)
    {
        /** @var Response $response */
        $response = $next($request);

        if (!method_exists($response, 'withCookie')) {
            return $response;
        }

        return $response->withCookie($this->createCookie($request->user(), $request->secure()));
    }

    private function createCookie($user, bool $secure)
    {
        // Add audience(s) this user has access to
        $subscriptions = [
            "http://example/user/{$user->id}"
        ];

        $token = (new Builder())
            ->setExpiration(time() + (60 * 15))
            ->set('mercure', ['subscribe' => $subscriptions])
            ->sign(new Sha256(), config('broadcasting.connections.mercure.secret'))
            ->getToken();

        return Cookie::make(
            'mercureAuthorization',
            (string) $token,
            15,
            '/hub', // or which path you have mercure running
            parse_url(config('app.url'), PHP_URL_HOST),
            $secure,
            true
        );
    }
}

Example event:

<?php

namespace App\Events;

use Duijker\LaravelMercureBroadcaster\Broadcasting\Channel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

class DirectMessageCreated implements ShouldBroadcast
{
    /**
     * @var DirectMessage
     */
    public $directMessage;

    public function __construct(DirectMessage $directMessage)
    {
        $this->directMessage = $directMessage;
    }

    public function broadcastOn()
    {
        return new Channel(
            "http://example/user/{$this->directMessage->user_id}/direct-messages", 
            ["http://example/user/{$this->directMessage->user_id}"]
        );
    }
}

Example Frontend:

var es = new EventSource('http://localhost:3000/hub?topic=' + encodeURIComponent('http://example/user/1/direct-messages'), { withCredentials: true });
es.addEventListener('message', (messageEvent) => {
    var eventData = JSON.parse(messageEvent.data);
    console.log(eventData);
});

Further reading

Make sure you read the documentation of Mercure and how to run it securely (behind https).

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Credits

License

The MIT License (MIT). Please see License File for more information.

You can’t perform that action at this time.