Laravel-echo-serverで遊ぶ over Apache

8 min read読了の目安(約8000字

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.

前提

※本記事ではやむを得ない理由[2]によりオレオレ証明書を使いますが、インターネット公開する人はLet's Encryptを使いましょう

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

手元の端末でdockerコンテナを使っている都合上オレオレ証明書を使っていますが、VPSなどグローバルIPが割り当てられている環境ではLet's Encryptの導入にチャレンジしましょう

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

バージョンアップによって削除されてしまった説明やサンプルコードがあるので、利用しているLaravelのバージョンのマニュアルから目的の情報を見つけられない時は古いバージョンのドキュメントも覗きに行ってみましょう

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);
});

lfz_database_public-echo-channelRealtimeEcho固定値文字列は丸写ししましょう

app.jsに処理を書いても良いですが、本記事ではデフォルトでpusher用の処理が掛かれているbootstrap.jsの該当箇所を書き換えています

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コンテナだから ↩︎