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.
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.
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);
});
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.
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:
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):
Then login in Firefox browser and enter room 1:
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 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:
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:
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