After months of procrastination, I'm finally writing my first article as a developer
So I made a chat app with the MEVN (MongoDB, Express, Vue.js, Node.js) stack and socket.io. The app functionalities are inspired by discord app.
The app features include:
- User can login with a username and password or using other social media accounts
- Users are automatically added to a welcome channel
- Users can create a channel
- Users can search and join a channel
- Users can leave a channel
- Users can edit their profile and change their display picture
Features I intend to add later
- Users can browse through and join public channels
- Users can directly message members of a channel
- A simple profile card of a user is displayed on hovering over his/her username
- User can change the theme of the app.
This post will focus on how socket.io is used on the app. Here is the Link to the source code, and the live link.
However, to get a clear understanding of this post, I'll explain few key terms.
- The channel schema
const mongoose=require('mongoose');
const Schema=mongoose.Schema;
const channelSchema=new Schema({
name:String,
description:String,
members:[
{
type:mongoose.Schema.Types.ObjectId,
ref:"User"
}
],
messages:[{
type:mongoose.Schema.Types.ObjectId,
ref:"Message"
}]
})
module.exports=mongoose.model('Channel',channelSchema);
When a user sends message to a channel, the channel is updated by pushing the new message to the channel's messages array.
- Channel: This represents the channel being currently viewed by a user
- Channels: This represents the array of channels a user belongs to.
- Updated Channel: This is a channel object updated with latest messages sent by members. i.e. new messages are already pushed to its messages array properties.
SOCKET.IO
The socket.io was used to allow for real-time bidirectional data flow between the client and the server. i.e. the client can emit event, along with some data, while the server listens to this event and handles them accordingly. This means that data can be exchanged between the client and the server without having to refresh the page.
Socket.io on the server
The socket.io is installed as shown
npm install socket.io
The socket io connection is then set up with express server as shown.
const express=require('express');
const socket = require('socket.io');
const app=express();
const server = app.listen(process.env.PORT || 3000,function(){
console.log("running");
});
const io = socket(server,{
cors: {
origin: "https://calm-meadow-71961.herokuapp.com",
methods: ["GET","PUT", "POST"],
}
});
On the server side, the socket listens to three kinds of event emitted from the client side.
- RegisterAll: This event is emitted whenever a client connects to the socket.io connection. The user's channels array is sent along with the event. This event is handled by subscribing the client to each channel's ID in the channels array i.e. the client joins an array of channel's ID room.
socket.on('registerAll',channels=>{
channels.forEach(channel => {
socket.join(channel._id);
});
});
- Register: This event is emitted when a user joins a new channel. The new channel object is sent along with the event. This event is handled by subscribing the client to the new channel's ID i.e. the client joins the new room.
socket.on('register',channel=>{
socket.join(channel._id);
})
-
messageSent: This event is emitted along with updatedChannel object when,
- Message is sent to a channel;
- User leaves a channel;
- User joins a channel;
- User creates a new channel. This event is handled by emitting the messageRecieved event along with the updatedChannel object to all clients that belong to the channel's ID room.
socket.on('messageSent',(channel)=>{
socket.to(channel._id).emit('messageReceived',channel);
})
Note: The messageSent and the Register events are both emitted from the client when a user joins a channel or creates a new channel
Socket.io on the client
Socket.io is installed on the client side
npm install socket.io-client;
It is then imported and initialized with the express server url
<script>
import io from 'socket.io-client';
data(){
return {
disconnected:false,
channels:[],
channel:{},
socket:io("https://whispering-everglades42925.herokuapp.com"),
}
}
<script/>
On the client side, the client handles three events emitted from the server side.
- connect: This is a reserved event emitted when a client connects to the socket.io connection. The event is handled by emitting the 'regsiterAll' event along with the user's channels [the array of channels the user belongs to] and also setting the disconnected variable to false.
this.socket.on("connect", () => {
if(this.channels.length>0){
this.registerChannels(this.channels);
this.disconnected=false;
}
});
- disconnect: This is a reserved event emitted when a client is disconnected from the socket.io connection. This event is handled by setting the disconnected variable to true.
this.socket.on("disconnect", (reason) => {
this.disconnected=true;
});
Hence the paragraph, "disconnected", is displayed whenever the client is disconnected from the socket connection
<p class="disconnected" v-if="disconnected">disconnected</p>
- messageRecieved: This event is handled by replacing a channel in the array of channels with the updated channel sent with the event.
this.socket.on('messageReceived',(channel)=>{
this.updateChannel(channel);
});`
The updateChannel method is defined as shown below.
funtion updateChannel(updatedChannel){
if(updatedChannel._id===this.channel._id){
this.channel=updatedChannel;
}
this.channels = this.channels.map(channel => (channel._id === updatedChannel._id) ? updatedChannel : channel)
}
The function takes the updatedChannel argument passed with the messageReceived event, sets the currently viewed channel
to the updated channel if it is the same as the updatedChannel, then replace the outdated channel in the user's channels with the updatedChannel
There goes my first post, Thanks for reading.
Top comments (0)