人狼GM支援ツールを作る（Laravel Echo編）

# はじめに

前回から間隔が空いてしまいましたが、この記事は[人狼GM支援ツールを作る（ Vue.js編）](https://qiita.com/3894eye/items/8589a03b5e9d904724a3)の続きとなります。

前回はVue.jsを使ってフロント側を作っていきました。
今回は、この「人狼GM支援ツール」の目玉であるチャット機能を実装します。

さて、今回のチャット機能は`Laravel Echo`というLaravelのプラグインを利用していきます。
この`Laravel Echo`がどういったものか、どう使うのかについて説明したいと思います。

# Laravel Echoの使い方と設定

## Laravel Echoとは

Laravel Echoとは……

> Laravel EchoはJavaScriptライブラリで、チャンネルの購読とLaravelによるイベントブロードキャストのリッスンを苦労なしに実現してくれます。

だそうです。（[日本語ドキュメント](https://readouble.com/laravel/5.6/ja/broadcasting.html)より抜粋）
一言で言えば、**クライアント側での接続を助けてくれるやつ**ってイメージですね。

npmで管理されているので、導入は以下のコマンドを叩くだけです。

```bash
npm install --save laravel-echo
```

websocketのブロードキャストには[pusher](https://pusher.com/)またはredisが利用できます。
私はredisを利用したので、composerからPredisというライブラリをインストールした上で.envにredisを使うよう設定を追記しました。

## websocketサーバの準備

redisを利用する場合には、socket.ioの実装が必要になります。
しかし、頑張って自力で実装する必要はありません。
なぜなら、`laravel-echo-server`というLaravel用のsocket.io実装が用意されているからです。
こちらもnpmで管理されているので、以下のコマンドでインストールします。

```bash
npm install -g laravel-echo-server
```

その後、

```bash
laravel-echo-server init
```

で設定ファイルを作成し、

```bash
laravel-echo-server start
```

で起動します。

コンソール上にecho-serverが起動した旨の表示が出れば設定完了です。

以上、Laravelでwebsocketを利用するために必要なモジュールの紹介でした。
細かい設定などは省略しているので、自分で試す際はLaravelの日本語ドキュメントを参考にして進めるとよいでしょう。

# redisとチャット機能の仕組み
## redisとは

ところで、前の項目で

> websocketのブロードキャストには[pusher](https://pusher.com/)またはredisが利用できます。
>
> 私はredisを利用したので、composerからPredisというライブラリをインストールした上で.envにredisを使うよう設定を追記しました。

と書きました。
突然出てきた`redis`とはなにか、コイツを使うと何が嬉しいのか、という部分から解説していきます。

redisとは、いわゆるNoSQLデータベース（RDBMSでないデータベース）です。
key = value の形のデータをメモリ上に持ち、セッションストアやキャッシュストアなどに使われることが多いです。

今回の用途では、redisのDBとしての機能ではなく、`publish/subscribe`の機能を使います。
これは、「別クライアントから送信されたメッセージを受け取る」機能です。

redisに対して、

`SUBSCRIBE <チャンネル名>`

のコマンドを送ると、redisは受信待ちの状態になります。
この状態で、別のクライアントから

`PUBLISH <チャンネル名> <内容>`

のコマンドを送ると、SUBSCRIBEしているクライアントにメッセージが届きます。
この機能が、チャット機能のいわば橋渡しのような役割を担います。

## Laravelからredisへ

次は、ブラウザ（javascript）から送信した文字がredisに送られるまでの流れを見ていきます。
javascript → Laravelは、Laravelで用意したチャットAPIにajaxで送りました。
送信した文字を受け取ったLaravel側では、`「イベントブロードキャスト」`という機能を使います。
簡単に言えば**外部連携機能**といったところでしょうか。
使い方は単純で、「redisに対してPUBLISHする」というイベントを用意しておくと、発火されたタイミングでredisにPUBLISHを送ります。
これでredisにユーザがブラウザ上で入力したチャット内容が到達しました！

## redisからjavascriptへ

redisにPUBLISHしても、肝心のredisがSUBSCRIBEで受信待ちしていなければ意味がありませんね。
そこで、redisの状態からwebsocket接続までをよしなに管理してくれるスゴいヤツ、`laravel-echo-server`の出番です。
本来なら自分でNode.jsを書く必要がある、redisの受信待ちや受け取ったメッセージをクライアントまで届けるといった部分を、
一手に担ってくれる優れものです。
laravel-echo-serverは以下のような役割を持ちます

- laravel-echo-serverがredisを受信待ちにして、メッセージを待ち構える。
- 同時に、クライアントとwebsocketの接続を行って、redisがメッセージをSUBSCRIBEしたらその内容をクライアントに流す。

つまり、redisからjavascriptまでの流れを全て担ってくれているわけですね。

これで、あるユーザが入力したチャット内容がLaravelとredis、laravel-echo-serverを介して別のユーザにリアルタイムで伝達されました。

##いったん整理

ここまでの通信の流れを整理してみましょう。

クライアント
↓　HTTP
Webサーバ(Laravel)
↓　PUBLISH
redis
↓　SUBSCRIBE
laravel-echo-server
↓　websocket
クライアント

以上の流れで、私が実装したチャット機能は動いています。

# 実装とLaravel Mix
## Laravel Mix

今まであまりLaravel Echoについて触れてこなかったわけですが、Laravel Echoとは`JavaScriptライブラリ`なんですね。
つまり、フロント側に何かしらの手段で読み込ませる必要があるということになります。
ここで、LaravelとJavaScriptの橋渡しとなる最強ライブラリ、`Laravel Mix`の出番です。
これはwebpackのラッパーで、煩雑になりがちなビルドやバンドルの設定を少しのJavaScriptとPHPだけで記述できるというものです。
Laravel Echoを使いたい場合、Laravel MixならエントリポイントとなるJavaScriptに以下を記述するだけです。

```js
import Echo from 'laravel-echo';

window.Echo = new Echo({
   broadcaster: "socket.io",
   host: window.location.hostname + ':6001'
});
```

laravel-echo-serverを使うために`broadcaster: "socket.io"`を指定し、
あとはlaravel-echo-serverのドメインを指定するだけで設定完了です。
`Echo`というプロパティを`window`に生やしているので、どこからでもLaravel Echoを呼び出せるようになりました。

## Laravel Echoの使い方

前回まで、フロントからサーバ、redis、そしてlaravel-echo-serverへデータが流れるフローを解説しました。
残るはLaravel Echoを使ってlaravel-echo-serverからpushされるデータを受け取るだけです。
早速ですが、実装を見てみましょう。

```js
Echo.channel('werewolves.' + roomId)
    .listen('WerewolvesReceived', e => {
        store.pushMessageList(e.message)
    });
```

これは実際にフロントで書いたコードの一部となります（「人狼GM支援ツール」の一部なので、人狼だけが見れるチャットの部分ですね）
ブロードキャストするイベント内で`どのチャンネルに飛ばすか`を指定しているので、受け取る側では`指定したチャンネルからどのイベントをリッスンするか`を指定します。

laravel-echo-serverとブラウザはwebsocketで接続しているので、あとは受け取ったメッセージを画面に表示させるだけです。
駆け足気味な説明でしたが、ついにチャット機能が完成しました！

# まとめ

今回はLaravel Echoでチャット機能を作ったお話でした。
「人狼GM支援ツールを作る」はこれで終わりとする予定ですが、また何かネタを思い出したら書くかもしれません。

ここまで読んでいただきまして、ありがとうございました。