menu

Engine - Push websocket from API Laravel with Ratchet Part-1


Pada tutorial sebelumnya kita sudah membuat sebuah engine push notifikasi dan chat menggunakan Ratchet Laravel yang hanya terjadi antara client, lantas bagaimana jika kita ingin mengirimkan pusher tersebut melalui API pada framework Laravel? tentu akan ada beberapa tambahan setup untuk itu.

Baiklah, dari case yang ada diatas pada tutorial kali ini kita akan membuat sebuah engine untuk mengirimkan notifikasi atau chat dari sebuah API menggunakan Ratchet Laravel.

Requirements yang codedoct gunakan adalah,
  1. Laravel versi 5.4
  2. PHP versi 5.6
  3. Ratchet cboden versi 0.4
  4. ZMQ versi 0.3
Sebelum memulai, pastikan ZeroMQ sudah terinstall pada PHP dan web server, jika belum klik disini(MAC OS) atau disini(Ubuntu OS).

Oke langsung saja kita mulai eksperimennya.
Pertama, install dulu requirement yang kita butuhkan, edit file composer.json dengan menambahkan code berikut,
"require": {
 "cboden/ratchet": "0.4.*",
 "react/zmq": "0.3.*"
}
dan update file composer,
$ composer update

Selanjutnya, buat file command laravel untuk dijalankan di server dengan cara,
$ php artisan make:command WebSocketServer --command=websocket:init

Syntax di atas akan secara otomatis membuat file baru dengan nama WebSocketServer.php pada path app/Console/Commands/ edit file tersebut sehingga akan tampak seperti ini,
<?php

namespace App\Console\Commands;

use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use Ratchet\Wamp\WampServer;

use React\EventLoop\Factory;
use React\ZMQ\Context;
use React\Socket\Server;

use Illuminate\Console\Command;
use App\Http\Controllers\Thirdparty\WebSocketPusherController;

class WebSocketServer extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'websocket:init';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $this->info("start server");
        $loop   = Factory::create();
        $pusher = new WebSocketPusherController;

        // Listen for the web server to make a ZeroMQ push after an ajax request
        $context = new Context($loop);
        $pull    = $context->getSocket(\ZMQ::SOCKET_PULL);

        // Binding to 127.0.0.1 means the only client that can connect is itself
        $pull->bind('tcp://127.0.0.1:5555');
        $pull->on('message', array($pusher, 'onBlogEntry'));

        // Binding to 0.0.0.0 means remotes can connect
        $webSock = new Server('0.0.0.0:8080',$loop);
        $webServer = new IoServer(
            new HttpServer(
                new WsServer(
                    new WampServer(
                        $pusher
                    )
                )
            ),
            $webSock
        );

        $loop->run();
    }
}

Pada code diatas kita membuat sebuah depedency dengan sebuah file WebSocketPusherController, buat file baru dengan nama WebSocketPusherController.php pada path app/Http/Controllers/Thirdparty/ dan isi dengan code berikut,
<?php

namespace App\Http\Controllers\Thirdparty;

use Ratchet\ConnectionInterface;
use Ratchet\Wamp\WampServerInterface;

class WebSocketPusherController implements WampServerInterface {
     /**
     * A lookup of all the topics clients have subscribed to
     */
    protected $subscribedTopics = array();

    public function onSubscribe(ConnectionInterface $conn, $topic) {
        $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 the lookup topic object isn't set there is no one to publish to
        if (!array_key_exists($entryData['type'], $this->subscribedTopics)) {
            return;
        }
        $topic = $this->subscribedTopics[$entryData['type']];

        // re-send the data to all the clients subscribed to that category
        $topic->broadcast($entryData);
    }

    /* The rest of our methods were as they were, omitted from docs to save space */
    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) {
        // In this application if clients send data it's because the user hacked around in console
        $conn->callError($id, $topic, 'You are not allowed to make calls')->close();
    }
    public function onPublish(ConnectionInterface $conn, $topic, $event, array $exclude, array $eligible) {
        // In this application if clients send data it's because the user hacked around in console
        $conn->close();
    }
    public function onError(ConnectionInterface $conn, \Exception $e) {
    }
}

Code websocket server diatas akan kita panggil melalui command php artisan untuk itu kita harus menambahkannya pada kernel laravel, yang terletak pada path app/Console/ dengan nama file Kernel.php edit bagian command menjadi seperti ini,
/**
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        Commands\WebSocketServer::class,
    ];

Oke jika semua sudah selesai saatnya kita coba run WebSocketServer nya dengan cara,
$ php artisan websocket:init

Sehingga akan tampak seperti ini tampilannya,


===DONE!===