Help us understand the problem. What is going on with this article?

laravel4 websocket push

More than 5 years have passed since last update.

二回目の微妙な登場でございます。

websocket push!

websocketの代表と言えばchatでしょうか?
laravel4でのチャット実装のそのまんまなサンプルは
laravel4 cookbook
にありますので、
そちらを参考にしていただければと思います。

laravel4パッケージにしたLatchetもありますが、
ratchetを使います。

今回はlaravel4で実装するwebsocket pushについてです

pushをご存知でない方が一番分かりやすいのは、
iPhoneやandroidでニュースやメッセージを受信したときに通知されるnotificationの
web版だと思ってください。

つまり、アクセスしている人にサーバから送信する事ができます。
node.jsで広告やコンテンツを一斉に配信したり、
ブラウザゲーム系にも活用されている方は多いかもしれません。

Ratchetとzmqを使って実装します。(といってもリファレンス通りですが!)
Ratchet
まずサーバpushを実装するにあたっていくつか必要なものがありますので、
makeします。
(mac環境での構築方法なので他のOSの方はそれ用にあわせてください)

libzmq

libzmq
$ git clone git://github.com/zeromq/libzmq.git
$ cd libzmq/
$ ./autogen.sh
$ ./configure && make
$ make install

*errorが出る場合はmacPortsでlibtool autoconf automakeをinstallしてください。

php-zmq

php-zmq
$ git clone git://github.com/mkoppanen/php-zmq.git
$ cd php-zmq/
$ phpize
$ ./configure && make
$ make install

re2cあたりがエラー出る場合は同様にmacPortsでzmq.soをiniに忘れずに追記してください。
php -mで確認してください!

あとはいつもと同じです

composer.json
    "require": {
        "laravel/framework": "4.0.*",
        "cboden/Ratchet": "0.3.*",
        "react/zmq": "0.2.*"
    }

push実装

Wamp/Pusher.php
namespace Wamp;
use Ratchet\ConnectionInterface;
use Ratchet\Wamp\WampServerInterface;

class Pusher implements WampServerInterface
{   
    protected $subscribedTopics = array();

    public function onSubscribe(ConnectionInterface $conn, $topic)
    {
        if (!array_key_exists($topic->getId(), $this->subscribedTopics))
        {
            $this->subscribedTopics[$topic->getId()] = $topic;
        }
    }

    /**
     * @param string JSON'ified string we'll receive from ZeroMQ
     */
    public function onBlogEntry($entry) {
        $entryData = json_decode($entry, true);

        if (!array_key_exists($entryData['cat'], $this->subscribedTopics)) {
            return;
        }

        $topic = $this->subscribedTopics[$entryData['cat']];
        $topic->broadcast($entryData);
    }

    public function onUnSubscribe(ConnectionInterface $conn, $topic) {
    }

    public function onOpen(ConnectionInterface $conn) {
    }

    public function onClose(ConnectionInterface $conn) {
    }

    public function onCall(ConnectionInterface $conn, $id, $topic, array $params) {
        $conn->callError($id, $topic, 'You are not allowed to make calls')->close();
    }

    public function onPublish(ConnectionInterface $conn, $topic, $event, array $exclude, array $eligible) {
        $conn->close();
    }

    public function onError(ConnectionInterface $conn, \Exception $e) {
    }
}

onBlogEntryが受け、
サーバから接続しているブラウザに送信する様にします。
実際にはDBで配信時間を見ながら自動で送信したりという実装ですが、
書くと長くなるので省きます

コマンド実装

app/commands/WampPushCommand.php
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use React\Socket;

class WampPushCommand extends Command {

    /**
     * @var string
     */
    protected $name = 'wamp:push';

    /**
     * The console command description.
     * @var string
     */
    protected $description = "boot wamp server";

    /**
     * @return void
     */
    public function fire()
    {
        $loop   = React\EventLoop\Factory::create();
        $pusher = new Wamp\Pusher;

        $context = new \React\ZMQ\Context($loop);
        $pull = $context->getSocket(ZMQ::SOCKET_PULL);
        $pull->bind('tcp://127.0.0.1:5555'); 
        $pull->on('message', array($pusher, 'onBlogEntry'));

        $webSock = new \React\Socket\Server($loop);
        $webSock->listen(10000, '0.0.0.0'); 
        $webServer = new Ratchet\Server\IoServer(
            new Ratchet\Http\HttpServer(
                new Ratchet\WebSocket\WsServer(
                    new Ratchet\Wamp\WampServer($pusher
                   )
                )
            ), $webSock);
        $this->info('wamp boot');
        $this->info('Listening on port ' . 10000);
        $loop->run();
    }
}

この例は
port 5555から受け付けて、port 10000にpushを行います。
実際にはコマンドの引数でport指定する様にしましょう。(サンプルなので手抜き)
ここでいうWampとは、The WebSocket Application Messaging Protocolで、
windows環境をさすものではありませんYo

artisanに登録します。

app/start/artisan.php
$artisan->add(new WampPushCommand);

これでwebsocketの準備が整いました。

$ php artisan wamp:push
wamp boot
Listening on port 10000

上記の様に起動します。

次にブラウザです。
折角なのでデフォルトのhello.phpに書いてしまいましょう
リファレンスと同じ様にwhen.js, autobahn.jsにしときます。

hello.phpに書いてみる
<script src="/js/when.js"></script>
<script src="http://autobahn.s3.amazonaws.com/js/autobahn.min.js"></script>
<script src="//code.jquery.com/jquery-1.10.2.min.js"></script>
<script>
    var conn = new ab.Session(
        'ws://127.0.0.1:10000' , function() {
            conn.subscribe('news', function(topic, data) {
                console.log('New article published to category "' + topic + '" : ' + data.title);
                $('.welcome').html(
                    'New article published to category "' + topic
                    + '"<br /> title : ' + data.title
                    + "<br /> article : " + data.article
                );
            });
        }, function() { 
            console.warn('WebSocket connection closed');
        }, {
            'skipSubprotocolCheck': true
        }
    );
</script>

newsカテゴリーを購読して、受信したときにlaravel4ロゴを書き換えます。(わかりやすい!)
リソースでエントリーします

ResourceController
    public function create()
    {
        $entryData = [
            'cat'     => 'news',
            'title'   => 'ニュース!',
            'article' => 'laravel4.1 でましたよ',
            'when'    => time()
        ];
        $context = new ZMQContext();
        $socket = $context->getSocket(ZMQ::SOCKET_PUSH, 'my pusher1');
        $socket->connect("tcp://localhost:5555");
        $socket->send(json_encode($entryData));
    }

先ほどのlaravel4のデフォルトページをそのまま表示させておき、
他のブラウザかタブからリソースを叩いて送ってみましょう。

sample.png

じゃーん

今回はリソース直叩きなので、普通のwebsocketと変わらないじゃん!と言われそうですが、
実際にはこれをサーバのみで実装します。
webでできるなんて、ちょっと気持ち悪いですね!!!
慣れるまでちょっと長い道のりですが、
実装できる様になると色んなものに使えると思います。
laravel4でwebsocketアプリケーションを実装する事で、
ブラウザからごにょごにょしたデータをnode.jsに送って解析して云々などしなくても、
用意されているものでユーザーデータだったり、色んな情報も簡単に実装する事ができます。
Illuminate万歳!

明日はatijust さんです

ytake
著: Laravelリファレンス(インプレス) Laravelエキスパート養成読本(技術評論社) PHPフレームワーク Laravel Webアプリケーション開発 バージョン 5.5 LTS対応(ソシム)
https://blog.ytake.jp.net/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした