Building a Live Online Chat Room Based on Laravel + Swoole + Vue (P12)

Building a Live Online Chat Room Based on Laravel + Swoole + Vue (P12): Join and Exit Chat Room Function Implementation

Today, we continue the previous tutorial, and continue to introduce the Websocket server implementation that triggers the room entry event after the user enters the chat room, and the room exit event that is triggered when the room is exited.

Enter the room

We look into the realization of the room, in routes/websocket.php the new code as follows:

WebsocketProxy::on('room', function (WebSocket $websocket, $data) {
    if (!empty($data['api_token']) && ($user = User::where('api_token', $data['api_token'])->first())) {
        // Get room ID from request data
        if (empty($data['roomid'])) {
            return;
        }
        $roomId = $data['roomid'];
        // Reset user association with fd
        Redis::command('hset', ['socket_id', $user->id, $websocket->getSender()]);
        // Clear user unread messages in the room
        $count = Count::where('user_id', $user->id)->where('room_id', $roomId)->first();
        $count->count = 0;
        $count->save();
        // Add users to the specified room
        $room = Count::$ROOMLIST[$roomId];
        $websocket->join($room);
        // Print log
        Log::info($user->name . 'Enter the room:' . $room);
        // Update online user information
        $roomUsersKey = 'online_users_' . $room;
        $onelineUsers = Cache::get($roomUsersKey);
        $user->src = $user->avatar;
        if ($onelineUsers) {
            $onelineUsers[$user->id] = $user;
            Cache::forever($roomUsersKey, $onelineUsers);
        } else {
            $onelineUsers = [
                $user->id => $user
            ];
            Cache::forever($roomUsersKey, $onelineUsers);
        }
        // Broadcast messages to all users in the room
        $websocket->to($room)->emit('room', $onelineUsers);
    } else {
        $websocket->emit('login', 'Login to enter chat room');
    }
});

First, make sure that the user is logged in (someone has suggested that user authentication can be handled by middleware, yes, I will optimize it uniformly later), and then make sure that the client passes the room number, otherwise it will not be able to communicate with the designated chat room Associated.

Next, we Redis through the HSET stored associated data structures, user ID Websocket connection for subsequent connection Websocket may obtain the corresponding user ID, so that messages sent to it unread count:

Redis::command('hset', ['socket_id', $user->id, $websocket->getSender()]);

The user is then present within the Chat Room room unread message is set to 0, by App\Services\WebSocket\Websocket the join method of this room added:

$room = Count::$ROOMLIST[$roomId];
$websocket->join($room);

The default is based on a room here Redis as a storage medium, you can config/laravels.php be adjusted to SwooleTable(currently only supports two drives):

'websocket'                => [
    'enable' => true,
    'handler' => \App\Services\WebSocket\WebSocketHandler::class,
    ...
    'drivers' => [
        'default' => 'redis',
        'table' => \App\Services\Websocket\Rooms\TableRoom::class,
        'redis' => \App\Services\Websocket\Rooms\RedisRoom::class,
        'settings' => [
            'table' => [
                ...
            ],
            'redis' => [
                'server' => [
                    'host' => env('REDIS_HOST', '127.0.0.1'),
                    'password' => env('REDIS_PASSWORD', null),
                    'port' => env('REDIS_PORT', 6379),
                    'database' => 0,
                    'persistent' => true,
                ],
                'options' => [
                    //
                ],
                'prefix' => 'swoole:',
            ],
        ],
    ],

Then, we update the online user information in the current room, we must save it to the cache, and finally broadcast the online user information to all users (including themselves) in the current room through the following code:

$websocket->to($room)->emit('room', $onelineUsers);

Thus, the client chat room pages resources/js/pages/Chat.vue which can be transmitted by the data server code to receive:

socket.on('room', function (obj) {
    that.$store.commit('setUsers', obj);
});

This is the implementation code for entering the room. Let’s look at exiting the room again.

Exit the room

Exiting the room is triggered when the client clicks the back button in the upper left corner of the chat room page:

goback () {
    const obj = {
      name: this.userid,
      roomid: this.roomid,
      api_token: this.auth_token,
    };
    socket.emit('roomout', obj);
    ...
},

Also contains user information, room information and authentication information in the service side we can respond to the client by writing the following routes in the roomout request:

WebsocketProxy::on('roomout', function (WebSocket $websocket, $data) {
    if (!empty($data['api_token']) && ($user = User::where('api_token', $data['api_token'])->first())) {
        if (empty($data['roomid'])) {
            return;
        }
        $roomId = $data['roomid'];
        $room = Count::$ROOMLIST[$roomId];
        // Update online user information
        $roomUsersKey = 'online_users_' . $room;
        $onelineUsers = Cache::get($roomUsersKey);
        if (!empty($onelineUsers[$user->id])) {
            unset($onelineUsers[$user->id]);
            Cache::forever($roomUsersKey, $onelineUsers);
        }
        $websocket->to($room)->emit('roomout', $onelineUsers);
        Log::info($user->name . 'Exit the room: ' . $room);
        $websocket->leave([$room]);
    } else {
        $websocket->emit('login', 'Login to enter chat room');
    }
});

Like entering a room, we need to ensure that the user is authenticated and the room number is not empty, then update the online user information (remove the current user), and finally leave the room with the following code and broadcast the updated user information to all online users on the client (Including yourself):

$websocket->to($room)->emit('roomout', $onelineUsers);
$websocket->leave([$room]);

Chat page on the client resources/js/pages/Chat.vue, the server may be received by the code Websocket roomout response:

socket.on('roomout', function (obj) {
    that.$store.commit('setUsers', obj);
});

Disconnect

In addition to the user clicking the back button in the chat room, when the Websocket connection is disconnected, the user on the corresponding connection must also exit all rooms and go offline. For now logically disconnect and exit the room is the same, so you can share the same set of code we write disconnect routing and reconstruction roomout routing codes are as follows:

WebsocketProxy::on('roomout', function (WebSocket $websocket, $data) {
    roomout($websocket, $data);
});

WebsocketProxy::on('disconnect', function (WebSocket $websocket, $data) {
    roomout($websocket, $data);
});

function roomout(WebSocket $websocket, $data) {
    if (!empty($data['api_token']) && ($user = User::where('api_token', $data['api_token'])->first())) {
        if (empty($data['roomid'])) {
            return;
        }
        $roomId = $data['roomid'];
        $room = Count::$ROOMLIST[$roomId];
        // Update online user information
        $roomUsersKey = 'online_users_' . $room;
        $onelineUsers = Cache::get($roomUsersKey);
        if (!empty($onelineUsers[$user->id])) {
            unset($onelineUsers[$user->id]);
            Cache::forever($roomUsersKey, $onelineUsers);
        }
        $websocket->to($room)->emit('roomout', $onelineUsers);
        Log::info($user->name . 'Exit the room: ' . $room);
        $websocket->leave([$room]);
    } else {
        $websocket->emit('login', 'Login to enter chat room');
    }
}

The client code does not need to make any adjustments. Let’s test the user entering and exiting the room.

Process test

In order to demonstrate the changes in the number of online users entering and exiting the room, we open a new browser (such as Firefox) to access the chat room application and register a new user test@xueyuanjun.com, and then enter room 1 in the Chrome browser:

This is image title

At this time, only one user chat room, the data table and then we counts initialize the new user (ID = 2) unread message recording (hereinafter this initialization process may be automatic process):

This is image title

Then login in Firefox browser and enter room 1:

This is image title

You can see that there are two users in chat room 1, and then return to the Chrome browser chat room interface, you can see that it has also become two online users without refreshing the page:

This is image title

This is because Websocket server sends a broadcast message, pushed to the room1 channel (room 1) of all clients.

Next, we exit room 1 in the Firefox browser, and then we can see that the number of online users has changed to 1 in the Chrome browser:

This is image title

If you’re a developer panel by WS viewing Websocket communication record label, then, you will see the joining and leaving the room in the Firefox browser will receive the corresponding broadcast message in the Chrome browser, and vice versa:

This is image title

The above is an introduction to the front-end and back-end interaction of Websocket communication for joining and exiting the chat room. In the next tutorial, we will officially start writing the message sending implementation code.

#laravel #swoole #vue

Building a Live Online Chat Room Based on Laravel + Swoole + Vue (P12)
11.40 GEEK