🌟

Laravel-echo-serverで遊ぶ over Apache

に公開

Laravel-echo-serverとは

  • Nodejs with socket.ioで作られたLaravel用 WebScoketサーバー
  • Laravel-echoとセットで利用する
  • 半リアルタイム通信Laravel+Livewireとは違いリアルタイム通信

但し

How does that work?
The client will try to establish a WebSocket connection if possible, and will fall back on HTTP long polling if not.

前提

https対応

1. オレオレ証明書の作成

command
mkdir /etc/httpd/conf.d/ssl \
&& cd /etc/httpd/conf.d/ssl \
&& echo 'subjectAltName = DNS:localhost, IP:127.0.0.1' > SAN.txt \
&& openssl genrsa -out server.key 2048 \
&& openssl req -new -key server.key -out server.csr -subj "/C=JP/ST=Saitama/O=lfz/CN=localhost" \
&& openssl x509 -req -in server.csr -days 3650 -sha256 -extfile SAN.txt -signkey server.key -out server.crt

2. apacheの設定

command
[root@0117bc9732cb conf.d]# dnf install mod_ssl
/etc/httpd/conf.d/ssl.conf
SSLCertificateFile /etc/httpd/conf.d/ssl/server.crt
SSLCertificateKeyFile /etc/httpd/conf.d/ssl/server.key
/etc/httpd/conf.d/laravel.conf
<VirtualHost *:80>
    DocumentRoot /var/www/lfz-app/public
    ServerName localhost
    RewriteEngine on
    DirectoryIndex index.html index.php
    <Directory "/var/www/lfz-app">
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>
<VirtualHost *:443>
    DocumentRoot /var/www/lfz-app/public
    ServerName localhost
    DirectoryIndex index.html index.php
    RewriteEngine on
    RewriteCond %{REQUEST_URI}  ^/socket.io            [NC]
    RewriteCond %{QUERY_STRING} transport=websocket    [NC]
    #RewriteCond %{QUERY_STRING} ^((?!X-Atmosphere-Transport=websocket).)*$ [NC]
    RewriteRule /(.*)           ws://127.0.0.1:6001/$1 [P,L]

    ProxyPass        /socket.io http://127.0.0.1:6001/socket.io
    ProxyPassReverse /socket.io http://127.0.0.1:6001/socket.io

    SSLEngine on
    SSLProtocol all -SSLv2 -SSLv3
    SSLCertificateFile /etc/httpd/conf.d/ssl/server.crt
    SSLCertificateKeyFile /etc/httpd/conf.d/ssl/server.key
    <Directory "/var/www/lfz-app">
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

3. apache再起動

command
[root@0117bc9732cb lfz-app]# systemctl restart httpd

Laravel-echo-serverの準備

1. laravel-echo-serverのインストール

command
[root@0117bc9732cb lfz-app]# cd /var/www/lfz-app/
[root@0117bc9732cb lfz-app]# npm install -g laravel-echo-server

2. 設定ファイルの作成

command
[root@3fade56e48d9 lfz-app]# laravel-echo-server init
? Do you want to run this server in development mode? Yes
? Which port would you like to serve from? 6001
? Which database would you like to use to store presence channel members? redis
? Enter the host of your Laravel authentication server. https://localhost
? Will you be serving on http or https? http
? Do you want to generate a client ID/Key for HTTP API? No
? Do you want to setup cross domain access to the API? No
? What do you want this config to be saved as? laravel-echo-server.json
Configuration file saved. Run laravel-echo-server start to run server.

Laravel echoの準備

1. クライアント用ライブラリインストール

command
[root@0117bc9732cb lfz-app]# npm install --save-dev socket.io-client@2 laravel-echo

参考にするのは
https://laravel.com/docs/8.x/broadcasting
ではなく
https://readouble.com/laravel/7.x/ja/broadcasting.html

2. .envの修正

  • .envの修正
.env
APP_NAME=lfz
BROADCAST_DRIVER=redis
CACHE_DRIVER=redis
SESSION_DRIVER=redis

3. configの修正

config/app.php
174         // App\Providers\BroadcastServiceProvider::class,
↓コメントアウト解除
174         App\Providers\BroadcastServiceProvider::class,

4. envの反映(キャッシュしてない場合は不要)

command
[root@3fade56e48d9 lfz-app]# php artisan cache:clear
Application cache cleared!
[root@3fade56e48d9 lfz-app]# php artisan config:cache
Configuration cache cleared!
Configuration cached successfully!

5. クライアント用javascriptの作成

resources/js/bootstrap.js
import Echo from 'laravel-echo';

// window.Pusher = require('pusher-js');

window.io = require('socket.io-client');
window.Echo = new Echo({
    broadcaster: 'socket.io',
    host: 'https://localhost:8883',
    forceTLS: true
});
window.Echo.channel('lfz_database_public-echo-channel')
    .listen('RealtimeEcho', (e) => {
    console.log(e);
});

6. assetsコンパイル

[root@3fade56e48d9 lfz-app]# npm run dev

7. blade修正

resources/views/welcome.blade.php
<!--追加-->
        <meta name="csrf-token" content="{{ csrf_token() }}">
        <script src="{{ mix('js/app.js') }}"></script>

ブロードキャストする為のイベント作成

1. イベント作成

command
[root@3fade56e48d9 /]# cd /var/www/lfz-app/
[root@3fade56e48d9 lfz-app]# php artisan make:event RealtimeEcho
Event created successfully.
app/Events/RealtimeEcho.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;
use Illuminate\Support\Facades\Redis;

class RealtimeEcho implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(){
        //
    }

    public function broadcastOn(){
        return new Channel('public-echo-channel');
    }

    public function broadcastWith(){
        return ['count' => Redis::get('count')
                ,'static' => 'STATIC STRING'
        ];
    }
}

2. イベントを叩きつける為のURL用意

routes/web.php
use Illuminate\Support\Facades\Redis;
Route::get('/realtimeecho', function(){
    (function($count){
            echo $count;
        is_null($count) ? Redis::set('count', 0) : Redis::set('count', $count+1);
    })(Redis::get('count'));
    broadcast(new \App\Events\RealtimeEcho);
});

laravel-echo-serverの稼働

command
[root@3fade56e48d9 lfz-app]# cd /var/www/lfz-app/
[root@3fade56e48d9 lfz-app]# laravel-echo-server start

L A R A V E L  E C H O  S E R V E R

version 1.6.2

 Starting server in DEV mode...

  Running at localhost on port 6001
  Channels are ready.
  Listening for http events...
  Listening for redis events...

Server ready!

動作チェック

1. Socket通信している画面を開く

2. イベントを叩きつける

https://localhost:8883/realtimeechoを開いてF5連打

log
{count: "3", static: "STATIC STRING", socket: null} app.js:1957 
{count: "4", static: "STATIC STRING", socket: null} app.js:1957 
{count: "5", static: "STATIC STRING", socket: null} app.js:1957 
{count: "6", static: "STATIC STRING", socket: null} app.js:1957 

という感じのログが出ればOK

これで定番のリアルタイムチャットとかを作れます

脚注
  1. 本記事の環境はdockerコンテナを利用している為ポートフォワードしています ↩︎

  2. dockerコンテナだから ↩︎

Discussion