Xây dựng ứng dụng chat bằng PHP WebSocket với Laravel P2

Mở đầu

Ở bài trước mình đã có một demo nho nhỏ về web socket sử dụng thư viện Ratchet, và ở phần tiếp theo này mình xin giới thiệu với các bạn cách đưa thư viện này vào 1 project Laravel và cách implement nó để tạo ứng dụng chat room.

Bắt đầu luôn thôi nào...

Cài đặt Ratchet với Laravel

Đầu tiên ta tạo 1 project Laravel rỗng (phiên bản nào cũng được, ở đây mình để tự động nó sẽ kéo bản mới nhất).

composer create-project --prefer-dist laravel/laravel chat-app

Sau đấy ta tiếp tục thêm Ratchet vào project

composer require cboden/ratchet

Để xây dựng ứng dụng chat 1vs1 và 1vsN ở đây mình sẽ sử dụng component WampServer của Ratchet. WAMP là viết tắt của WebSocket Application Messaging Protocol, WAMP mang đến cho các developer một cách tương tác có tổ chức và dễ dàng hơn giữa client (Javascript) và server (Ratchet-PHP). WAMP cung cấp các RPC (Remote Procedure Call) và PubSub (Publish and Subscribe) patterns. Để xây dựng ứng dụng trên WampServer ta cần 1 thư viện Javascript để thực hiện phía client đó là AutobahnJS. Mình sẽ hướng dẫn thêm và sử dụng thư viện này ở phần dưới. Còn bây giờ ta sẽ triển khai cài đặt Wamp trên server trước.

Bây giờ chúng ta sẽ tạo 1 class tên là Pusher implements WampServerInterface. Nội dung như sau:

namespace App\Services;

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

class Pusher 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;
    }
    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) {
        $topic->broadcat($event);
    }
    public function onError(ConnectionInterface $conn, \Exception $e) {
    }

}

Ta tạo một command để xử lý logic phần gửi và nhận message. Chúng ta sẽ xây dựng ứng dụng Ratchet với I/O, WebSocket, Wamp và ZeroMQ và chạy vòng lặp sự kiện. php artisan make:command PushServer với nội dung:

namespace App\Console\Commands;

use App\Services\Pusher;
use Illuminate\Console\Command;
use Ratchet\Http\HttpServer;
use Ratchet\Server\IoServer;
use Ratchet\Wamp\WampServer;
use Ratchet\WebSocket\WsServer;
use React\EventLoop\Factory;
use React\Socket\Server;
use React\ZMQ\Context;

class PushServer extends Command
{
    protected $signature = 'push_server:run';

    protected $description = 'We\'re going to build our Ratchet application with I/O, WebSockets, Wamp, and ZeroMQ components and run the event loop.';

    public function __construct()
    {
        parent::__construct();
    }

    public function handle()
    {
        $loop   = Factory::create();
        $pusher = new Pusher;

        // Set up our WebSocket server for clients wanting real-time updates
        $webSock = new Server($loop);
        $webSock->listen(8080, '0.0.0.0'); // Binding to 0.0.0.0 means remotes can connect
        $webServer = new IoServer(
            new HttpServer(
                new WsServer(
                    new WampServer(
                        $pusher
                    )
                )
            ),
            $webSock
        );

        $loop->run();
    }
}

Ta có thể giải thích về 2 class trên như sau. Class Pusher implement lại các event của WampServerInterface trong đó onSubscribe là lúc ta đăng kí kết nối với 1 chat room nào đó, tương tự onUnsubcribe là thoát khỏi chatroom, onPublish là push data vào 1 topic nào đó (ở đây là gửi message vào 1 chatroom). $topic->broadcat($event) để gửi data đến toàn bộ client đã subcribe topic đó (tức là gửi message đến toàn bộ member có trong chat room). Còn command PushServer chỉ đơn giản là mở 1 cổng WebSocket 8080 và lắng nghe từ cổng đó. Và ta nhớ chạy command này nhé php artisan push_server:run

Sau đây ta sẽ thêm phần xử lý cho client bằng thư viện AutobahnJs đã nói ở trên. Ta cài đặt AutobahnJs vào project bằng dòng lệnh

npm install autobahn

Ta thêm phần xử lý cho client như sau:

var autobahn = require('autobahn');

var connection = new autobahn.Connection({url: 'ws://127.0.0.1:8080/', realm: 'realm1'});

connection.onopen = function (session) {

   // 1) subscribe to a topic
   function onevent(args) {
      console.log("Event:", args[0]);
   }
   session.subscribe('chat_room_001', onevent);

   // 2) publish an event
   session.publish('chat_room_001', ['Hello, world!']);
};

connection.open();

Nhìn vào đoạn code trên ta có thể hiểu khi tạo một chat room thì ta sẽ subscribe vào chat room đó để nhận message từ các client khác cùng subscribe room đó, khi gửi message ta dùng publish. Cơ bản thư viện này khá dễ dùng và implement đầy đủ các event trên WampServer. Với document rõ ràng và dễ hiểu thì ta dễ dàng để sử dụng chúng trong project của mình.

Kết luận

Như vậy mình đã giới thiệu xong cách implement Ratchet vào project Laravel. Ngoài ra các bạn hoàn toàn có thể mở rộng thêm: push thông báo đến client khi có 1 sự kiện nào đó (giống như facebook gửi notifi khi có người like comment bài viết)... Cảm ơn các bạn đã theo dõi.


All Rights Reserved