mvanduijker/laravel-mercure-broadcaster

3.6.0 2024-03-13 20:10 UTC

This package is auto-updated.

Last update: 2024-09-13 21:14:18 UTC


README

Latest Version on Packagist Build status Total Downloads

Laravel 的 Mercure 广播器,用于轻松实现服务器端事件。

安装

确保您已安装并运行 Mercure。请参阅他们的文档了解如何操作。(很简单)

通过编辑 config/broadcasting.php 配置 Laravel 使用 Mercure 广播器,例如

<?php

return [

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

    'connections' => [

        // ...

        'mercure' => [
            'driver' => 'mercure',
            'url' => env('MERCURE_URL', 'https://:3000/.well-known/mercure'),
            'secret' => env('MERCURE_SECRET', 'aVerySecretKey'),
        ],

    ],

];

用法

添加实现 ShouldBroadcast 接口的事件,例如在 https://laravel.net.cn/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');
    }
}

在前端进行类似操作

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

私有频道与通过套接字进行广播略有不同。私有频道是 Mercure 内置的,并使用 jwt 令牌进行安全保护。

首先创建一个 http 中间件,以便我们可以使用令牌生成 Mercure 认证 cookie。别忘了将中间件添加到路由中!

示例

<?php 

namespace App\Http\Middleware;

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

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 topic(s) this user has access to
        // This can also be URI Templates (to match several topics), or * (to match all topics)
        $subscriptions = [
            "http://example/user/{$user->id}/direct-messages",
        ];

        $jwtConfiguration = Configuration::forSymmetricSigner(
            new Sha256(),
            InMemory::plainText(config('broadcasting.connections.mercure.secret'))
        );

        $token = $jwtConfiguration->builder()
            ->withClaim('mercure', ['subscribe' => $subscriptions])
            ->getToken($jwtConfiguration->signer(), $jwtConfiguration->signingKey())
            ->toString();

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

由于 Laravel 默认对 cookie 进行加密和解密,请务必在 App\Http\Middleware\EncryptCookies 中添加对 mercureAuthorization cookie 的 异常

示例事件

<?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", 
            true
        );
    }
}

示例前端

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

高级用法

如果您想生成自己的 JWT,可以通过覆盖 mvanduijker.mercure_broadcaster.publisher_jwt 服务来实现。如果您想自定义声明、使用其他签名算法等,请执行此操作。它期望返回包含 JWT 的字符串。默认 JWT 的生成示例:https://github.com/mvanduijker/laravel-mercure-broadcaster/blob/master/src/LaravelMercureBroadcasterServiceProvider.php#L32

请确保您还在 cookie 中间件中进行了更改。

进一步阅读

请确保您阅读了 Mercure 的文档以及如何安全地运行它(在 https 后面)。

测试

composer test

变更日志

请参阅 CHANGELOG 了解最近更改的详细信息。

贡献

请参阅 CONTRIBUTING 了解详细信息。

鸣谢

许可

MIT 许可证(MIT)。请参阅 许可文件 了解更多信息。